/* * 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. */ #define NONAMELESSUNION #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"; 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: return ((const struct symt_function*)sym)->hash_elt.name; case SymTagPublicSymbol: return ((const struct symt_public*)sym)->hash_elt.name; case SymTagBaseType: return ((const struct symt_basic*)sym)->hash_elt.name; case SymTagLabel: return ((const struct symt_hierarchy_point*)sym)->hash_elt.name; case SymTagThunk: return ((const struct symt_thunk*)sym)->hash_elt.name; /* hierarchy tree */ case SymTagEnum: return ((const struct symt_enum*)sym)->name; case SymTagTypedef: return ((const struct symt_typedef*)sym)->hash_elt.name; case SymTagUDT: return ((const struct symt_udt*)sym)->hash_elt.name; default: FIXME("Unsupported sym-tag %s\n", symt_get_tag_str(sym->tag)); /* fall through */ case SymTagArrayType: case SymTagPointerType: case SymTagFunctionType: return NULL; } } 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; } 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: *addr = ((const struct symt_data*)type)->u.var.offset; break; default: return FALSE; } break; case SymTagFunction: *addr = ((const struct symt_function*)type)->address; break; 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)) return FALSE; *addr += ((const struct symt_hierarchy_point*)type)->loc.offset; break; case SymTagThunk: *addr = ((const struct symt_thunk*)type)->address; break; case SymTagCompiland: *addr = ((const struct symt_compiland*)type)->address; break; default: FIXME("Unsupported sym-tag %s for get-address\n", symt_get_tag_str(type->tag)); 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_new_basic(struct module* module, enum BasicType bt, const char* typename, unsigned size) { struct symt_basic* sym; if (typename) { sym = (struct symt_basic*)symt_find_type_by_name(module, SymTagBaseType, typename); if (sym && sym->bt == bt && sym->size == size) return sym; } if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { sym->symt.tag = SymTagBaseType; 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->bt = bt; sym->size = size; symt_add_type(module, &sym->symt); } return sym; } 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", debugstr_w(module->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 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); if (name) { unsigned int i; for (i=0; i<vector_length(&udt_type->vchildren); i++) { m = *(struct symt_data**)vector_at(&udt_type->vchildren, i); 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; m->hash_elt.name = name ? pool_strdup(&module->pool, name) : ""; m->hash_elt.next = NULL; m->kind = DataIsMember; m->container = &udt_type->symt; m->type = elt_type; m->u.member.offset = offset; m->u.member.length = ((offset & 7) || (size & 7)) ? size : 0; 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) { struct symt_enum* sym; if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { sym->symt.tag = SymTagEnum; sym->name = (typename) ? pool_strdup(&module->pool, typename) : NULL; sym->base_type = basetype; vector_init(&sym->vchildren, sizeof(struct symt*), 8); } 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; e->u.value.n1.n2.vt = VT_I4; e->u.value.n1.n2.n3.lVal = 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, int max, 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->end = max; sym->base_type = base; sym->index_type = index; symt_add_type(module, &sym->symt); } return sym; } static inline DWORD symt_array_count(struct module* module, const struct symt_array* array) { if (array->end < 0) { DWORD64 elem_size; /* One could want to also set the array->end field in array, but we won't do it * as long as all the get_type() helpers use const objects */ if (symt_get_info(module, array->base_type, TI_GET_LENGTH, &elem_size) && elem_size) return -array->end / (DWORD)elem_size; return 0; } return array->end - array->start + 1; } 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); } return sym; } 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; arg->container = &sig_type->symt; 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; sym->size = size; symt_add_type(module, &sym->symt); } return sym; } 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) { struct module_pair pair; char buffer[sizeof(SYMBOL_INFO) + 256]; SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer; const char* tmp; struct symt* type; DWORD64 size; unsigned int i; TRACE("(%p %s %p %p)\n", hProcess, wine_dbgstr_longlong(BaseOfDll), EnumSymbolsCallback, UserContext); if (!(pair.pcs = process_find_by_handle(hProcess))) return FALSE; pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN); if (!module_get_debug(&pair)) 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; tmp = symt_get_name(type); if (tmp) { sym_info->NameLen = min(strlen(tmp),sym_info->MaxNameLen-1); memcpy(sym_info->Name, tmp, sym_info->NameLen); sym_info->Name[sym_info->NameLen] = '\0'; } else sym_info->Name[sym_info->NameLen = 0] = '\0'; 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 addr, PVOID _et) { struct enum_types_AtoW* et = _et; SYMBOL_INFOW* siW = (SYMBOL_INFOW*)et->buffer; copy_symbolW(siW, si); return et->callback(siW, addr, 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); } /****************************************************************** * 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) { 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: v = &((const struct symt_function*)type)->vchildren; break; default: 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: return symt_get_address(type, (ULONG64*)pInfo); case TI_GET_BASETYPE: switch (type->tag) { case SymTagBaseType: X(DWORD) = ((const struct symt_basic*)type)->bt; break; case SymTagEnum: X(DWORD) = btInt; break; 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.length != 0) X(DWORD) = ((const struct symt_data*)type)->u.member.offset & 7; else return FALSE; break; case TI_GET_CHILDRENCOUNT: switch (type->tag) { case SymTagUDT: X(DWORD) = vector_length(&((const struct symt_udt*)type)->vchildren); break; case SymTagEnum: X(DWORD) = vector_length(&((const struct symt_enum*)type)->vchildren); break; case SymTagFunctionType: X(DWORD) = vector_length(&((const struct symt_function_signature*)type)->vchildren); break; case SymTagFunction: X(DWORD) = vector_length(&((const struct symt_function*)type)->vchildren); break; case SymTagPointerType: /* MS does it that way */ case SymTagArrayType: /* MS does it that way */ case SymTagThunk: /* MS does it that way */ X(DWORD) = 0; break; default: FIXME("Unsupported sym-tag %s for get-children-count\n", symt_get_tag_str(type->tag)); /* fall through */ case SymTagData: case SymTagPublicSymbol: case SymTagBaseType: return FALSE; } break; case TI_GET_COUNT: switch (type->tag) { case SymTagArrayType: X(DWORD) = symt_array_count(module, (const struct symt_array*)type); 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; break; case SymTagFunction: X(DWORD64) = ((const struct symt_function*)type)->size; break; case SymTagPointerType: X(DWORD64) = ((const struct symt_pointer*)type)->size; break; case SymTagUDT: X(DWORD64) = ((const struct symt_udt*)type)->size; break; case SymTagEnum: X(DWORD64) = sizeof(int); /* FIXME: should be size of base-type of enum !!! */ break; case SymTagData: if (((const struct symt_data*)type)->kind != DataIsMember || !((const struct symt_data*)type)->u.member.length) return FALSE; X(DWORD64) = ((const struct symt_data*)type)->u.member.length; break; case SymTagArrayType: if (!symt_get_info(module, ((const struct symt_array*)type)->base_type, TI_GET_LENGTH, pInfo)) return FALSE; X(DWORD64) *= symt_array_count(module, (const struct symt_array*)type); break; case SymTagPublicSymbol: X(DWORD64) = ((const struct symt_public*)type)->size; break; 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 SymTagLabel: X(DWORD64) = 0; break; default: FIXME("Unsupported sym-tag %s for get-length\n", symt_get_tag_str(type->tag)); /* fall through */ case SymTagFunctionType: return FALSE; } break; case TI_GET_LEXICALPARENT: switch (type->tag) { case SymTagBlock: X(DWORD) = symt_ptr2index(module, ((const struct symt_block*)type)->container); break; case SymTagData: X(DWORD) = symt_ptr2index(module, ((const struct symt_data*)type)->container); break; case SymTagFunction: X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->container); break; case SymTagThunk: X(DWORD) = symt_ptr2index(module, ((const struct symt_thunk*)type)->container); break; case SymTagFunctionArgType: X(DWORD) = symt_ptr2index(module, ((const struct symt_function_arg_type*)type)->container); break; default: FIXME("Unsupported sym-tag %s for get-lexical-parent\n", symt_get_tag_str(type->tag)); 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: X(ULONG) = ((const struct symt_data*)type)->u.var.offset; break; case DataIsMember: X(ULONG) = ((const struct symt_data*)type)->u.member.offset >> 3; break; default: FIXME("Unknown kind (%u) for get-offset\n", ((const struct symt_data*)type)->kind); return FALSE; } break; default: FIXME("Unsupported sym-tag %s for get-offset\n", symt_get_tag_str(type->tag)); return FALSE; } break; case TI_GET_SYMNAME: { const char* name = symt_get_name(type); if (!name) return FALSE; len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0); X(WCHAR*) = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); if (!X(WCHAR*)) return FALSE; MultiByteToWideChar(CP_ACP, 0, name, -1, X(WCHAR*), len); } break; case TI_GET_SYMTAG: X(DWORD) = type->tag; break; case TI_GET_TYPE: case TI_GET_TYPEID: switch (type->tag) { /* hierarchical => hierarchical */ case SymTagArrayType: X(DWORD) = symt_ptr2index(module, ((const struct symt_array*)type)->base_type); break; case SymTagPointerType: X(DWORD) = symt_ptr2index(module, ((const struct symt_pointer*)type)->pointsto); break; case SymTagFunctionType: X(DWORD) = symt_ptr2index(module, ((const struct symt_function_signature*)type)->rettype); break; case SymTagTypedef: X(DWORD) = symt_ptr2index(module, ((const struct symt_typedef*)type)->type); break; /* lexical => hierarchical */ case SymTagData: X(DWORD) = symt_ptr2index(module, ((const struct symt_data*)type)->type); break; case SymTagFunction: X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->type); break; case SymTagEnum: X(DWORD) = symt_ptr2index(module, ((const struct symt_enum*)type)->base_type); break; case SymTagFunctionArgType: X(DWORD) = symt_ptr2index(module, ((const struct symt_function_arg_type*)type)->arg_type); break; default: FIXME("Unsupported sym-tag %s for get-type\n", symt_get_tag_str(type->tag)); /* fall through */ case SymTagPublicSymbol: case SymTagThunk: case SymTagLabel: return FALSE; } break; case TI_GET_UDTKIND: if (type->tag != SymTagUDT) return FALSE; X(DWORD) = ((const struct symt_udt*)type)->kind; break; case TI_GET_VALUE: if (type->tag != SymTagData) return FALSE; switch (((const struct symt_data*)type)->kind) { case DataIsConstant: X(VARIANT) = ((const struct symt_data*)type)->u.value; break; case DataIsLocal: case DataIsParam: { struct location loc = ((const struct symt_data*)type)->u.var; unsigned i; struct module_format* modfmt; if (loc.kind < loc_user) return FALSE; for (i = 0; i < DFI_LAST; i++) { modfmt = module->format_info[i]; if (modfmt && modfmt->loc_compute) { modfmt->loc_compute(module->process, modfmt, (const struct symt_function*)((const struct symt_data*)type)->container, &loc); break; } } if (loc.kind != loc_absolute) return FALSE; X(VARIANT).n1.n2.vt = VT_UI4; /* FIXME */ X(VARIANT).n1.n2.n3.uiVal = loc.offset; } break; default: return FALSE; } break; case TI_GET_CALLING_CONVENTION: if (type->tag != SymTagFunctionType) return FALSE; if (((const struct symt_function_signature*)type)->call_conv == -1) { FIXME("No support for calling convention for this signature\n"); X(DWORD) = CV_CALL_FAR_C; /* FIXME */ } else X(DWORD) = ((const struct symt_function_signature*)type)->call_conv; break; case TI_GET_ARRAYINDEXTYPEID: if (type->tag != SymTagArrayType) return FALSE; X(DWORD) = symt_ptr2index(module, ((const struct symt_array*)type)->index_type); break; case TI_GET_CLASSPARENTID: /* FIXME: we don't support properly C++ for now, pretend this symbol doesn't * belong to a parent class */ return FALSE; #undef X case TI_GET_ADDRESSOFFSET: case TI_GET_SYMINDEX: case TI_GET_THISADJUST: case TI_GET_VIRTUALBASECLASS: case TI_GET_VIRTUALBASEPOINTEROFFSET: case TI_GET_VIRTUALTABLESHAPEID: case TI_IS_EQUIV_TO: FIXME("Unsupported GetInfo request (%u)\n", req); return FALSE; default: FIXME("Unknown GetInfo request (%u)\n", req); return FALSE; } return TRUE; } /****************************************************************** * SymGetTypeInfo (DBGHELP.@) * */ BOOL WINAPI SymGetTypeInfo(HANDLE hProcess, DWORD64 ModBase, ULONG TypeId, IMAGEHLP_SYMBOL_TYPE_INFO GetType, PVOID pInfo) { struct module_pair pair; pair.pcs = process_find_by_handle(hProcess); if (!pair.pcs) return FALSE; pair.requested = module_find_by_addr(pair.pcs, ModBase, DMT_UNKNOWN); if (!module_get_debug(&pair)) { FIXME("Someone didn't properly set ModBase (%s)\n", wine_dbgstr_longlong(ModBase)); return FALSE; } return symt_get_info(pair.effective, symt_index2ptr(pair.effective, TypeId), GetType, pInfo); } /****************************************************************** * SymGetTypeFromName (DBGHELP.@) * */ BOOL WINAPI SymGetTypeFromName(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Name, PSYMBOL_INFO Symbol) { struct process* pcs = process_find_by_handle(hProcess); struct module_pair pair; struct symt* type; if (!pcs) return FALSE; pair.requested = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN); if (!module_get_debug(&pair)) return FALSE; type = symt_find_type_by_name(pair.effective, SymTagNull, Name); if (!type) return FALSE; Symbol->TypeIndex = symt_ptr2index(pair.effective, type); return TRUE; }