Compare commits

...

18 Commits

Author SHA1 Message Date
Hannes Domani
80f0e38f11 PDB: Increase maximum number of "aclass" registrations 2022-04-20 22:03:36 +02:00
Hannes Domani
30605047d3 PDB: DLLs 2022-04-18 18:58:11 +02:00
Hannes Domani
54ba83a63d PDB: optimized-out variables 2022-04-18 16:28:00 +02:00
Hannes Domani
5f758d8cea PDB: thread-local variables 2022-04-18 16:27:59 +02:00
Hannes Domani
701a2f8749 PDB: add wchar/bool base types 2022-04-18 16:27:58 +02:00
Hannes Domani
9aa93eac41 PDB: refactor variable symbols 2022-04-18 16:27:57 +02:00
Hannes Domani
48852b4dc8 PDB: bitfields 2022-04-18 16:27:56 +02:00
Hannes Domani
f6201a399a PDB: on i386 local variables are relative to $ebp 2022-04-16 20:52:56 +02:00
Hannes Domani
966dffcb4f PDB: skip jump thunks for i386 also 2022-04-16 18:21:19 +02:00
Hannes Domani
232738a7b1 PDB: inner function scopes 2022-04-16 18:21:13 +02:00
Hannes Domani
b594ecd867 PDB: enums 2022-04-16 18:21:03 +02:00
Hannes Domani
df03b57cee PDB: typedefs 2022-04-16 18:20:55 +02:00
Hannes Domani
7ceacbf8ad PDB: skip jump thunks 2022-04-15 20:38:46 +02:00
Hannes Domani
020fd79ff7 Fix overflow when reading the exception directory 2022-04-15 20:38:35 +02:00
Hannes Domani
3abda17b82 PDB: local variables relative to $rsp 2022-04-13 20:27:45 +02:00
Hannes Domani
8b27d76d9e PDB: array 2022-04-11 19:38:10 +02:00
Hannes Domani
e4405d097d PDB: cache types 2022-04-11 19:37:59 +02:00
Hannes Domani
bf22f1d710 pdb, part one 2022-04-10 20:45:41 +02:00
5 changed files with 932 additions and 5 deletions

View File

@@ -1033,7 +1033,7 @@ amd64_windows_find_unwind_info (struct gdbarch *gdbarch, CORE_ADDR pc,
lo = 0;
hi = dir->Size / sizeof (struct external_pex64_runtime_function);
*unwind_info = 0;
while (lo <= hi)
while (lo < hi)
{
unsigned long mid = lo + (hi - lo) / 2;
struct external_pex64_runtime_function d;
@@ -1046,7 +1046,7 @@ amd64_windows_find_unwind_info (struct gdbarch *gdbarch, CORE_ADDR pc,
sa = extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order);
ea = extract_unsigned_integer (d.rva_EndAddress, 4, byte_order);
if (pc < base + sa)
hi = mid - 1;
hi = mid;
else if (pc >= base + ea)
lo = mid + 1;
else if (pc >= base + sa && pc < base + ea)
@@ -1237,7 +1237,8 @@ amd64_windows_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
/* Check for jmp *<offset>(%rip) (jump near, absolute indirect (/4)). */
if (pc && read_memory_unsigned_integer (pc, 2, byte_order) == 0x25ff)
unsigned instr = pc ? read_memory_unsigned_integer (pc, 2, byte_order) : 0;
if (instr == 0x25ff)
{
/* Get opcode offset and see if we can find a reference in our data. */
ULONGEST offset
@@ -1260,6 +1261,18 @@ amd64_windows_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
= read_memory_unsigned_integer (indirect_addr, 8, byte_order);
}
}
else if ((instr & 0xff) == 0xe9)
{
struct minimal_symbol *sym = lookup_minimal_symbol_by_pc (pc).minsym;
const char *symname = sym ? sym->linkage_name () : NULL;
if (symname && startswith (symname, "__thunk_"))
{
ULONGEST offset
= read_memory_unsigned_integer (pc + 1, 4, byte_order);
destination = pc + offset + 5;
}
}
return destination;
}

View File

@@ -325,6 +325,12 @@ pe_as32 (void *ptr)
return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
}
#ifdef _WIN32
bool pdb_load_functions (const char *name, minimal_symbol_reader *reader,
struct objfile *objfile);
#endif
/* Read the (non-debug) export symbol table from a portable
executable. Code originally lifted from the ld function
@@ -384,6 +390,11 @@ read_pe_exported_syms (minimal_symbol_reader &reader,
return;
}
#ifdef _WIN32
if (pdb_load_functions (dll_name, &reader, objfile))
return;
#endif
/* Get pe_header, optional header and numbers of export entries. */
pe_header_offset = pe_get32 (dll, 0x3c);
opthdr_ofs = pe_header_offset + 4 + 20;

