Newer
Older
/*
* File types.c - management of types (hierarchical tree)
*
* Copyright (C) 1997, Eric Youngdale.
* 2004, Eric Pouech.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* Note: This really doesn't do much at the moment, but it forms the framework
* upon which full support for datatype handling will eventually be built.
*/
Robert Shearman
committed
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "wine/debug.h"
#include "dbghelp_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symt);
static const char* symt_get_tag_str(DWORD tag)
{
switch (tag)
{
case SymTagNull: return "SymTagNull";
case SymTagExe: return "SymTagExe";
case SymTagCompiland: return "SymTagCompiland";
case SymTagCompilandDetails: return "SymTagCompilandDetails";
case SymTagCompilandEnv: return "SymTagCompilandEnv";
case SymTagFunction: return "SymTagFunction";
case SymTagBlock: return "SymTagBlock";
case SymTagData: return "SymTagData";
case SymTagAnnotation: return "SymTagAnnotation";
case SymTagLabel: return "SymTagLabel";
case SymTagPublicSymbol: return "SymTagPublicSymbol";
case SymTagUDT: return "SymTagUDT";
case SymTagEnum: return "SymTagEnum";
case SymTagFunctionType: return "SymTagFunctionType";
case SymTagPointerType: return "SymTagPointerType";
case SymTagArrayType: return "SymTagArrayType";
case SymTagBaseType: return "SymTagBaseType";
case SymTagTypedef: return "SymTagTypedef,";
case SymTagBaseClass: return "SymTagBaseClass";
case SymTagFriend: return "SymTagFriend";
case SymTagFunctionArgType: return "SymTagFunctionArgType,";
case SymTagFuncDebugStart: return "SymTagFuncDebugStart";
case SymTagFuncDebugEnd: return "SymTagFuncDebugEnd";
case SymTagUsingNamespace: return "SymTagUsingNamespace";
case SymTagVTableShape: return "SymTagVTableShape";
case SymTagVTable: return "SymTagVTable";
case SymTagCustom: return "SymTagCustom";
case SymTagThunk: return "SymTagThunk";
case SymTagCustomType: return "SymTagCustomType";
case SymTagManagedType: return "SymTagManagedType";
case SymTagDimension: return "SymTagDimension";
case SymTagCallSite: return "SymTagCallSite";
case SymTagInlineSite: return "SymTagInlineSite";
case SymTagBaseInterface: return "SymTagBaseInterface";
case SymTagVectorType: return "SymTagVectorType";
case SymTagMatrixType: return "SymTagMatrixType";
case SymTagHLSLType: return "SymTagHLSLType";
case SymTagCaller: return "SymTagCaller";
case SymTagCallee: return "SymTagCallee";
case SymTagExport: return "SymTagExport";
case SymTagHeapAllocationSite: return "SymTagHeapAllocationSite";
case SymTagCoffGroup: return "SymTagCoffGroup";

eric pouech
committed
case SymTagInlinee: return "SymTagInlinee";
default: return "---";
}
}
const char* symt_get_name(const struct symt* sym)
{
switch (sym->tag)
{
/* lexical tree */
case SymTagData: return ((const struct symt_data*)sym)->hash_elt.name;
case SymTagFunction:
case SymTagInlineSite: return ((const struct symt_function*)sym)->hash_elt.name;
case SymTagPublicSymbol: return ((const struct symt_public*)sym)->hash_elt.name;

eric pouech
committed
case SymTagLabel: return ((const struct symt_hierarchy_point*)sym)->hash_elt.name;
case SymTagThunk: return ((const struct symt_thunk*)sym)->hash_elt.name;
case SymTagCustom: return ((const struct symt_custom*)sym)->hash_elt.name;
case SymTagEnum: return ((const struct symt_enum*)sym)->hash_elt.name;
case SymTagTypedef: return ((const struct symt_typedef*)sym)->hash_elt.name;
case SymTagUDT: return ((const struct symt_udt*)sym)->hash_elt.name;
case SymTagCompiland: return source_get(((const struct symt_compiland*)sym)->container->module,
((const struct symt_compiland*)sym)->source);
default:
FIXME("Unsupported sym-tag %s\n", symt_get_tag_str(sym->tag));
/* fall through */
case SymTagBaseType:
case SymTagArrayType:
case SymTagPointerType:
case SymTagFunctionType:
case SymTagFunctionArgType:
case SymTagBlock:
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:

eric pouech
committed
WCHAR* symt_get_nameW(const struct symt* sym)
{
const char* name = symt_get_name(sym);
WCHAR* nameW;
DWORD sz;
if (!name) return NULL;
sz = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
if ((nameW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, sz);
return nameW;
}

eric pouech
committed
BOOL symt_get_address(const struct symt* type, ULONG64* addr)
{
switch (type->tag)
{
case SymTagData:
switch (((const struct symt_data*)type)->kind)
{
case DataIsGlobal:
case DataIsFileStatic:

eric pouech
committed
*addr = ((const struct symt_data*)type)->u.var.offset;
break;
default: return FALSE;
}
break;
case SymTagBlock:
*addr = ((const struct symt_block*)type)->ranges[0].low;
break;

eric pouech
committed
case SymTagFunction:

eric pouech
committed
case SymTagInlineSite:
*addr = ((const struct symt_function*)type)->ranges[0].low;

eric pouech
committed
break;

eric pouech
committed
case SymTagPublicSymbol:
*addr = ((const struct symt_public*)type)->address;
break;
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:
case SymTagLabel:
if (!((const struct symt_hierarchy_point*)type)->parent ||
!symt_get_address(((const struct symt_hierarchy_point*)type)->parent, addr))

eric pouech
committed
*addr += ((const struct symt_hierarchy_point*)type)->loc.offset;
break;
case SymTagThunk:
*addr = ((const struct symt_thunk*)type)->address;
break;
case SymTagCustom:
*addr = ((const struct symt_custom*)type)->address;
break;

eric pouech
committed
default:
FIXME("Unsupported sym-tag %s for get-address\n", symt_get_tag_str(type->tag));

eric pouech
committed
/* fall through */
case SymTagExe:
case SymTagCompiland:
case SymTagFunctionType:
case SymTagFunctionArgType:
case SymTagBaseType:
case SymTagUDT:
case SymTagEnum:
case SymTagTypedef:
case SymTagPointerType:
case SymTagArrayType:

eric pouech
committed
return FALSE;
}
return TRUE;
}
static struct symt* symt_find_type_by_name(const struct module* module,
enum SymTagEnum sym_tag,
const char* typename)
{
void* ptr;
struct symt_ht* type;
struct hash_table_iter hti;
assert(typename);
assert(module);
hash_table_iter_init(&module->ht_types, &hti, typename);
while ((ptr = hash_table_iter_up(&hti)))
{
type = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
if ((sym_tag == SymTagNull || type->symt.tag == sym_tag) &&
type->hash_elt.name && !strcmp(type->hash_elt.name, typename))
return &type->symt;
}
SetLastError(ERROR_INVALID_NAME); /* FIXME ?? */
return NULL;
}
static void symt_add_type(struct module* module, struct symt* symt)
{
struct symt** p;
p = vector_add(&module->vtypes, &module->pool);
assert(p);
*p = symt;
}
struct symt_basic* symt_get_basic(enum BasicType bt, unsigned size)
static struct symt_basic cache[32] = { { {SymTagBaseType}, btNoType, 0 } };
int i;
if (bt == btNoType) return &cache[0];
for (i = 1; i < ARRAY_SIZE(cache); i++)
if (cache[i].bt == btNoType) /* empty slot, create new entry */
cache[i].symt.tag = SymTagBaseType;
cache[i].bt = bt;
cache[i].size = size;
return &cache[i];
}
if (cache[i].bt == bt && cache[i].size == size)
return &cache[i];
FIXME("Too few slots in basic types cache\n");
return &cache[0];
}
struct symt_udt* symt_new_udt(struct module* module, const char* typename,
unsigned size, enum UdtKind kind)
{
struct symt_udt* sym;
TRACE_(dbghelp_symt)("Adding udt %s:%s\n",

eric pouech
committed
debugstr_w(module->modulename), typename);
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagUDT;
sym->kind = kind;
sym->size = size;
if (typename)
{
sym->hash_elt.name = pool_strdup(&module->pool, typename);
hash_table_add(&module->ht_types, &sym->hash_elt);
} else sym->hash_elt.name = NULL;
vector_init(&sym->vchildren, sizeof(struct symt*), 8);
symt_add_type(module, &sym->symt);
}
return sym;
}
BOOL symt_set_udt_size(struct module* module, struct symt_udt* udt, unsigned size)
{
assert(udt->symt.tag == SymTagUDT);
if (vector_length(&udt->vchildren) != 0)
{
if (udt->size != size)
FIXME_(dbghelp_symt)("Changing size for %s from %u to %u\n",
udt->hash_elt.name, udt->size, size);
return TRUE;
}
udt->size = size;
return TRUE;
}
/******************************************************************
* symt_add_udt_element
*
* add an element to a udt (struct, class, union)
* the size & offset parameters are expressed in bits (not bytes) so that
* we can mix in the single call bytes aligned elements (regular fields) and
* the others (bit fields)
*/
BOOL symt_add_udt_element(struct module* module, struct symt_udt* udt_type,
const char* name, struct symt* elt_type,
unsigned offset, unsigned bit_offset, unsigned bit_size)
{
struct symt_data* m;
struct symt** p;
assert(udt_type->symt.tag == SymTagUDT);
TRACE_(dbghelp_symt)("Adding %s to UDT %s\n", name, udt_type->hash_elt.name);
Eric Pouech
committed
if (name)
for (i=0; i<vector_length(&udt_type->vchildren); i++)
Eric Pouech
committed
{
m = *(struct symt_data**)vector_at(&udt_type->vchildren, i);
Eric Pouech
committed
assert(m);
assert(m->symt.tag == SymTagData);
if (strcmp(m->hash_elt.name, name) == 0)
return TRUE;
}
}
if ((m = pool_alloc(&module->pool, sizeof(*m))) == NULL) return FALSE;
memset(m, 0, sizeof(*m));
m->symt.tag = SymTagData;
Eric Pouech
committed
m->hash_elt.name = name ? pool_strdup(&module->pool, name) : "";
m->kind = DataIsMember;
m->container = &module->top->symt; /* native defines lexical parent as module, not udt... */
m->type = elt_type;
m->u.member.offset = offset;
m->u.member.bit_offset = bit_offset;
m->u.member.bit_length = bit_size;
p = vector_add(&udt_type->vchildren, &module->pool);
*p = &m->symt;
return TRUE;
}
struct symt_enum* symt_new_enum(struct module* module, const char* typename,
struct symt* basetype)
TRACE_(dbghelp_symt)("Adding enum %s:%s\n",

eric pouech
committed
debugstr_w(module->modulename), typename);
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagEnum;
if (typename)
{
sym->hash_elt.name = pool_strdup(&module->pool, typename);
hash_table_add(&module->ht_types, &sym->hash_elt);
} else sym->hash_elt.name = NULL;
sym->base_type = basetype;
vector_init(&sym->vchildren, sizeof(struct symt*), 8);
symt_add_type(module, &sym->symt);
}
return sym;
}
BOOL symt_add_enum_element(struct module* module, struct symt_enum* enum_type,
const char* name, int value)
{
struct symt_data* e;
struct symt** p;
assert(enum_type->symt.tag == SymTagEnum);
e = pool_alloc(&module->pool, sizeof(*e));
if (e == NULL) return FALSE;
e->symt.tag = SymTagData;
e->hash_elt.name = pool_strdup(&module->pool, name);
e->hash_elt.next = NULL;
e->kind = DataIsConstant;
e->container = &enum_type->symt;
e->type = enum_type->base_type;
V_VT(&e->u.value) = VT_I4;
V_I4(&e->u.value) = value;
p = vector_add(&enum_type->vchildren, &module->pool);
if (!p) return FALSE; /* FIXME we leak e */
*p = &e->symt;
return TRUE;
}
struct symt_array* symt_new_array(struct module* module, int min, DWORD cnt,
struct symt* base, struct symt* index)
{
struct symt_array* sym;
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagArrayType;
sym->start = min;
sym->base_type = base;
sym->index_type = index;
symt_add_type(module, &sym->symt);
}
return sym;
}
struct symt_function_signature* symt_new_function_signature(struct module* module,
struct symt* ret_type,
enum CV_call_e call_conv)
struct symt_function_signature* sym;
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagFunctionType;
sym->rettype = ret_type;
vector_init(&sym->vchildren, sizeof(struct symt*), 4);
sym->call_conv = call_conv;
symt_add_type(module, &sym->symt);
BOOL symt_add_function_signature_parameter(struct module* module,
struct symt_function_signature* sig_type,
struct symt* param)
{
struct symt** p;
struct symt_function_arg_type* arg;
assert(sig_type->symt.tag == SymTagFunctionType);
arg = pool_alloc(&module->pool, sizeof(*arg));
if (!arg) return FALSE;
arg->symt.tag = SymTagFunctionArgType;
arg->arg_type = param;
p = vector_add(&sig_type->vchildren, &module->pool);
if (!p) return FALSE; /* FIXME we leak arg */
*p = &arg->symt;
return TRUE;
}
struct symt_pointer* symt_new_pointer(struct module* module, struct symt* ref_type, ULONG_PTR size)
{
struct symt_pointer* sym;
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagPointerType;
sym->pointsto = ref_type;
symt_add_type(module, &sym->symt);
struct symt_typedef* symt_new_typedef(struct module* module, struct symt* ref,
const char* name)
{
struct symt_typedef* sym;
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagTypedef;
sym->type = ref;
sym->hash_elt.name = pool_strdup(&module->pool, name);
hash_table_add(&module->ht_types, &sym->hash_elt);
symt_add_type(module, &sym->symt);
}
return sym;
}
/******************************************************************
* SymEnumTypes (DBGHELP.@)
*
*/
BOOL WINAPI SymEnumTypes(HANDLE hProcess, ULONG64 BaseOfDll,
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
PVOID UserContext)
char buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer;
struct symt* type;
DWORD64 size;
TRACE("(%p %I64x %p %p)\n", hProcess, BaseOfDll, EnumSymbolsCallback, UserContext);
if (!module_init_pair(&pair, hProcess, BaseOfDll)) return FALSE;
sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
for (i=0; i<vector_length(&pair.effective->vtypes); i++)
type = *(struct symt**)vector_at(&pair.effective->vtypes, i);
sym_info->TypeIndex = symt_ptr2index(pair.effective, type);
sym_info->Index = 0; /* FIXME */
symt_get_info(pair.effective, type, TI_GET_LENGTH, &size);
sym_info->Size = size;
sym_info->ModBase = pair.requested->module.BaseOfImage;
sym_info->Flags = 0; /* FIXME */
sym_info->Value = 0; /* FIXME */
sym_info->Address = 0; /* FIXME */
sym_info->Register = 0; /* FIXME */
sym_info->Scope = 0; /* FIXME */
sym_info->Tag = type->tag;
symbol_setname(sym_info, symt_get_name(type));
if (!EnumSymbolsCallback(sym_info, sym_info->Size, UserContext)) break;
}
return TRUE;
}
struct enum_types_AtoW
{
char buffer[sizeof(SYMBOL_INFOW) + 256 * sizeof(WCHAR)];
void* user;
PSYM_ENUMERATESYMBOLS_CALLBACKW callback;
};
static BOOL CALLBACK enum_types_AtoW(PSYMBOL_INFO si, ULONG size, PVOID _et)
{
struct enum_types_AtoW* et = _et;
SYMBOL_INFOW* siW = (SYMBOL_INFOW*)et->buffer;
copy_symbolW(siW, si);
return et->callback(siW, size, et->user);
}
/******************************************************************
* SymEnumTypesW (DBGHELP.@)
*
*/
BOOL WINAPI SymEnumTypesW(HANDLE hProcess, ULONG64 BaseOfDll,
PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
PVOID UserContext)
{
struct enum_types_AtoW et;
et.callback = EnumSymbolsCallback;
et.user = UserContext;
return SymEnumTypes(hProcess, BaseOfDll, enum_types_AtoW, &et);
}
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
static void enum_types_of_module(struct module_pair* pair, const char* name, PSYM_ENUMERATESYMBOLS_CALLBACK cb, PVOID user)
{
char buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer;
struct symt* type;
DWORD64 size;
unsigned i;
const char* tname;
sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
for (i = 0; i < vector_length(&pair->effective->vtypes); i++)
{
type = *(struct symt**)vector_at(&pair->effective->vtypes, i);
tname = symt_get_name(type);
if (tname && SymMatchStringA(tname, name, TRUE))
{
sym_info->TypeIndex = symt_ptr2index(pair->effective, type);
sym_info->Index = 0; /* FIXME */
symt_get_info(pair->effective, type, TI_GET_LENGTH, &size);
sym_info->Size = size;
sym_info->ModBase = pair->requested->module.BaseOfImage;
sym_info->Flags = 0; /* FIXME */
sym_info->Value = 0; /* FIXME */
sym_info->Address = 0; /* FIXME */
sym_info->Register = 0; /* FIXME */
sym_info->Scope = 0; /* FIXME */
sym_info->Tag = type->tag;
symbol_setname(sym_info, tname);
if (!cb(sym_info, sym_info->Size, user)) break;
}
}
}
static BOOL walk_modules(struct module_pair* pair)
{
/* first walk PE only modules */
if (!pair->requested || pair->requested->type == DMT_PE)
{
while ((pair->requested = pair->requested ? pair->requested->next : pair->pcs->lmodules) != NULL)
{
if (pair->requested->type == DMT_PE && module_get_debug(pair)) return TRUE;
}
}
/* then walk ELF or Mach-O modules, not containing PE modules */
while ((pair->requested = pair->requested ? pair->requested->next : pair->pcs->lmodules) != NULL)
{
if ((pair->requested->type == DMT_ELF || pair->requested->type == DMT_MACHO) &&
!module_get_containee(pair->pcs, pair->requested) &&
module_get_debug(pair))
return TRUE;
}
return FALSE;
}
BOOL WINAPI SymEnumTypesByName(HANDLE proc, ULONG64 base, PCSTR name, PSYM_ENUMERATESYMBOLS_CALLBACK cb, PVOID user)
{
struct module_pair pair;
const char* bang;
TRACE("(%p %I64x %s %p %p)\n", proc, base, wine_dbgstr_a(name), cb, user);
if (!name) return SymEnumTypes(proc, base, cb, user);
bang = strchr(name, '!');
if (bang)
{
DWORD sz;
WCHAR* modW;
pair.pcs = process_find_by_handle(proc);
if (bang == name) return FALSE;
if (!pair.pcs) return FALSE;
sz = MultiByteToWideChar(CP_ACP, 0, name, bang - name, NULL, 0) + 1;
if ((modW = malloc(sz * sizeof(WCHAR))) == NULL) return FALSE;
MultiByteToWideChar(CP_ACP, 0, name, bang - name, modW, sz);
modW[sz - 1] = L'\0';
pair.requested = NULL;
while (walk_modules(&pair))
{
if (SymMatchStringW(pair.requested->modulename, modW, FALSE))
enum_types_of_module(&pair, bang + 1, cb, user);
}
free(modW);
}
else
{
if (!module_init_pair(&pair, proc, base) || !module_get_debug(&pair)) return FALSE;
enum_types_of_module(&pair, name, cb, user);
}
return TRUE;
}
BOOL WINAPI SymEnumTypesByNameW(HANDLE proc, ULONG64 base, PCWSTR nameW, PSYM_ENUMERATESYMBOLS_CALLBACKW cb, PVOID user)
{
struct enum_types_AtoW et;
DWORD len = nameW ? WideCharToMultiByte(CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL) : 0;
char* name;
BOOL ret;
TRACE("(%p %I64x %s %p %p)\n", proc, base, wine_dbgstr_w(nameW), cb, user);
if (len)
{
if (!(name = malloc(len))) return FALSE;
WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, len, NULL, NULL);
}
else name = NULL;
et.callback = cb;
et.user = user;
ret = SymEnumTypesByName(proc, base, name, enum_types_AtoW, &et);
free(name);
return ret;
}
/******************************************************************
* symt_get_info
*
* Retrieves information about a symt (either symbol or type)
BOOL symt_get_info(struct module* module, const struct symt* type,
IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo)
{
unsigned len;
if (!type) return FALSE;
/* helper to typecast pInfo to its expected type (_t) */
#define X(_t) (*((_t*)pInfo))
switch (req)
{
case TI_FINDCHILDREN:
{
const struct vector* v;
struct symt** pt;
unsigned i;
TI_FINDCHILDREN_PARAMS* tifp = pInfo;
switch (type->tag)
{

eric pouech
committed
case SymTagExe: v = &((const struct symt_module*)type)->vchildren; break;
case SymTagCompiland: v = &((const struct symt_compiland*)type)->vchildren; break;
case SymTagUDT: v = &((const struct symt_udt*)type)->vchildren; break;
case SymTagEnum: v = &((const struct symt_enum*)type)->vchildren; break;
case SymTagFunctionType: v = &((const struct symt_function_signature*)type)->vchildren; break;
case SymTagFunction:
case SymTagInlineSite: v = &((const struct symt_function*)type)->vchildren; break;
case SymTagBlock: v = &((const struct symt_block*)type)->vchildren; break;
case SymTagPointerType:
case SymTagArrayType:
case SymTagFunctionArgType:
case SymTagThunk:
case SymTagLabel:
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:
case SymTagTypedef:
case SymTagBaseType:
/* for those, CHILDRENCOUNT returns 0 */
return tifp->Count == 0;
FIXME("Unsupported sym-tag %s for find-children\n",
symt_get_tag_str(type->tag));
return FALSE;
}
for (i = 0; i < tifp->Count; i++)
{
if (!(pt = vector_at(v, tifp->Start + i))) return FALSE;
tifp->ChildId[i] = symt_ptr2index(module, *pt);
}
}
break;
case TI_GET_ADDRESS:

eric pouech
committed
return symt_get_address(type, (ULONG64*)pInfo);
switch (type->tag)
{
case SymTagBaseType:
X(DWORD) = ((const struct symt_basic*)type)->bt;
break;
case SymTagEnum:
return symt_get_info(module, ((const struct symt_enum*)type)->base_type, req, pInfo);
default:
return FALSE;
}
break;
case TI_GET_BITPOSITION:
if (type->tag == SymTagData &&
((const struct symt_data*)type)->kind == DataIsMember &&
((const struct symt_data*)type)->u.member.bit_length != 0)
X(DWORD) = ((const struct symt_data*)type)->u.member.bit_offset;
else return FALSE;
break;
case TI_GET_CHILDRENCOUNT:
switch (type->tag)
{

eric pouech
committed
case SymTagExe:
X(DWORD) = vector_length(&((const struct symt_module*)type)->vchildren);
break;
case SymTagCompiland:
X(DWORD) = vector_length(&((const struct symt_compiland*)type)->vchildren);
break;
X(DWORD) = vector_length(&((const struct symt_udt*)type)->vchildren);
X(DWORD) = vector_length(&((const struct symt_enum*)type)->vchildren);
case SymTagFunctionType:
X(DWORD) = vector_length(&((const struct symt_function_signature*)type)->vchildren);
break;
case SymTagFunction:

eric pouech
committed
case SymTagInlineSite:
X(DWORD) = vector_length(&((const struct symt_function*)type)->vchildren);

eric pouech
committed
break;
case SymTagBlock:
X(DWORD) = vector_length(&((const struct symt_block*)type)->vchildren);
break;
/* some SymTag:s return 0 */
case SymTagPointerType:
case SymTagArrayType:
case SymTagFunctionArgType:
case SymTagThunk:
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:
case SymTagLabel:
case SymTagTypedef:
case SymTagBaseType:
X(DWORD) = 0;
break;
FIXME("Unsupported sym-tag %s for get-children-count\n",
symt_get_tag_str(type->tag));
/* some others return error */
case SymTagData:
case SymTagPublicSymbol:
return FALSE;
}
break;
case TI_GET_COUNT:
switch (type->tag)
{
case SymTagArrayType:
X(DWORD) = ((const struct symt_array*)type)->count;
break;
case SymTagFunctionType:
/* this seems to be wrong for (future) C++ methods, where 'this' parameter
* should be included in this value (and not in GET_CHILDREN_COUNT)
*/
X(DWORD) = vector_length(&((const struct symt_function_signature*)type)->vchildren);
break;
default: return FALSE;
}
break;
case TI_GET_DATAKIND:
if (type->tag != SymTagData) return FALSE;
X(DWORD) = ((const struct symt_data*)type)->kind;
break;
case TI_GET_LENGTH:
switch (type->tag)
{
case SymTagBaseType:
X(DWORD64) = ((const struct symt_basic*)type)->size;
X(DWORD64) = addr_range_size(&((const struct symt_function*)type)->ranges[0]);
case SymTagBlock:
/* When there are several ranges available, we can only return one contiguous chunk of memory.
* We return only the first range. It will lead to not report the other ranges
* being part of the block, but it will not return gaps (between the ranges) as being
* part of the block.
* So favor a correct (yet incomplete) value than an incorrect one.
*/
if (((const struct symt_block*)type)->num_ranges > 1)
WARN("Only returning first range from multiple ranges\n");
X(DWORD64) = ((const struct symt_block*)type)->ranges[0].high - ((const struct symt_block*)type)->ranges[0].low;
break;
X(DWORD64) = ((const struct symt_pointer*)type)->size;
X(DWORD64) = ((const struct symt_udt*)type)->size;
if (!symt_get_info(module, ((const struct symt_enum*)type)->base_type, TI_GET_LENGTH, pInfo))
return FALSE;
switch (((const struct symt_data*)type)->kind)
{
case DataIsMember:
if (!((const struct symt_data*)type)->u.member.bit_length)
return FALSE;
X(DWORD64) = ((const struct symt_data*)type)->u.member.bit_length;
break;
default:
if (!symt_get_info(module, ((const struct symt_data*)type)->type, TI_GET_LENGTH, pInfo))
return FALSE;
}
case SymTagArrayType:
if (!symt_get_info(module, ((const struct symt_array*)type)->base_type,
TI_GET_LENGTH, pInfo))
return FALSE;
X(DWORD64) *= ((const struct symt_array*)type)->count;
X(DWORD64) = ((const struct symt_public*)type)->size;
case SymTagTypedef:
return symt_get_info(module, ((const struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo);
case SymTagThunk:
X(DWORD64) = ((const struct symt_thunk*)type)->size;
break;
case SymTagCustom:
X(DWORD64) = ((const struct symt_custom*)type)->size;
break;
FIXME("Unsupported sym-tag %s for get-length\n",
symt_get_tag_str(type->tag));
/* fall through */

eric pouech
committed
case SymTagExe:
case SymTagCompiland:
case SymTagFunctionType:

eric pouech
committed
case SymTagInlineSite: /* native doesn't expose it, perhaps because of non-contiguous range */
case SymTagLabel:
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:
}
break;
case TI_GET_LEXICALPARENT:
switch (type->tag)
{

eric pouech
committed
case SymTagCompiland:
X(DWORD) = symt_ptr2index(module, &((const struct symt_compiland*)type)->container->symt);
break;
X(DWORD) = symt_ptr2index(module, ((const struct symt_block*)type)->container);
X(DWORD) = symt_ptr2index(module, ((const struct symt_data*)type)->container);
break;
case SymTagFunction:

eric pouech
committed
case SymTagInlineSite:
X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->container);

eric pouech
committed
break;
case SymTagThunk:
X(DWORD) = symt_ptr2index(module, ((const struct symt_thunk*)type)->container);

eric pouech
committed
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:
case SymTagLabel:
X(DWORD) = symt_ptr2index(module, ((const struct symt_hierarchy_point*)type)->parent);
break;
case SymTagUDT:
case SymTagEnum:

eric pouech
committed
case SymTagFunctionType:

eric pouech
committed
case SymTagFunctionArgType:

eric pouech
committed
case SymTagPointerType:
case SymTagArrayType:
case SymTagBaseType:
case SymTagTypedef:
case SymTagBaseClass:

eric pouech
committed
case SymTagPublicSymbol:
X(DWORD) = symt_ptr2index(module, &module->top->symt);
break;
FIXME("Unsupported sym-tag %s for get-lexical-parent\n",
symt_get_tag_str(type->tag));

eric pouech
committed
/* fall through */
case SymTagExe:
return FALSE;
}
break;
case TI_GET_NESTED:
switch (type->tag)
{
case SymTagUDT:
case SymTagEnum:
X(DWORD) = 0;
break;
default:
return FALSE;
}
break;
case TI_GET_OFFSET:
switch (type->tag)
{
case SymTagData:
switch (((const struct symt_data*)type)->kind)
case DataIsParam:
case DataIsLocal:

eric pouech
committed
{
struct location loc = ((const struct symt_data*)type)->u.var;
if (loc.kind == loc_register || loc.kind == loc_regrel)
X(ULONG) = ((const struct symt_data*)type)->u.var.offset;
else
return FALSE; /* FIXME perhaps do better with local context? */
}
break;
case DataIsMember:
X(ULONG) = ((const struct symt_data*)type)->u.member.offset;
WARN("Unsupported kind (%u) for get-offset\n",
((const struct symt_data*)type)->kind);
return FALSE;
FIXME("Unsupported sym-tag %s for get-offset\n",
symt_get_tag_str(type->tag));
/* fall through */
case SymTagExe:
case SymTagCompiland:
case SymTagUDT:
case SymTagFunctionType:
case SymTagFunctionArgType:
case SymTagPointerType:
case SymTagArrayType:
case SymTagBaseType:
case SymTagTypedef:
case SymTagFunction:
case SymTagBlock:
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:
case SymTagLabel:

eric pouech
committed
case SymTagInlineSite:
case SymTagPublicSymbol:
case SymTagThunk:
return FALSE;
}
break;
case TI_GET_SYMNAME:
if (type->tag == SymTagExe)
{
DWORD len = (lstrlenW(module->modulename) + 1) * sizeof(WCHAR);
WCHAR* wname = HeapAlloc(GetProcessHeap(), 0, len);
if (!wname) return FALSE;
memcpy(wname, module->modulename, len);
X(WCHAR*) = wname;
}