View File

@@ -92,7 +92,27 @@ static int i386_windows_gregset_reg_offset[] =
static CORE_ADDR
i386_windows_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
{
return i386_pe_skip_trampoline_code (frame, pc, NULL);
CORE_ADDR addr = i386_pe_skip_trampoline_code (frame, pc, NULL);
if (addr == 0 && pc != 0)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
if (read_memory_unsigned_integer (pc, 1, byte_order) == 0xe9)
{
struct minimal_symbol *sym = lookup_minimal_symbol_by_pc (pc).minsym;
const char *symname = sym ? sym->linkage_name () : NULL;
if (symname && (startswith (symname, "__thunk_")
|| startswith (symname, "_thunk_")))
{
ULONGEST offset
= read_memory_unsigned_integer (pc + 1, 4, byte_order);
return pc + offset + 5;
}
}
}
return addr;
}
static const char *

View File

@@ -6480,7 +6480,7 @@ static int next_aclass_value = LOC_FINAL_VALUE;
/* The maximum number of "aclass" registrations we support. This is
constant for convenience. */
#define MAX_SYMBOL_IMPLS (LOC_FINAL_VALUE + 10)
#define MAX_SYMBOL_IMPLS (LOC_FINAL_VALUE + 16)
/* The objects representing the various "aclass" values. The elements
from 0 up to LOC_FINAL_VALUE-1 represent themselves, and subsequent

View File

@@ -60,6 +60,9 @@
#include "i386-tdep.h"
#include "i387-tdep.h"
#ifdef __x86_64__
#include "amd64-tdep.h"
#endif
#include "windows-tdep.h"
#include "windows-nat.h"
@@ -71,6 +74,8 @@
#include "gdbsupport/gdb_wait.h"
#include "nat/windows-nat.h"
#include "gdbsupport/symbol.h"
#include "buildsym.h"
#include "block.h"
using namespace windows_nat;
@@ -3042,6 +3047,104 @@ windows_nat_target::thread_name (struct thread_info *thr)
}
struct pdb_regrel_baton
{
int regnum;
ULONG64 offset;
};
static value *
pdb_read_variable (struct symbol *symbol, struct frame_info *frame)
{
pdb_regrel_baton *baton
= (pdb_regrel_baton *) SYMBOL_LOCATION_BATON (symbol);
ULONGEST regvalue = get_frame_register_unsigned (frame, baton->regnum);
return value_at_lazy (symbol->type (), regvalue + baton->offset);
}
struct pdb_tls_baton
{
ULONG64 offset;
int tib_ofs;
int ptr_size;
symbol *tls_index_sym;
};
static value *
pdb_tls_read_variable (struct symbol *symbol, struct frame_info *frame)
{
pdb_tls_baton *baton = (pdb_tls_baton *) SYMBOL_LOCATION_BATON (symbol);
CORE_ADDR tib;
if (baton->tls_index_sym != nullptr
&& the_windows_nat_target.get_tib_address (inferior_ptid, &tib))
{
struct gdbarch *gdbarch = get_frame_arch (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
ULONGEST thread_local_storage
= read_memory_unsigned_integer (tib + baton->tib_ofs,
baton->ptr_size, byte_order);
DWORD tls_index = read_memory_unsigned_integer
(SYMBOL_VALUE_ADDRESS (baton->tls_index_sym), 4, byte_order);
ULONGEST tls = read_memory_unsigned_integer
(thread_local_storage + tls_index * baton->ptr_size,
baton->ptr_size, byte_order);
return value_at_lazy (symbol->type (), tls + baton->offset);
}
return allocate_optimized_out_value (symbol->type ());
}
static enum symbol_needs_kind
pdb_get_symbol_read_needs (struct symbol *symbol)
{
return SYMBOL_NEEDS_FRAME;
}
static void
pdb_describe_location (struct symbol *symbol, CORE_ADDR addr,
struct ui_file *stream)
{
}
static void
pdb_tracepoint_var_ref (struct symbol *symbol, struct agent_expr *ax,
struct axs_value *value)
{
}
static void
pdb_generate_c_location (struct symbol *symbol, string_file *stream,
struct gdbarch *gdbarch,
std::vector<bool> &registers_used,
CORE_ADDR pc, const char *result_name)
{
}
const struct symbol_computed_ops pdb_regrel_funcs = {
pdb_read_variable,
NULL,
pdb_get_symbol_read_needs,
pdb_describe_location,
0, /* location_has_loclist */
pdb_tracepoint_var_ref,
pdb_generate_c_location
};
static int pdb_regrel_index;
const struct symbol_computed_ops pdb_tls_funcs = {
pdb_tls_read_variable,
NULL,
pdb_get_symbol_read_needs,
pdb_describe_location,
0, /* location_has_loclist */
pdb_tracepoint_var_ref,
pdb_generate_c_location
};
static int pdb_tls_index;
void _initialize_windows_nat ();
void
_initialize_windows_nat ()
@@ -3143,6 +3246,10 @@ Show whether to display kernel exceptions in child process."), NULL,
cannot automatically find executable file or library to read symbols.\n\
Use \"file\" or \"dll\" command to load executable/libraries directly."));
}
pdb_regrel_index = register_symbol_computed_impl (LOC_COMPUTED,
&pdb_regrel_funcs);
pdb_tls_index = register_symbol_computed_impl (LOC_COMPUTED, &pdb_tls_funcs);
}
/* Hardware watchpoint support, adapted from go32-nat.c code. */
@@ -3215,6 +3322,782 @@ windows_nat_target::thread_alive (ptid_t ptid)
return WaitForSingleObject (th->h, 0) != WAIT_OBJECT_0;
}
typedef BOOL WINAPI (SymInitialize_ftype) (HANDLE, PCSTR, BOOL);
typedef BOOL WINAPI (SymCleanup_ftype) (HANDLE);
typedef DWORD64 WINAPI (SymLoadModule64_ftype) (HANDLE, HANDLE, PCSTR,
PCSTR, DWORD64, DWORD);
typedef BOOL WINAPI (SymGetModuleInfo64_ftype)
(HANDLE, DWORD64, PIMAGEHLP_MODULE64);
typedef BOOL WINAPI (SymFromName_ftype) (HANDLE, PCSTR, PSYMBOL_INFO);
typedef BOOL WINAPI (SymEnumTypes_ftype)
(HANDLE, ULONG64, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);
typedef BOOL WINAPI (SymEnumSymbols_ftype)
(HANDLE, ULONG64, PCSTR, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);
typedef BOOL WINAPI (SymEnumSourceLines_ftype)
(HANDLE, ULONG64, PCSTR, PCSTR, DWORD, DWORD, PSYM_ENUMLINES_CALLBACK,
PVOID);
typedef BOOL WINAPI (SymGetTypeInfo_ftype)
(HANDLE, DWORD64, ULONG, IMAGEHLP_SYMBOL_TYPE_INFO, PVOID);
typedef BOOL WINAPI (SymSetContext_ftype)
(HANDLE, PIMAGEHLP_STACK_FRAME, PIMAGEHLP_CONTEXT);
typedef BOOL WINAPI (SymSearch_ftype)
(HANDLE, ULONG64, DWORD, DWORD, PCSTR, DWORD64,
PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID, DWORD);
enum SymTagEnum
{
SymTagNull,
SymTagExe,
SymTagCompiland,
SymTagCompilandDetails,
SymTagCompilandEnv,
SymTagFunction,
SymTagBlock,
SymTagData,
SymTagAnnotation,
SymTagLabel,
SymTagPublicSymbol,
SymTagUDT,
SymTagEnum,
SymTagFunctionType,
SymTagPointerType,
SymTagArrayType,
SymTagBaseType,
SymTagTypedef,
SymTagBaseClass,
SymTagFriend,
SymTagFunctionArgType,
SymTagFuncDebugStart,
SymTagFuncDebugEnd,
SymTagUsingNamespace,
SymTagVTableShape,
SymTagVTable,
SymTagCustom,
SymTagThunk,
SymTagCustomType,
SymTagManagedType,
SymTagDimension,
SymTagCallSite,
SymTagMax
};
enum UdtKind
{
UdtStruct,
UdtClass,
UdtUnion,
UdtInterface
};
enum DataKind
{
DataIsUnknown,
DataIsLocal,
DataIsStaticLocal,
DataIsParam,
DataIsObjectPtr,
DataIsFileStatic,
DataIsGlobal,
DataIsMember,
DataIsStaticMember,
DataIsConstant
};
struct pdb_line_info
{
minimal_symbol_reader *reader;
buildsym_compunit *builder;
pending **local_symbols;
objfile *objfile;
HANDLE p;
SymGetTypeInfo_ftype *fSymGetTypeInfo;
SymEnumSymbols_ftype *fSymEnumSymbols;
SymSetContext_ftype *fSymSetContext;
SymSearch_ftype *fSymSearch;
DWORD64 addr;
ULONGEST base_ofs;
DWORD64 max_addr;
symbol *tls_index_sym;
std::vector<type *> cache;
std::vector<symbol *> functions;
};
static const char *wchar_to_objfile (pdb_line_info *pli, WCHAR *nameW)
{
int len = WideCharToMultiByte (CP_ACP, 0, nameW, -1,
NULL, 0, NULL, NULL);
gdb::unique_xmalloc_ptr<char> name;
if (len > 1)
{
name.reset ((char *) xmalloc (len));
WideCharToMultiByte (CP_ACP, 0, nameW, -1,
name.get (), len, NULL, NULL);
}
LocalFree (nameW);
return pli->objfile->intern (name.get ());
}
static LONGEST get_pdb_int_constant (pdb_line_info *pli, DWORD type_index)
{
VARIANT v;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_VALUE, &v))
{
switch (v.vt)
{
case VT_I1: return v.cVal;
case VT_I2: return v.iVal;
case VT_I4: return v.lVal;
case VT_I8: return v.llVal;
case VT_UI1: return v.bVal;
case VT_UI2: return v.uiVal;
case VT_UI4: return v.ulVal;
case VT_UI8: return v.ullVal;
}
}
return 0;
}
static type *get_pdb_type (pdb_line_info *pli, DWORD type_index);
static type *get_pdb_type_cached (pdb_line_info *pli, DWORD type_index)
{
const struct objfile_type *ot = objfile_type (pli->objfile);
DWORD tag;
if (!pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_SYMTAG, &tag))
return ot->builtin_void;
switch (tag)
{
case SymTagFunctionType:
{
DWORD tid;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_TYPEID, &tid))
{
type *ftype = lookup_function_type (get_pdb_type (pli, tid));
DWORD children;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_CHILDRENCOUNT, &children)
&& children > 0)
{
gdb::unique_xmalloc_ptr<TI_FINDCHILDREN_PARAMS> args
((TI_FINDCHILDREN_PARAMS *)
xmalloc (sizeof (TI_FINDCHILDREN_PARAMS)
+ children * sizeof (ULONG)));
args->Count = children;
args->Start = 0;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_FINDCHILDREN, args.get ()))
{
std::vector<DWORD> arg_types;
for (DWORD i = 0; i < children; i++)
{
if (pli->fSymGetTypeInfo (pli->p, pli->addr,
args->ChildId[i],
TI_GET_SYMTAG, &tag)
&& tag == SymTagFunctionArgType
&& pli->fSymGetTypeInfo (pli->p, pli->addr,
args->ChildId[i],
TI_GET_TYPEID, &tid))
arg_types.push_back (tid);
}
if (!arg_types.empty ())
{
int nparams = arg_types.size ();
ftype->set_num_fields (nparams);
ftype->set_fields
((struct field *) TYPE_ZALLOC
(ftype, nparams * sizeof (struct field)));
for (int i = 0; i < nparams; i++)
ftype->field (i).set_type
(get_pdb_type (pli, arg_types[i]));
}
}
}
return ftype;
}
break;
}
case SymTagBaseType:
{
DWORD basetype;
ULONG64 length;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_BASETYPE, &basetype)
&& pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_LENGTH, &length))
{
switch (basetype)
{
case 1: // void
return ot->builtin_void;
case 2: // signed char
return ot->builtin_signed_char;
case 3: // wchar
return builtin_type (pli->objfile->arch ())->builtin_wchar;
case 6: // signed short/int/long_long
if (length == 2)
return ot->builtin_short;
else if (length == 4)
return ot->builtin_int;
else if (length == 8)
return ot->builtin_long_long;
break;
case 7: // unsigned char/short/int/long_long
if (length == 1)
return ot->builtin_unsigned_char;
else if (length == 2)
return ot->builtin_unsigned_short;
else if (length == 4)
return ot->builtin_unsigned_int;
else if (length == 8)
return ot->builtin_unsigned_long_long;
break;
case 8: // float/double
if (length == 4)
return ot->builtin_float;
else if (length == 8)
return ot->builtin_double;
break;
case 10: // bool
return builtin_type (pli->objfile->arch ())->builtin_bool;
case 13: // signed long
return ot->builtin_long;
case 14: // unsigned long
return ot->builtin_unsigned_long;
}
}
break;
}
case SymTagPointerType:
{
DWORD tid;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_TYPEID, &tid))
return lookup_pointer_type (get_pdb_type (pli, tid));
break;
}
case SymTagUDT:
{
DWORD udtkind;
ULONG64 length;
WCHAR *nameW = NULL;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_UDTKIND, &udtkind)
&& pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_LENGTH, &length)
&& pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_SYMNAME, &nameW))
{
type *t = alloc_type (pli->objfile);
INIT_CPLUS_SPECIFIC (t);
pli->cache[type_index] = t;
t->set_name (wchar_to_objfile (pli, nameW));
if (udtkind == UdtUnion)
t->set_code (TYPE_CODE_UNION);
else
t->set_code (TYPE_CODE_STRUCT);
TYPE_LENGTH (t) = length;
DWORD children;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_CHILDRENCOUNT, &children)
&& children > 0)
{
gdb::unique_xmalloc_ptr<TI_FINDCHILDREN_PARAMS> members
((TI_FINDCHILDREN_PARAMS *)
xmalloc (sizeof (TI_FINDCHILDREN_PARAMS)
+ children * sizeof (ULONG)));
members->Count = children;
members->Start = 0;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_FINDCHILDREN, members.get ()))
{
t->set_num_fields (children);
t->set_fields ((struct field *) TYPE_ZALLOC
(t, children * sizeof (struct field)));
DWORD i;
for (i = 0; i < children; i++)
{
DWORD tid, dk, ofs;
if (pli->fSymGetTypeInfo (pli->p, pli->addr,
members->ChildId[i],
TI_GET_SYMTAG, &tag)
&& tag == SymTagData
&& pli->fSymGetTypeInfo (pli->p, pli->addr,
members->ChildId[i],
TI_GET_TYPEID, &tid)
&& pli->fSymGetTypeInfo (pli->p, pli->addr,
members->ChildId[i],
TI_GET_DATAKIND, &dk)
&& dk == DataIsMember
&& pli->fSymGetTypeInfo (pli->p, pli->addr,
members->ChildId[i],
TI_GET_OFFSET, &ofs)
&& pli->fSymGetTypeInfo (pli->p, pli->addr,
members->ChildId[i],
TI_GET_SYMNAME, &nameW))
{
t->field (i).set_type (get_pdb_type (pli, tid));
t->field (i).set_name (wchar_to_objfile
(pli, nameW));
DWORD bitofs = 0;
DWORD bitpos;
if (pli->fSymGetTypeInfo
(pli->p, pli->addr, members->ChildId[i],
TI_GET_BITPOSITION, &bitpos)
&& pli->fSymGetTypeInfo
(pli->p, pli->addr, members->ChildId[i],
TI_GET_LENGTH, &length))
{
bitofs = bitpos;
FIELD_BITSIZE (t->field (i)) = length;
}
t->field (i).set_loc_bitpos (ofs * 8 + bitofs);
}
}
}
}
return t;
}
break;
}
case SymTagArrayType:
{
DWORD tid, index_tid;
DWORD count;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_TYPEID, &tid)
&& pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_ARRAYINDEXTYPEID, &index_tid)
&& pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_COUNT, &count))
{
type *element_type = get_pdb_type (pli, tid);
type *index_type = get_pdb_type (pli, index_tid);
type *range_type
= create_static_range_type (NULL, index_type, 0, count - 1);
return create_array_type (NULL, element_type, range_type);
}
break;
}
case SymTagTypedef:
{
DWORD tid;
WCHAR *nameW = NULL;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_TYPEID, &tid)
&& pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_SYMNAME, &nameW))
{
type *t = init_type (pli->objfile, TYPE_CODE_TYPEDEF, 0,
wchar_to_objfile (pli, nameW));
TYPE_TARGET_TYPE (t) = get_pdb_type (pli, tid);
return t;
}
break;
}
case SymTagEnum:
{
DWORD tid;
DWORD children;
WCHAR *nameW = NULL;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_TYPEID, &tid)
&& pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_CHILDRENCOUNT, &children)
&& children > 0
&& pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_GET_SYMNAME, &nameW))
{
type *t = alloc_type (pli->objfile);
t->set_code (TYPE_CODE_ENUM);
t->set_name (wchar_to_objfile (pli, nameW));
TYPE_TARGET_TYPE (t) = get_pdb_type (pli, tid);
t->set_is_unsigned (TYPE_TARGET_TYPE (t)->is_unsigned ());
TYPE_LENGTH (t) = TYPE_LENGTH (TYPE_TARGET_TYPE (t));
gdb::unique_xmalloc_ptr<TI_FINDCHILDREN_PARAMS> values
((TI_FINDCHILDREN_PARAMS *)
xmalloc (sizeof (TI_FINDCHILDREN_PARAMS)
+ children * sizeof (ULONG)));
values->Count = children;
values->Start = 0;
if (pli->fSymGetTypeInfo (pli->p, pli->addr, type_index,
TI_FINDCHILDREN, values.get ()))
{
t->set_num_fields (children);
t->set_fields ((struct field *) TYPE_ZALLOC
(t, children * sizeof (struct field)));
DWORD i;
for (i = 0; i < children; i++)
{
DWORD dk;
if (pli->fSymGetTypeInfo (pli->p, pli->addr,
values->ChildId[i],
TI_GET_SYMTAG, &tag)
&& tag == SymTagData
&& pli->fSymGetTypeInfo (pli->p, pli->addr,
values->ChildId[i],
TI_GET_DATAKIND, &dk)
&& dk == DataIsConstant
&& pli->fSymGetTypeInfo (pli->p, pli->addr,
values->ChildId[i],
TI_GET_SYMNAME, &nameW))
{
t->field (i).set_name (wchar_to_objfile
(pli, nameW));
t->field (i).set_loc_enumval
(get_pdb_int_constant (pli, values->ChildId[i]));
}
}
}
return t;
}
break;
}
}
return ot->builtin_void;
}
static type *get_pdb_type (pdb_line_info *pli, DWORD type_index)
{
if (type_index >= pli->cache.size ())
pli->cache.resize (type_index + 1, nullptr);
else if (pli->cache[type_index] != nullptr)
return pli->cache[type_index];
type *t = get_pdb_type_cached (pli, type_index);
pli->cache[type_index] = t;
return t;
}
static BOOL CALLBACK symbol_callback(PSYMBOL_INFO si,
ULONG /*SymbolSize*/, PVOID UserContext);
static void pdb_enum_locals(pdb_line_info *pli, PSYMBOL_INFO si)
{
pending **local_symbols = pli->local_symbols;
pli->local_symbols = pli->builder->get_local_symbols ();
IMAGEHLP_STACK_FRAME isf;
memset (&isf, 0, sizeof (isf));
isf.InstructionOffset = si->Address;
pli->fSymSetContext (pli->p, &isf, NULL);
pli->fSymEnumSymbols (pli->p, 0, NULL, symbol_callback, pli);
pli->local_symbols = local_symbols;
}
static BOOL CALLBACK block_callback(PSYMBOL_INFO si,
ULONG /*SymbolSize*/, PVOID UserContext)
{
pdb_line_info *pli = (pdb_line_info *) UserContext;
ULONG64 length;
if (si->Tag == SymTagBlock
&& pli->fSymGetTypeInfo (pli->p, pli->addr, si->info,
TI_GET_LENGTH, &length))
{
ULONGEST addr = si->Address + pli->base_ofs;
pli->builder->push_context (0, addr);
pdb_enum_locals (pli, si);
pli->fSymSearch (pli->p, 0, 0, SymTagBlock, NULL, 0,
block_callback, pli, 0);
struct context_stack cstk = pli->builder->pop_context ();
if (*pli->builder->get_local_symbols () != NULL)
pli->builder->finish_block (0, cstk.old_blocks, NULL,
addr, addr + length);
*pli->builder->get_local_symbols () = cstk.locals;
pli->builder->set_local_using_directives (cstk.local_using_directives);
}
return TRUE;
}
static symbol *
pdb_read_data_symbol (PSYMBOL_INFO si, pdb_line_info *pli, const char *name)
{
objfile *objfile = pli->objfile;
if (si->info >= pli->cache.size ())
pli->cache.resize (si->info + 1, nullptr);
else if (pli->cache[si->info] != nullptr)
return nullptr;
symbol *sym = new (&objfile->objfile_obstack) symbol;
sym->set_linkage_name (objfile->intern (name));
sym->set_language (language_c, &objfile->objfile_obstack);
sym->set_domain (VAR_DOMAIN);
type *t = get_pdb_type (pli, si->TypeIndex);
sym->set_type (t);
if (si->Flags & SYMFLAG_REGREL)
{
pdb_regrel_baton *baton
= XOBNEW (&objfile->objfile_obstack, pdb_regrel_baton);
#ifdef __x86_64__
if (gdbarch_ptr_bit (objfile->arch ()) == 64)
baton->regnum = AMD64_RSP_REGNUM;
else
#endif
baton->regnum = I386_EBP_REGNUM;
baton->offset = si->Address;
SYMBOL_LOCATION_BATON (sym) = baton;
sym->set_aclass_index (pdb_regrel_index);
if (si->Flags & SYMFLAG_PARAMETER)
sym->set_is_argument (true);
}
else if (si->Flags & SYMFLAG_TLSREL)
{
pdb_tls_baton *baton
= XOBNEW (&objfile->objfile_obstack, pdb_tls_baton);
baton->offset = si->Address;
#ifdef __x86_64__
if (gdbarch_ptr_bit (objfile->arch ()) == 64)
{
baton->tib_ofs = 88;
baton->ptr_size = 8;
}
else
#endif
{
baton->tib_ofs = 44;
baton->ptr_size = 4;
}
baton->tls_index_sym = pli->tls_index_sym;
SYMBOL_LOCATION_BATON (sym) = baton;
sym->set_aclass_index (pdb_tls_index);
}
else if (si->Flags & 0x80000) // SYMFLAG_NULL
{
sym->set_aclass_index (LOC_OPTIMIZED_OUT);
}
else
{
SET_SYMBOL_VALUE_ADDRESS (sym, si->Address + pli->base_ofs);
sym->set_aclass_index (LOC_STATIC);
}
if (pli->local_symbols != nullptr)
add_symbol_to_list (sym, pli->local_symbols);
else
add_symbol_to_list (sym, pli->builder->get_global_symbols ());
pli->cache[si->info] = t;
return sym;
}
static BOOL CALLBACK symbol_callback(PSYMBOL_INFO si,
ULONG /*SymbolSize*/, PVOID UserContext)
{
pdb_line_info *pli = (pdb_line_info *) UserContext;
objfile *objfile = pli->objfile;
ULONGEST base_ofs = pli->base_ofs;
if (si->Tag == SymTagFunction)
{
ULONGEST addr = si->Address + base_ofs;
context_stack *newobj = pli->builder->push_context (0, addr);
symbol *sym = new (&objfile->objfile_obstack) symbol;
sym->set_linkage_name (objfile->intern (si->Name));
sym->set_language (language_c, &objfile->objfile_obstack);
sym->set_domain (VAR_DOMAIN);
sym->set_type (get_pdb_type (pli, si->TypeIndex));
sym->set_aclass_index (LOC_BLOCK);
SET_SYMBOL_VALUE_ADDRESS (sym, addr);
add_symbol_to_list (sym, pli->builder->get_global_symbols ());
newobj->name = sym;
// locals
pdb_enum_locals (pli, si);
// inner scopes
pli->fSymSearch (pli->p, 0, 0, SymTagBlock, NULL, 0,
block_callback, pli, 0);
struct context_stack cstk = pli->builder->pop_context ();
pli->builder->finish_block (cstk.name, cstk.old_blocks, cstk.static_link,
addr, addr + si->Size);
gdbarch_make_symbol_special (objfile->arch (), cstk.name, objfile);
pli->functions.push_back (sym);
}
else if (si->Tag == SymTagData)
{
pdb_read_data_symbol (si, pli, si->Name);
}
else if (si->Tag == SymTagThunk)
{
for (symbol *sym : pli->functions)
{
if (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) == si->Value + base_ofs)
{
std::string imp_name
= string_printf ("__thunk_%s", sym->linkage_name ());
struct minimal_symbol *msym = pli->reader->record_full
(imp_name.c_str (), true, si->Address, mst_data, 0);
if (msym)
SET_MSYMBOL_SIZE (msym, si->Size);
}
}
}
else if (si->Tag == SymTagUDT || si->Tag == SymTagTypedef
|| si->Tag == SymTagEnum)
{
symbol *sym = new (&objfile->objfile_obstack) symbol;
sym->set_linkage_name (objfile->intern (si->Name));
sym->set_language (language_c, &objfile->objfile_obstack);
sym->set_aclass_index (LOC_TYPEDEF);
sym->set_domain (si->Tag == SymTagTypedef ? VAR_DOMAIN : STRUCT_DOMAIN);
sym->set_type (get_pdb_type (pli, si->TypeIndex));
add_symbol_to_list (sym, pli->builder->get_global_symbols ());
}
return TRUE;
}
static BOOL CALLBACK line_callback(PSRCCODEINFO li, PVOID UserContext)
{
pdb_line_info *pli = (pdb_line_info *) UserContext;
ULONGEST addr = li->Address + pli->base_ofs;
if (addr > pli->max_addr)
pli->max_addr = addr;
buildsym_compunit *builder = pli->builder;
subfile *sf = builder->get_current_subfile ();
if (sf == nullptr || strcmp (sf->name, li->FileName) != 0)
{
builder->start_subfile (li->FileName);
sf = builder->get_current_subfile ();
}
builder->record_line (sf, li->LineNumber, 0, addr, true);
return TRUE;
}
bool pdb_load_functions (const char *name, minimal_symbol_reader *reader,
struct objfile *objfile);
bool
pdb_load_functions (const char *name, minimal_symbol_reader *reader,
struct objfile *objfile)
{
if (GetModuleHandle("ucrtbase.dll") == NULL)
LoadLibrary("ucrtbase.dll");
HMODULE dh = LoadLibrary("dbghelp.dll");
if (dh == NULL)
return false;
SymInitialize_ftype *fSymInitialize = (SymInitialize_ftype *)
GetProcAddress (dh, "SymInitialize");
SymCleanup_ftype *fSymCleanup = (SymCleanup_ftype *)
GetProcAddress (dh, "SymCleanup");
SymFromName_ftype *fSymFromName = (SymFromName_ftype *)
GetProcAddress (dh, "SymFromName");
SymEnumTypes_ftype *fSymEnumTypes = (SymEnumTypes_ftype *)
GetProcAddress (dh, "SymEnumTypes");
SymEnumSymbols_ftype *fSymEnumSymbols = (SymEnumSymbols_ftype *)
GetProcAddress (dh, "SymEnumSymbols");
SymLoadModule64_ftype *fSymLoadModule64 = (SymLoadModule64_ftype *)
GetProcAddress (dh, "SymLoadModule64");
SymGetModuleInfo64_ftype *fSymGetModuleInfo64 = (SymGetModuleInfo64_ftype *)
GetProcAddress (dh, "SymGetModuleInfo64");
SymEnumSourceLines_ftype *fSymEnumSourceLines = (SymEnumSourceLines_ftype *)
GetProcAddress (dh, "SymEnumSourceLines");
SymGetTypeInfo_ftype *fSymGetTypeInfo = (SymGetTypeInfo_ftype *)
GetProcAddress (dh, "SymGetTypeInfo");
SymSetContext_ftype *fSymSetContext = (SymSetContext_ftype *)
GetProcAddress (dh, "SymSetContext");
SymSearch_ftype *fSymSearch = (SymSearch_ftype *)
GetProcAddress (dh, "SymSearch");
if (fSymInitialize != NULL && fSymCleanup != NULL
&& fSymLoadModule64 != NULL && fSymGetModuleInfo64 != NULL
&& fSymFromName != NULL
&& fSymEnumTypes != NULL && fSymEnumSymbols != NULL
&& fSymEnumSourceLines != NULL && fSymGetTypeInfo != NULL
&& fSymSetContext != NULL && fSymSearch != NULL)
{
HANDLE p = (void *) 1;
fSymInitialize (p, NULL, FALSE);
DWORD64 addr = fSymLoadModule64(p, NULL, name, NULL, 0, 0);
IMAGEHLP_MODULE64 mi;
memset (&mi, 0, sizeof(mi));
mi.SizeOfStruct = sizeof(mi);
if (!fSymGetModuleInfo64 (p, addr, &mi) || mi.SymType != SymPdb)
{
fSymCleanup(p);
FreeLibrary(dh);
return false;
}
std::unique_ptr<buildsym_compunit> builder;
builder.reset (new buildsym_compunit
(objfile, name, NULL, language_c, addr));
pdb_line_info pli;
pli.reader = reader;
pli.builder = builder.get ();
pli.local_symbols = nullptr;
pli.objfile = objfile;
pli.p = p;
pli.fSymGetTypeInfo = fSymGetTypeInfo;
pli.fSymEnumSymbols = fSymEnumSymbols;
pli.fSymSetContext = fSymSetContext;
pli.fSymSearch = fSymSearch;
pli.addr = addr;
pli.base_ofs = objfile->text_section_offset ();
pli.max_addr = 0;
pli.tls_index_sym = nullptr;
SYMBOL_INFO si;
memset (&si, 0, sizeof (si));
si.SizeOfStruct = sizeof (si);
if (fSymFromName (p, "_tls_index", &si))
pli.tls_index_sym = pdb_read_data_symbol (&si, &pli, "_tls_index");
fSymEnumTypes(p, addr, symbol_callback, &pli);
fSymEnumSymbols(p, addr, NULL, symbol_callback, &pli);
fSymSearch (p, addr, 0, SymTagThunk, NULL, 0, symbol_callback, &pli,
SYMSEARCH_RECURSE);
fSymEnumSourceLines(p, addr, NULL, NULL, 0, 0, line_callback, &pli);
builder->end_symtab (pli.max_addr, SECT_OFF_TEXT (objfile));
fSymCleanup(p);
}
FreeLibrary(dh);
return true;
}
void _initialize_check_for_gdb_ini ();
void
_initialize_check_for_gdb_ini ()