| /******************************************************************************* |
| * Copyright (c) 2007, 2014 Wind River Systems, Inc. and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * and Eclipse Distribution License v1.0 which accompany this distribution. |
| * The Eclipse Public License is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * and the Eclipse Distribution License is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * You may elect to redistribute this code under either of these licenses. |
| * |
| * Contributors: |
| * Wind River Systems - initial API and implementation |
| *******************************************************************************/ |
| |
| /* |
| * Symbols service - Windows version |
| */ |
| |
| #include <tcf/config.h> |
| |
| #if SERVICE_Symbols && (!ENABLE_SymbolsProxy || ENABLE_LineNumbersMux) && ENABLE_PE |
| |
| #include <errno.h> |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <wchar.h> |
| #include <tcf/framework/errors.h> |
| #include <tcf/framework/events.h> |
| #include <tcf/framework/myalloc.h> |
| #include <tcf/framework/trace.h> |
| #include <tcf/services/symbols.h> |
| #include <tcf/services/stacktrace.h> |
| #include <tcf/services/memorymap.h> |
| #include <tcf/services/funccall.h> |
| #include <system/Windows/tcf/windbgcache.h> |
| #include <system/Windows/tcf/context-win32.h> |
| #if ENABLE_SymbolsMux |
| #define SYM_READER_PREFIX win32_reader_ |
| #include <tcf/services/symbols_mux.h> |
| #endif |
| |
| #ifndef MAX_SYM_NAME |
| # define MAX_SYM_NAME 2000 |
| #endif |
| |
| typedef struct TypeInfo { |
| char * name; |
| unsigned char size; |
| unsigned char sign; |
| unsigned char real; |
| } TypeInfo; |
| |
| static const TypeInfo basic_type_info[] = { |
| { "void", 0, 0, 0 }, |
| { "char", sizeof(char), 1, 0 }, |
| { "unsigned char", sizeof(char), 0, 0 }, |
| { "signed char", sizeof(char), 1, 0 }, |
| { "short", sizeof(short), 1, 0 }, |
| { "unsigned short", sizeof(short), 0, 0 }, |
| { "signed short", sizeof(short), 1, 0 }, |
| { "short int", sizeof(short), 1, 0 }, |
| { "unsigned short int", sizeof(short), 0, 0 }, |
| { "signed short int", sizeof(short), 1, 0 }, |
| { "int", sizeof(int), 1, 0 }, |
| { "unsigned", sizeof(int), 0, 0 }, |
| { "unsigned int", sizeof(int), 0, 0 }, |
| { "signed int", sizeof(int), 1, 0 }, |
| { "long", sizeof(long), 1, 0 }, |
| { "unsigned long", sizeof(long), 0, 0 }, |
| { "signed long", sizeof(long), 1, 0 }, |
| { "long int", sizeof(long), 1, 0 }, |
| { "unsigned long int", sizeof(long), 0, 0 }, |
| { "signed long int", sizeof(long), 1, 0 }, |
| { "long long", sizeof(int64_t), 1, 0 }, |
| { "unsigned long long", sizeof(int64_t), 0, 0 }, |
| { "signed long long", sizeof(int64_t), 1, 0 }, |
| { "long long int", sizeof(int64_t), 1, 0 }, |
| { "unsigned long long int", sizeof(int64_t), 0, 0 }, |
| { "signed long long int", sizeof(int64_t), 1, 0 }, |
| { "float", sizeof(float), 1, 1 }, |
| { "double", sizeof(double), 1, 1 }, |
| { "long double", sizeof(long double), 1, 1 }, |
| { "uint8_t", 1, 0, 0 }, |
| { "uint16_t", 2, 0, 0 }, |
| { "uint32_t", 4, 0, 0 }, |
| { "uint64_t", 8, 0, 0 }, |
| { "int8_t", 1, 1, 0 }, |
| { "int16_t", 2, 1, 0 }, |
| { "int32_t", 4, 1, 0 }, |
| { "int64_t", 8, 1, 0 }, |
| { "char16_t", 2, 0, 0 }, |
| { "char32_t", 4, 0, 0 }, |
| { NULL } |
| }; |
| |
| #define BST_UNSIGNED 11 |
| |
| struct Symbol { |
| #if ENABLE_SymbolsMux |
| SymbolReader * reader; |
| #endif |
| unsigned magic; |
| Context * ctx; |
| unsigned frame; |
| int sym_class; |
| ULONG64 module; |
| ULONG index; /* The symbol index in debug info section */ |
| const TypeInfo * info; /* If not NULL, the symbol is basic type */ |
| const Symbol * base; /* If not NULL, the symbol is array or pointer with this base type */ |
| size_t length; |
| ContextAddress address; |
| }; |
| |
| typedef struct SymbolCacheEntry { |
| struct SymbolCacheEntry * next; |
| ULONG64 pc; |
| char name[MAX_SYM_NAME]; |
| ErrorReport * error; |
| int sym_class; |
| int frame_relative; |
| ULONG64 module; |
| ULONG index; |
| } SymbolCacheEntry; |
| |
| #define SYMBOL_CACHE_SIZE (4 * MEM_USAGE_FACTOR - 1) |
| |
| typedef struct ContextExtensionWinSym { |
| SymbolCacheEntry ** symbol_cache; |
| } ContextExtensionWinSym; |
| |
| static size_t context_extension_offset = 0; |
| |
| #define EXT(ctx) ((ContextExtensionWinSym *)((char *)(ctx) + context_extension_offset)) |
| |
| static char * tmp_buf = NULL; |
| static int tmp_buf_size = 0; |
| static LocationCommands * location_cmds = NULL; |
| |
| #define SYMBOL_MAGIC 0x34875234 |
| |
| static Symbol * alloc_symbol(void) { |
| Symbol * s = (Symbol *)tmp_alloc_zero(sizeof(Symbol)); |
| #if ENABLE_SymbolsMux |
| s->reader = &symbol_reader; |
| #endif |
| s->magic = SYMBOL_MAGIC; |
| return s; |
| } |
| |
| static int get_stack_frame(Context * ctx, int frame, ContextAddress ip, IMAGEHLP_STACK_FRAME * stack_frame) { |
| memset(stack_frame, 0, sizeof(IMAGEHLP_STACK_FRAME)); |
| if (frame == STACK_NO_FRAME) { |
| stack_frame->InstructionOffset = ip; |
| } |
| else if (ctx->parent != NULL) { |
| uint64_t v = 0; |
| StackFrame * frame_info; |
| if (get_frame_info(ctx, frame, &frame_info) < 0) return -1; |
| if (read_reg_value(frame_info, get_PC_definition(ctx), &v) < 0) return -1; |
| stack_frame->InstructionOffset = v; |
| } |
| return 0; |
| } |
| |
| static int get_sym_info(const Symbol * sym, DWORD index, SYMBOL_INFO ** res) { |
| static ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; |
| SYMBOL_INFO * info = (SYMBOL_INFO *)buffer; |
| HANDLE process = get_context_handle(context_get_group(sym->ctx, CONTEXT_GROUP_PROCESS)); |
| |
| info->SizeOfStruct = sizeof(SYMBOL_INFO); |
| info->MaxNameLen = MAX_SYM_NAME; |
| if (!SymFromIndex(process, sym->module, index, info)) { |
| set_win32_errno(GetLastError()); |
| return -1; |
| } |
| *res = info; |
| return 0; |
| } |
| |
| static int get_type_info(const Symbol * sym, IMAGEHLP_SYMBOL_TYPE_INFO info_tag, void * info) { |
| HANDLE process = get_context_handle(context_get_group(sym->ctx, CONTEXT_GROUP_PROCESS)); |
| if (!SymGetTypeInfo(process, sym->module, sym->index, info_tag, info)) { |
| set_win32_errno(GetLastError()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| static void tag2symclass(Symbol * sym, int tag) { |
| DWORD dword; |
| sym->sym_class = SYM_CLASS_UNKNOWN; |
| switch (tag) { |
| case SymTagFunction: |
| sym->sym_class = SYM_CLASS_FUNCTION; |
| break; |
| case SymTagData: |
| if (get_type_info(sym, TI_GET_DATAKIND, &dword) == 0) { |
| if (dword == DataIsConstant) { |
| sym->sym_class = SYM_CLASS_VALUE; |
| break; |
| } |
| } |
| sym->sym_class = SYM_CLASS_REFERENCE; |
| break; |
| case SymTagUDT: |
| case SymTagEnum: |
| case SymTagFunctionType: |
| case SymTagPointerType: |
| case SymTagArrayType: |
| case SymTagBaseType: |
| case SymTagTypedef: |
| case SymTagBaseClass: |
| case SymTagCustomType: |
| case SymTagManagedType: |
| case SymTagFunctionArgType: |
| sym->sym_class = SYM_CLASS_TYPE; |
| break; |
| } |
| } |
| |
| static int is_frame_relative(SYMBOL_INFO * info) { |
| return (info->Flags & SYMFLAG_FRAMEREL) || (info->Flags & SYMFLAG_REGREL); |
| } |
| |
| static int is_register(SYMBOL_INFO * info) { |
| return info->Flags & SYMFLAG_REGISTER; |
| } |
| |
| static int syminfo2symbol(Context * ctx, int frame, SYMBOL_INFO * info, Symbol * sym) { |
| sym->module = info->ModBase; |
| sym->index = info->Index; |
| if (is_frame_relative(info) || is_register(info)) { |
| if (frame == STACK_NO_FRAME) return 0; |
| assert(frame >= 0); |
| assert(ctx != ctx->mem); |
| sym->frame = frame - STACK_NO_FRAME; |
| } |
| else { |
| assert(sym->frame == 0); |
| ctx = ctx->mem; |
| } |
| sym->ctx = ctx; |
| tag2symclass(sym, info->Tag); |
| return 1; |
| } |
| |
| static int get_type_tag(Symbol * type, DWORD * tag) { |
| DWORD dword; |
| for (;;) { |
| if (get_type_info(type, TI_GET_SYMTAG, &dword) < 0) return -1; |
| switch (dword) { |
| case SymTagTypedef: |
| case SymTagFunction: |
| case SymTagData: |
| case SymTagFunctionArgType: |
| if (get_type_info(type, TI_GET_TYPE, &dword) < 0) return -1; |
| type->index = dword; |
| continue; |
| } |
| break; |
| } |
| type->sym_class = SYM_CLASS_TYPE; |
| *tag = dword; |
| return 0; |
| } |
| |
| const char * symbol2id(const Symbol * sym) { |
| static char buf[256]; |
| assert(sym->magic == SYMBOL_MAGIC); |
| if (sym->base) { |
| char base[sizeof(buf)]; |
| assert(sym->ctx == sym->base->ctx); |
| assert(sym->sym_class == SYM_CLASS_TYPE); |
| strcpy(base, symbol2id(sym->base)); |
| snprintf(buf, sizeof(buf), "@P%"PRIX64".%s", (uint64_t)sym->length, base); |
| } |
| else { |
| int i = sym->info ? (int)(sym->info - basic_type_info) + 1 : 0; |
| snprintf(buf, sizeof(buf), "@S%"PRIX64".%lX.%X.%X.%s", |
| (uint64_t)sym->module, sym->index, sym->frame, i, sym->ctx->id); |
| } |
| return buf; |
| } |
| |
| static uint64_t read_hex(const char ** s) { |
| uint64_t res = 0; |
| const char * p = *s; |
| for (;;) { |
| if (*p >= '0' && *p <= '9') res = (res << 4) | (*p - '0'); |
| else if (*p >= 'A' && *p <= 'F') res = (res << 4) | (*p - 'A' + 10); |
| else break; |
| p++; |
| } |
| *s = p; |
| return res; |
| } |
| |
| int id2symbol(const char * id, Symbol ** res) { |
| Symbol * sym = NULL; |
| Context * ctx = NULL; |
| ULONG64 module = 0; |
| ULONG index = 0; |
| unsigned frame = 0; |
| const Symbol * base = NULL; |
| const TypeInfo * info = NULL; |
| size_t length = 0; |
| const char * p; |
| |
| if (id != NULL && id[0] == '@' && id[1] == 'P') { |
| p = id + 2; |
| length = (size_t)read_hex(&p); |
| if (*p == '.') p++; |
| if (id2symbol(p, (Symbol **)&base)) return -1; |
| ctx = base->ctx; |
| } |
| else if (id != NULL && id[0] == '@' && id[1] == 'S') { |
| unsigned idx = 0; |
| p = id + 2; |
| module = (ULONG64)read_hex(&p); |
| if (*p == '.') p++; |
| index = (ULONG)read_hex(&p); |
| if (*p == '.') p++; |
| frame = (unsigned)read_hex(&p); |
| if (*p == '.') p++; |
| idx = (unsigned)read_hex(&p); |
| if (idx) info = basic_type_info + (idx - 1); |
| if (*p == '.') p++; |
| ctx = id2ctx(p); |
| } |
| else { |
| errno = ERR_INV_CONTEXT; |
| return -1; |
| } |
| if (ctx == NULL) { |
| errno = ERR_INV_CONTEXT; |
| return -1; |
| } |
| sym = alloc_symbol(); |
| sym->ctx = ctx; |
| sym->module = module; |
| sym->index = index; |
| sym->frame = frame; |
| sym->base = base; |
| sym->info = info; |
| sym->length = length; |
| if (sym->base || sym->info) { |
| sym->sym_class = SYM_CLASS_TYPE; |
| } |
| else { |
| DWORD dword = 0; |
| if (get_type_info(sym, TI_GET_SYMTAG, &dword) < 0) return -1; |
| tag2symclass(sym, dword); |
| } |
| *res = sym; |
| return 0; |
| } |
| |
| int get_symbol_class(const Symbol * sym, int * sym_class) { |
| assert(sym->magic == SYMBOL_MAGIC); |
| *sym_class = sym->sym_class; |
| return 0; |
| } |
| |
| int get_symbol_type_class(const Symbol * sym, int * type_class) { |
| int res = TYPE_CLASS_UNKNOWN; |
| Symbol type = *sym; |
| DWORD tag = 0; |
| DWORD base = 0; |
| |
| assert(sym->magic == SYMBOL_MAGIC); |
| if (sym->base) { |
| *type_class = sym->length == 0 ? TYPE_CLASS_POINTER : TYPE_CLASS_ARRAY; |
| return 0; |
| } |
| if (sym->info) { |
| if (sym->info->real) { |
| *type_class = TYPE_CLASS_REAL; |
| } |
| else if (sym->info->sign) { |
| *type_class = TYPE_CLASS_INTEGER; |
| } |
| else { |
| *type_class = TYPE_CLASS_CARDINAL; |
| } |
| return 0; |
| } |
| if (get_type_tag(&type, &tag)) return -1; |
| |
| switch (tag) { |
| case SymTagFunction: |
| case SymTagPublicSymbol: |
| res = TYPE_CLASS_FUNCTION; |
| break; |
| case SymTagEnum: |
| res = TYPE_CLASS_ENUMERATION; |
| break; |
| case SymTagFunctionType: |
| res = TYPE_CLASS_FUNCTION; |
| break; |
| case SymTagPointerType: |
| res = TYPE_CLASS_POINTER; |
| break; |
| case SymTagArrayType: |
| res = TYPE_CLASS_ARRAY; |
| break; |
| case SymTagUDT: |
| res = TYPE_CLASS_COMPOSITE; |
| break; |
| case SymTagBaseType: |
| if (get_type_info(&type, TI_GET_BASETYPE, &base) < 0) return -1; |
| switch (base) { |
| case btNoType: |
| break; |
| case btVoid: |
| case btChar: |
| case btWChar: |
| case btInt: |
| case btBool: |
| case btLong: |
| case btBit: |
| res = TYPE_CLASS_INTEGER; |
| break; |
| case btUInt: |
| case btULong: |
| res = TYPE_CLASS_CARDINAL; |
| break; |
| case btFloat: |
| res = TYPE_CLASS_REAL; |
| break; |
| case btBCD: |
| case btCurrency: |
| case btDate: |
| case btVariant: |
| case btComplex: |
| case btBSTR: |
| case btHresult: |
| break; |
| } |
| break; |
| } |
| |
| *type_class = res; |
| return 0; |
| } |
| |
| int get_symbol_update_policy(const Symbol * sym, char ** id, int * policy) { |
| assert(sym->magic == SYMBOL_MAGIC); |
| *id = sym->ctx->id; |
| *policy = sym->frame > 0 ? UPDATE_ON_EXE_STATE_CHANGES : UPDATE_ON_MEMORY_MAP_CHANGES; |
| return 0; |
| } |
| |
| int get_symbol_name(const Symbol * sym, char ** name) { |
| WCHAR * ptr = NULL; |
| |
| assert(sym->magic == SYMBOL_MAGIC); |
| if (sym->base) { |
| *name = NULL; |
| return 0; |
| } |
| if (sym->info) { |
| *name = sym->info->name; |
| return 0; |
| } |
| *name = NULL; |
| if (get_type_info(sym, TI_GET_SYMNAME, &ptr) < 0) ptr = NULL; |
| if (ptr != NULL && wcscmp(ptr, L"<unnamed-tag>") == 0) ptr = NULL; |
| if (ptr != NULL) { |
| int len = 0; |
| int err = 0; |
| if (tmp_buf == NULL) { |
| tmp_buf_size = 256; |
| tmp_buf = (char *)loc_alloc(tmp_buf_size); |
| } |
| for (;;) { |
| len = WideCharToMultiByte(CP_UTF8, 0, ptr, -1, tmp_buf, tmp_buf_size - 1, NULL, NULL); |
| if (len != 0) break; |
| err = GetLastError(); |
| if (err != ERROR_INSUFFICIENT_BUFFER) { |
| set_win32_errno(err); |
| return -1; |
| } |
| tmp_buf_size *= 2; |
| tmp_buf = (char *)loc_realloc(tmp_buf, tmp_buf_size); |
| } |
| HeapFree(GetProcessHeap(), 0, ptr); |
| tmp_buf[len] = 0; |
| *name = tmp_buf; |
| } |
| else { |
| DWORD tag = 0; |
| Symbol type = *sym; |
| if (get_type_tag(&type, &tag)) return -1; |
| if (tag == SymTagBaseType) { |
| ContextAddress size = 0; |
| int type_class = 0; |
| unsigned char sign = 0; |
| unsigned char real = 0; |
| const TypeInfo * p = basic_type_info; |
| if (get_symbol_size(&type, &size)) return -1; |
| if (get_symbol_type_class(&type, &type_class)) return -1; |
| if (type_class == TYPE_CLASS_INTEGER) sign = 1; |
| else if (type_class == TYPE_CLASS_REAL) real = sign = 1; |
| while (p->name != NULL) { |
| if (p->size == size && p->sign == sign && p->real == real) { |
| *name = p->name; |
| break; |
| } |
| p++; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| int get_symbol_size(const Symbol * sym, ContextAddress * size) { |
| uint64_t res = 0; |
| DWORD tag = 0; |
| |
| assert(sym->magic == SYMBOL_MAGIC); |
| if (sym->base) { |
| if (sym->length > 0) { |
| if (get_symbol_size(sym->base, size)) return -1; |
| *size *= sym->length; |
| } |
| else { |
| *size = sizeof(void *); |
| } |
| return 0; |
| } |
| if (sym->info) { |
| *size = sym->info->size; |
| return 0; |
| } |
| if (sym->module == 0) { |
| set_errno(ERR_OTHER, "Debug info not available"); |
| return -1; |
| } |
| if (sym->sym_class == SYM_CLASS_REFERENCE || sym->sym_class == SYM_CLASS_FUNCTION) { |
| SYMBOL_INFO * info = NULL; |
| if (get_sym_info(sym, sym->index, &info) < 0) return -1; |
| res = info->Size; |
| } |
| else { |
| Symbol type = *sym; |
| if (get_type_tag(&type, &tag)) return -1; |
| if (get_type_info(&type, TI_GET_LENGTH, &res) < 0) return -1; |
| } |
| |
| *size = (ContextAddress)res; |
| return 0; |
| } |
| |
| int get_symbol_type(const Symbol * sym, Symbol ** type) { |
| assert(sym->magic == SYMBOL_MAGIC); |
| if (sym->address) { |
| *type = NULL; |
| return 0; |
| } |
| if (!sym->base && !sym->info) { |
| DWORD tag = 0; |
| DWORD index = 0; |
| Symbol * res = alloc_symbol(); |
| *res = *sym; |
| if (get_type_info(sym, TI_GET_SYMTAG, &tag) < 0) return -1; |
| switch (tag) { |
| case SymTagTypedef: |
| case SymTagFunction: |
| case SymTagPublicSymbol: |
| case SymTagData: |
| case SymTagFunctionArgType: |
| if (get_type_info(sym, TI_GET_TYPE, &index) < 0) return -1; |
| res->sym_class = SYM_CLASS_TYPE; |
| res->index = index; |
| *type = res; |
| return 0; |
| } |
| assert(sym->sym_class == SYM_CLASS_TYPE); |
| } |
| *type = (Symbol *)sym; |
| return 0; |
| } |
| |
| int get_symbol_base_type(const Symbol * sym, Symbol ** type) { |
| DWORD tag = 0; |
| DWORD index = 0; |
| Symbol * res = NULL; |
| |
| assert(sym->magic == SYMBOL_MAGIC); |
| if (sym->base) { |
| *type = (Symbol *)sym->base; |
| return 0; |
| } |
| if (sym->info) { |
| errno = ERR_INV_CONTEXT; |
| return -1; |
| } |
| res = alloc_symbol(); |
| *res = *sym; |
| if (get_type_tag(res, &tag)) return -1; |
| if (get_type_info(res, TI_GET_TYPE, &index) < 0) return -1; |
| res->index = index; |
| *type = res; |
| return 0; |
| } |
| |
| int get_symbol_index_type(const Symbol * sym, Symbol ** type) { |
| DWORD tag = 0; |
| DWORD index = 0; |
| Symbol * res = alloc_symbol(); |
| |
| assert(sym->magic == SYMBOL_MAGIC); |
| if (sym->base && sym->length) { |
| res->ctx = sym->ctx; |
| res->sym_class = SYM_CLASS_TYPE; |
| res->info = basic_type_info + BST_UNSIGNED; |
| assert(res->info->size == sizeof(int)); |
| assert(res->info->sign == 0); |
| assert(res->info->real == 0); |
| *type = res; |
| return 0; |
| } |
| if (sym->base || sym->info) { |
| errno = ERR_INV_CONTEXT; |
| return -1; |
| } |
| *res = *sym; |
| if (get_type_tag(res, &tag)) return -1; |
| if (get_type_info(res, TI_GET_ARRAYINDEXTYPEID, &index) < 0) return -1; |
| res->index = index; |
| *type = res; |
| return 0; |
| } |
| |
| int get_symbol_container(const Symbol * sym, Symbol ** container) { |
| errno = ERR_UNSUPPORTED; |
| return -1; |
| } |
| |
| int get_symbol_length(const Symbol * sym, ContextAddress * length) { |
| DWORD res = 0; |
| Symbol type = *sym; |
| DWORD tag = 0; |
| |
| assert(sym->magic == SYMBOL_MAGIC); |
| if (sym->base && sym->length) { |
| *length = sym->length; |
| return 0; |
| } |
| if (sym->base || sym->info) { |
| errno = ERR_INV_CONTEXT; |
| return -1; |
| } |
| if (get_type_tag(&type, &tag)) return -1; |
| switch (tag) { |
| case SymTagArrayType: |
| if (get_type_info(&type, TI_GET_COUNT, &res) < 0) return -1; |
| *length = res; |
| return 0; |
| } |
| errno = ERR_INV_CONTEXT; |
| return -1; |
| } |
| |
| int get_symbol_lower_bound(const Symbol * sym, int64_t * value) { |
| Symbol type = *sym; |
| DWORD tag = 0; |
| |
| assert(sym->magic == SYMBOL_MAGIC); |
| if (sym->base && sym->length) { |
| *value = 0; |
| return 0; |
| } |
| if (sym->base || sym->info) { |
| errno = ERR_INV_CONTEXT; |
| return -1; |
| } |
| if (get_type_tag(&type, &tag)) return -1; |
| switch (tag) { |
| case SymTagArrayType: |
| /* TODO: Windows array symbol lower bound value */ |
| *value = 0; |
| return 0; |
| } |
| errno = ERR_INV_CONTEXT; |
| return -1; |
| } |
| |
| int get_symbol_children(const Symbol * sym, Symbol *** children, int * count) { |
| |
| static const DWORD FINDCHILDREN_BUF_SIZE = 64; |
| static TI_FINDCHILDREN_PARAMS * params = NULL; |
| Symbol ** buf = NULL; |
| |
| DWORD cnt = 0; |
| Symbol type = *sym; |
| DWORD tag = 0; |
| |
| assert(sym->magic == SYMBOL_MAGIC); |
| if (sym->base || sym->info) { |
| *children = NULL; |
| *count = 0; |
| return 0; |
| } |
| if (get_type_tag(&type, &tag)) return -1; |
| if (get_type_info(&type, TI_GET_CHILDRENCOUNT, &cnt) < 0) return -1; |
| if (params == NULL) params = (TI_FINDCHILDREN_PARAMS *)loc_alloc( |
| sizeof(TI_FINDCHILDREN_PARAMS) + (FINDCHILDREN_BUF_SIZE - 1) * sizeof(ULONG)); |
| |
| buf = (Symbol **)tmp_alloc(sizeof(Symbol *) * cnt); |
| |
| params->Start = 0; |
| while (params->Start < cnt) { |
| DWORD i = cnt - (DWORD)params->Start; |
| params->Count = i > FINDCHILDREN_BUF_SIZE ? FINDCHILDREN_BUF_SIZE : i; |
| if (get_type_info(&type, TI_FINDCHILDREN, params) < 0) return -1; |
| for (i = 0; params->Start < cnt; i++) { |
| DWORD dword = 0; |
| Symbol * x = alloc_symbol(); |
| *x = *sym; |
| x->index = params->ChildId[i]; |
| if (get_type_info(x, TI_GET_SYMTAG, &dword) < 0) return -1; |
| tag2symclass(x, dword); |
| buf[params->Start++] = x; |
| } |
| } |
| |
| *children = buf; |
| *count = cnt; |
| return 0; |
| } |
| |
| static RegisterDefinition * find_register(Context * ctx, const char * name) { |
| RegisterDefinition * defs = get_reg_definitions(ctx); |
| if (defs == NULL) return NULL; |
| while (defs->name != NULL) { |
| if (strcasecmp(defs->name, name) == 0) return defs; |
| defs++; |
| } |
| return NULL; |
| } |
| |
| int get_symbol_flags(const Symbol * sym, SYM_FLAGS * flags) { |
| DWORD tag = 0; |
| DWORD dword = 0; |
| SYMBOL_INFO * info = NULL; |
| |
| *flags = 0; |
| assert(sym->magic == SYMBOL_MAGIC); |
| if (sym->address || sym->base || sym->info) return 0; |
| if (get_type_info(sym, TI_GET_SYMTAG, &tag) < 0) return -1; |
| if (get_sym_info(sym, sym->index, &info) == 0 && (info->Flags & SYMFLAG_PARAMETER) != 0) *flags |= SYM_FLAG_PARAMETER; |
| if (get_type_info(sym, TI_GET_IS_REFERENCE, &dword) == 0 && dword) *flags |= SYM_FLAG_REFERENCE; |
| if (tag == SymTagFunctionArgType) *flags |= SYM_FLAG_PARAMETER; |
| if (tag == SymTagPublicSymbol) *flags |= SYM_FLAG_EXTERNAL; |
| if (tag == SymTagTypedef) *flags |= SYM_FLAG_TYPEDEF; |
| if (tag == SymTagEnum) *flags |= SYM_FLAG_ENUM_TYPE; |
| |
| return 0; |
| } |
| |
| int get_symbol_props(const Symbol * sym, SymbolProperties * props) { |
| memset(props, 0, sizeof(SymbolProperties)); |
| return 0; |
| } |
| |
| int get_symbol_frame(const Symbol * sym, Context ** ctx, int * frame) { |
| int n = sym->frame + STACK_NO_FRAME; |
| if (n == STACK_TOP_FRAME) { |
| n = get_top_frame(sym->ctx); |
| if (n < 0) return -1; |
| } |
| *ctx = sym->ctx; |
| *frame = n; |
| return 0; |
| } |
| |
| int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** ptr) { |
| assert(sym->magic == SYMBOL_MAGIC); |
| *ptr = alloc_symbol(); |
| (*ptr)->ctx = sym->ctx; |
| (*ptr)->sym_class = SYM_CLASS_TYPE; |
| (*ptr)->base = (Symbol *)sym; |
| (*ptr)->length = length; |
| return 0; |
| } |
| |
| static unsigned symbol_hash(ULONG64 pc, PCSTR name) { |
| int i; |
| unsigned h = (unsigned)(uintptr_t)pc; |
| for (i = 0; name[i]; i++) h += name[i]; |
| h = h + h / SYMBOL_CACHE_SIZE; |
| return h % SYMBOL_CACHE_SIZE; |
| } |
| |
| static int find_cache_symbol(Context * ctx, int frame, ULONG64 pc, PCSTR name, Symbol * sym) { |
| ContextExtensionWinSym * ext = EXT(ctx->mem); |
| if (ext->symbol_cache != NULL) { |
| int cnt = 0; |
| SymbolCacheEntry * entry = ext->symbol_cache[symbol_hash(pc, name)]; |
| while (entry != NULL) { |
| if (entry->pc == pc && strcmp(entry->name, name) == 0) { |
| if (entry->error == NULL) { |
| if (entry->frame_relative) { |
| assert(frame >= 0); |
| sym->frame = frame - STACK_NO_FRAME; |
| } |
| else { |
| ctx = ctx->mem; |
| } |
| sym->ctx = ctx; |
| sym->sym_class = entry->sym_class; |
| sym->module = entry->module; |
| sym->index = entry->index; |
| } |
| set_error_report_errno(entry->error); |
| return 1; |
| } |
| else if (cnt > 32) { |
| while (entry->next) { |
| SymbolCacheEntry * next = entry->next; |
| entry->next = next->next; |
| release_error_report(next->error); |
| loc_free(next); |
| } |
| return 0; |
| } |
| entry = entry->next; |
| cnt++; |
| } |
| } |
| return 0; |
| } |
| |
| static void add_cache_symbol(Context * ctx, ULONG64 pc, PCSTR name, Symbol * sym, int error) { |
| unsigned h = symbol_hash(pc, name); |
| ContextExtensionWinSym * ext = EXT(ctx->mem); |
| SymbolCacheEntry * entry = (SymbolCacheEntry *)loc_alloc_zero(sizeof(SymbolCacheEntry)); |
| assert(!ctx->mem->exited); |
| entry->pc = pc; |
| strcpy(entry->name, name); |
| entry->error = get_error_report(error); |
| if (!error) { |
| entry->frame_relative = sym->frame > 0; |
| entry->sym_class = sym->sym_class; |
| entry->module = sym->module; |
| entry->index = sym->index; |
| } |
| if (ext->symbol_cache == NULL) ext->symbol_cache = (SymbolCacheEntry **)loc_alloc_zero(sizeof(SymbolCacheEntry *) * SYMBOL_CACHE_SIZE); |
| entry->next = ext->symbol_cache[h]; |
| ext->symbol_cache[h] = entry; |
| } |
| |
| static int set_pe_context(Context * ctx, int frame, ContextAddress ip, HANDLE process, IMAGEHLP_STACK_FRAME * stack_frame) { |
| if (get_stack_frame(ctx, frame, ip, stack_frame) < 0) return -1; |
| |
| if (!SymSetContext(process, stack_frame, NULL)) { |
| DWORD err = GetLastError(); |
| if (err == ERROR_SUCCESS) { |
| /* Don't know why Windows do this */ |
| } |
| else if (err == ERROR_MOD_NOT_FOUND && frame != STACK_NO_FRAME) { |
| /* No local symbols data, search global scope */ |
| if (get_stack_frame(ctx, STACK_NO_FRAME, 0, stack_frame) < 0) return -1; |
| if (!SymSetContext(process, stack_frame, NULL)) { |
| err = GetLastError(); |
| if (err != ERROR_SUCCESS) { |
| set_win32_errno(err); |
| return -1; |
| } |
| } |
| } |
| else if (err == ERROR_NOT_SUPPORTED) { |
| /* Compiled without debug info */ |
| errno = ERR_SYM_NOT_FOUND; |
| return -1; |
| } |
| else { |
| set_win32_errno(err); |
| return -1; |
| } |
| } |
| return 0; |
| } |
| |
| static int find_pe_symbol_by_name(Context * ctx, int frame, ContextAddress ip, const char * name, Symbol * sym) { |
| HANDLE process = get_context_handle(context_get_group(ctx, CONTEXT_GROUP_PROCESS)); |
| ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; |
| SYMBOL_INFO * info = (SYMBOL_INFO *)buffer; |
| IMAGEHLP_STACK_FRAME stack_frame; |
| DWORD err; |
| |
| if (set_pe_context(ctx, frame, ip, process, &stack_frame) < 0) return -1; |
| |
| memset(info, 0, sizeof(SYMBOL_INFO)); |
| info->SizeOfStruct = sizeof(SYMBOL_INFO); |
| info->MaxNameLen = MAX_SYM_NAME; |
| |
| if (find_cache_symbol(ctx, frame, stack_frame.InstructionOffset, name, sym)) return errno ? -1 : 0; |
| |
| /* TODO: SymFromName() searches only main executable, need to search DLLs too */ |
| SetLastError(0); |
| if (SymFromName(process, name, info) && info->Tag != SymTagPublicSymbol) { |
| if (syminfo2symbol(ctx, frame, info, sym)) { |
| add_cache_symbol(ctx, stack_frame.InstructionOffset, name, sym, 0); |
| return 0; |
| } |
| } |
| if (stack_frame.InstructionOffset != 0) { |
| DWORD64 module = SymGetModuleBase64(process, stack_frame.InstructionOffset); |
| if (module != 0 && SymGetTypeFromName(process, module, name, info)) { |
| if (syminfo2symbol(ctx, frame, info, sym)) { |
| add_cache_symbol(ctx, stack_frame.InstructionOffset, name, sym, 0); |
| return 0; |
| } |
| } |
| } |
| set_win32_errno(err = GetLastError()); |
| if (err == 0 || err == ERROR_MOD_NOT_FOUND) { |
| add_cache_symbol(ctx, stack_frame.InstructionOffset, name, NULL, ERR_SYM_NOT_FOUND); |
| errno = ERR_SYM_NOT_FOUND; |
| } |
| return -1; |
| } |
| |
| static int find_pe_symbol_by_addr(Context * ctx, int frame, ContextAddress addr, Symbol * sym) { |
| HANDLE process = get_context_handle(context_get_group(ctx, CONTEXT_GROUP_PROCESS)); |
| ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; |
| SYMBOL_INFO * info = (SYMBOL_INFO *)buffer; |
| IMAGEHLP_STACK_FRAME stack_frame; |
| DWORD err; |
| |
| if (set_pe_context(ctx, frame, 0, process, &stack_frame) < 0) return -1; |
| |
| memset(info, 0, sizeof(SYMBOL_INFO)); |
| info->SizeOfStruct = sizeof(SYMBOL_INFO); |
| info->MaxNameLen = MAX_SYM_NAME; |
| |
| SetLastError(0); |
| if (SymFromAddr(process, addr, NULL, info)) { |
| if (syminfo2symbol(ctx, frame, info, sym)) return 0; |
| } |
| |
| set_win32_errno(err = GetLastError()); |
| if (err == 0 || err == ERROR_MOD_NOT_FOUND || err == ERROR_INVALID_ADDRESS) { |
| errno = ERR_SYM_NOT_FOUND; |
| } |
| return -1; |
| } |
| |
| static int find_basic_type_symbol(Context * ctx, const char * name, Symbol * sym) { |
| const TypeInfo * p = basic_type_info; |
| while (p->name != NULL) { |
| if (strcmp(p->name, name) == 0) { |
| sym->ctx = ctx->mem; |
| sym->sym_class = SYM_CLASS_TYPE; |
| sym->info = p; |
| return 0; |
| } |
| p++; |
| } |
| errno = ERR_SYM_NOT_FOUND; |
| return -1; |
| } |
| |
| int find_symbol_by_name(Context * ctx, int frame, ContextAddress ip, const char * name, Symbol ** sym) { |
| int found = 0; |
| |
| *sym = alloc_symbol(); |
| (*sym)->ctx = ctx; |
| if (frame == STACK_TOP_FRAME && (frame = get_top_frame(ctx)) < 0) return -1; |
| if (find_pe_symbol_by_name(ctx, frame, ip, name, *sym) >= 0) found = 1; |
| else if (get_error_code(errno) != ERR_SYM_NOT_FOUND) return -1; |
| if (!found) { |
| if (find_basic_type_symbol(ctx, name, *sym) >= 0) found = 1; |
| else if (get_error_code(errno) != ERR_SYM_NOT_FOUND) return -1; |
| } |
| if (!found) { |
| errno = ERR_SYM_NOT_FOUND; |
| return -1; |
| } |
| assert(frame >= 0 || (*sym)->ctx == ctx->mem); |
| assert((*sym)->ctx == ((*sym)->frame ? ctx : ctx->mem)); |
| assert((*sym)->frame == ((*sym)->ctx == (*sym)->ctx->mem ? 0u : frame - STACK_NO_FRAME)); |
| return 0; |
| } |
| |
| typedef struct FSISEnumerateSymbolsContext { |
| Context * ctx; |
| int frame; |
| const char * name; |
| Symbol * sym; |
| unsigned cnt; |
| } FSISEnumerateSymbolsContext; |
| |
| static BOOL CALLBACK fsis_enumerate_symbols(SYMBOL_INFO * info, ULONG symbol_size, VOID * user_context) { |
| FSISEnumerateSymbolsContext * enum_context = (FSISEnumerateSymbolsContext *)user_context; |
| if (strcmp(enum_context->name, info->Name) == 0) { |
| Symbol * sym = alloc_symbol(); |
| if (syminfo2symbol(enum_context->ctx, enum_context->frame, info, sym)) { |
| enum_context->sym = sym; |
| enum_context->cnt++; |
| } |
| } |
| return TRUE; |
| } |
| |
| int find_symbol_in_scope(Context * ctx, int frame, ContextAddress ip, Symbol * scope, const char * name, Symbol ** sym) { |
| ContextAddress scope_addr = 0; |
| Symbol ** buf = NULL; |
| int cnt = 0; |
| int i; |
| |
| if (scope == NULL) return find_symbol_by_name(ctx, frame, ip, name, sym); |
| |
| if (get_symbol_children(scope, &buf, &cnt) < 0) return -1; |
| for (i = 0; i < cnt; i++) { |
| char * s = NULL; |
| if (get_symbol_name(buf[i], &s) < 0) return -1; |
| if (s != NULL && strcmp(s, name) == 0) { |
| *sym = buf[i]; |
| return 0; |
| } |
| } |
| |
| if (get_symbol_address(scope, &scope_addr) == 0) { |
| ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; |
| HANDLE process = get_context_handle(context_get_group(ctx, CONTEXT_GROUP_PROCESS)); |
| SYMBOL_INFO * symbol = (SYMBOL_INFO *)buffer; |
| IMAGEHLP_STACK_FRAME stack_frame; |
| FSISEnumerateSymbolsContext enum_context; |
| |
| symbol->SizeOfStruct = sizeof(SYMBOL_INFO); |
| symbol->MaxNameLen = MAX_SYM_NAME; |
| |
| memset(&stack_frame, 0, sizeof(IMAGEHLP_STACK_FRAME)); |
| stack_frame.InstructionOffset = scope_addr; |
| |
| if (!SymSetContext(process, &stack_frame, NULL)) { |
| DWORD err = GetLastError(); |
| if (err == ERROR_SUCCESS) { |
| /* Don't know why Windows do this */ |
| } |
| else { |
| set_win32_errno(err); |
| return -1; |
| } |
| } |
| |
| memset(&enum_context, 0, sizeof(FSISEnumerateSymbolsContext)); |
| enum_context.ctx = ctx; |
| enum_context.frame = frame; |
| enum_context.name = name; |
| |
| if (!SymEnumSymbols(process, 0, NULL, fsis_enumerate_symbols, &enum_context)) { |
| set_win32_errno(GetLastError()); |
| return -1; |
| } |
| |
| if (enum_context.cnt == 1) { |
| *sym = enum_context.sym; |
| return 0; |
| } |
| } |
| |
| errno = ERR_SYM_NOT_FOUND; |
| return -1; |
| } |
| |
| int find_symbol_by_addr(Context * ctx, int frame, ContextAddress addr, Symbol ** sym) { |
| *sym = alloc_symbol(); |
| (*sym)->ctx = ctx; |
| if (frame == STACK_TOP_FRAME && (frame = get_top_frame(ctx)) < 0) return -1; |
| if (find_pe_symbol_by_addr(ctx, frame, addr, *sym) < 0) return -1; |
| assert(frame >= 0 || (*sym)->ctx == ctx->mem); |
| assert((*sym)->ctx == ((*sym)->frame ? ctx : ctx->mem)); |
| assert((*sym)->frame == ((*sym)->ctx == (*sym)->ctx->mem ? 0u : frame - STACK_NO_FRAME)); |
| return 0; |
| } |
| |
| int find_next_symbol(Symbol ** sym) { |
| /* TODO: find_next_symbol() for Windows */ |
| errno = ERR_SYM_NOT_FOUND; |
| return -1; |
| } |
| |
| typedef struct EnumerateSymbolsContext { |
| Context * ctx; |
| int frame; |
| EnumerateSymbolsCallBack * call_back; |
| void * args; |
| } EnumerateSymbolsContext; |
| |
| static BOOL CALLBACK enumerate_symbols_proc(SYMBOL_INFO * info, ULONG symbol_size, VOID * user_context) { |
| EnumerateSymbolsContext * enum_context = (EnumerateSymbolsContext *)user_context; |
| Symbol * sym = alloc_symbol(); |
| if (syminfo2symbol(enum_context->ctx, enum_context->frame, info, sym)) { |
| enum_context->call_back(enum_context->args, sym); |
| } |
| return TRUE; |
| } |
| |
| int enumerate_symbols(Context * ctx, int frame, EnumerateSymbolsCallBack * call_back, void * args) { |
| ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; |
| SYMBOL_INFO * symbol = (SYMBOL_INFO *)buffer; |
| IMAGEHLP_STACK_FRAME stack_frame; |
| EnumerateSymbolsContext enum_context; |
| HANDLE process = get_context_handle(context_get_group(ctx, CONTEXT_GROUP_PROCESS)); |
| |
| symbol->SizeOfStruct = sizeof(SYMBOL_INFO); |
| symbol->MaxNameLen = MAX_SYM_NAME; |
| |
| if (frame == STACK_TOP_FRAME) frame = get_top_frame(ctx); |
| if (frame == STACK_TOP_FRAME) return -1; |
| if (get_stack_frame(ctx, frame, 0, &stack_frame) < 0) return -1; |
| |
| if (!SymSetContext(process, &stack_frame, NULL)) { |
| DWORD err = GetLastError(); |
| if (err == ERROR_SUCCESS) { |
| /* Don't know why Windows do this */ |
| } |
| else { |
| set_win32_errno(err); |
| return -1; |
| } |
| } |
| |
| enum_context.ctx = ctx; |
| enum_context.frame = frame; |
| enum_context.call_back = call_back; |
| enum_context.args = args; |
| |
| if (!SymEnumSymbols(process, 0, NULL, enumerate_symbols_proc, &enum_context)) { |
| set_win32_errno(GetLastError()); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| ContextAddress is_plt_section(Context * ctx, ContextAddress addr) { |
| errno = 0; |
| return 0; |
| } |
| |
| int get_context_isa(Context * ctx, ContextAddress addr, const char ** isa, |
| ContextAddress * range_addr, ContextAddress * range_size) { |
| *isa = NULL; |
| *range_addr = addr; |
| *range_size = 1; |
| return 0; |
| } |
| |
| static LocationExpressionCommand * add_location_command(int op) { |
| LocationExpressionCommand * cmd = NULL; |
| if (location_cmds->cnt >= location_cmds->max) { |
| location_cmds->max += 4; |
| location_cmds->cmds = (LocationExpressionCommand *)tmp_realloc(location_cmds->cmds, |
| sizeof(LocationExpressionCommand) * location_cmds->max); |
| } |
| cmd = location_cmds->cmds + location_cmds->cnt++; |
| memset(cmd, 0, sizeof(LocationExpressionCommand)); |
| cmd->cmd = op; |
| return cmd; |
| } |
| |
| int get_location_info(const Symbol * sym, LocationInfo ** loc) { |
| DWORD dword = 0; |
| static VARIANT data; |
| SYMBOL_INFO * info = NULL; |
| |
| assert(sym->magic == SYMBOL_MAGIC); |
| *loc = (LocationInfo *)tmp_alloc_zero(sizeof(LocationInfo)); |
| location_cmds = &(*loc)->value_cmds; |
| |
| if (sym->address != 0) { |
| add_location_command(SFT_CMD_NUMBER)->args.num = sym->address; |
| return 0; |
| } |
| |
| if (sym->base || sym->info) { |
| errno = ERR_INV_CONTEXT; |
| return -1; |
| } |
| |
| if (get_sym_info(sym, sym->index, &info) < 0) return -1; |
| |
| if (is_frame_relative(info)) { |
| add_location_command(SFT_CMD_FP); |
| add_location_command(SFT_CMD_NUMBER)->args.num = |
| info->Address - context_word_size(sym->ctx) * 2; |
| add_location_command(SFT_CMD_ADD); |
| return 0; |
| } |
| |
| if (is_register(info)) { |
| RegisterDefinition * def = NULL; |
| /* Register numbers are defined in cvconst.h */ |
| if (info->Register < 40) { |
| static const char * reg_names[] = { |
| NULL, "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH", "AX", |
| "CX", "DX", "BX", "SP", "BP", "SI", "DI", "EAX", "ECX", "EDX", |
| "EBX", "ESP", "EBP", "ESI", "EDI", "ES", "CS", "SS", "DS", "FS", |
| "GS", "IP", "FLAGS", "EIP", "EFLAGS", NULL, NULL, NULL, NULL, NULL, |
| }; |
| def = find_register(sym->ctx, reg_names[info->Register]); |
| } |
| else if (info->Register >= 328 && info->Register <= 343) { |
| static const char * reg_names[] = { |
| "RAX", "RBX", "RCX", "RDX", "RSI", "RDI", "RBP", "RSP", |
| "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15" |
| }; |
| def = find_register(sym->ctx, reg_names[info->Register - 328]); |
| } |
| if (def != NULL) { |
| LocationExpressionCommand * cmd = add_location_command(SFT_CMD_PIECE); |
| cmd->args.piece.reg = def; |
| cmd->args.piece.bit_size = def->size * 8; |
| return 0; |
| } |
| set_errno(ERR_OTHER, "Unknown register index"); |
| return -1; |
| } |
| |
| if (get_type_info(sym, TI_GET_OFFSET, &dword) == 0) { |
| DWORD bit = 0; |
| add_location_command(SFT_CMD_ARG)->args.arg_no = 0; |
| add_location_command(SFT_CMD_NUMBER)->args.num = dword; |
| add_location_command(SFT_CMD_ADD); |
| if (get_type_info(sym, TI_GET_BITPOSITION, &bit) == 0) { |
| LocationExpressionCommand * cmd = add_location_command(SFT_CMD_PIECE); |
| cmd->args.piece.bit_offs = bit; |
| cmd->args.piece.bit_size = info->Size; |
| } |
| (*loc)->args_cnt = 1; |
| return 0; |
| } |
| |
| if (get_type_info(sym, TI_GET_VALUE, &data) == 0) { |
| VARTYPE vt; |
| void * data_addr = &data.bVal; |
| size_t data_size = 0; |
| LocationExpressionCommand * cmd = NULL; |
| |
| assert(data_addr == &data.lVal); |
| |
| vt = data.vt; |
| if (vt & VT_BYREF) { |
| data_addr = *(void **)data_addr; |
| vt &= ~VT_BYREF; |
| } |
| |
| switch (vt) { |
| /* VOID */ case 0: break; |
| /* CHAR */ case VT_I1: data_size = 1; break; |
| /* SHORT */ case VT_I2: data_size = 2; break; |
| /* LONG */ case VT_I4: data_size = 4; break; |
| /* LONGLONG */ case VT_I8: data_size = 8; break; |
| /* INT */ case VT_INT: data_size = sizeof(int); break; |
| /* BYTE */ case VT_UI1: data_size = 1; break; |
| /* USHORT */ case VT_UI2: data_size = 2; break; |
| /* ULONG */ case VT_UI4: data_size = 4; break; |
| /* ULONGLONG */ case VT_UI8: data_size = 8; break; |
| /* UINT */ case VT_UINT: data_size = sizeof(unsigned int); break; |
| /* FLOAT */ case VT_R4: data_size = 4; break; |
| /* DOUBLE */ case VT_R8: data_size = 8; break; |
| /* VARIANT_BOOL */ case VT_BOOL: data_size = sizeof(BOOL); break; |
| /* SCODE */ case VT_ERROR: data_size = sizeof(ERROR); break; |
| /* CY */ case VT_CY: data_size = sizeof(CY); break; |
| /* DATE */ case VT_DATE: data_size = sizeof(DATE); break; |
| /* BSTR */ case VT_BSTR: data_size = sizeof(BSTR); break; |
| /* IUnknown * */ case VT_UNKNOWN: data_size = sizeof(IUnknown *); break; |
| /* IDispatch * */ case VT_DISPATCH: data_size = sizeof(IDispatch *); break; |
| /* SAFEARRAY * */ case VT_ARRAY: data_size = sizeof(SAFEARRAY *); break; |
| /* VARIANT */ case VT_VARIANT: data_size = sizeof(VARIANT); break; |
| /* DECIMAL */ case VT_DECIMAL: data_size = sizeof(DECIMAL); break; |
| } |
| |
| cmd = add_location_command(SFT_CMD_PIECE); |
| cmd->args.piece.bit_size = data_size * 8; |
| cmd->args.piece.value = tmp_alloc(data_size); |
| memcpy(cmd->args.piece.value, data_addr, data_size); |
| return 0; |
| } |
| |
| add_location_command(SFT_CMD_NUMBER)->args.num = info->Address; |
| return 0; |
| } |
| |
| int get_stack_tracing_info(Context * ctx, ContextAddress addr, StackTracingInfo ** info) { |
| *info = NULL; |
| return 0; |
| } |
| |
| int get_funccall_info(const Symbol * func, |
| const Symbol ** args, unsigned args_cnt, FunctionCallInfo ** res) { |
| FunctionCallInfo * info = (FunctionCallInfo *)tmp_alloc_zero(sizeof(FunctionCallInfo)); |
| Symbol * type = (Symbol *)func; |
| DWORD tag = 0; |
| DWORD cc = 0; |
| |
| assert(func->magic == SYMBOL_MAGIC); |
| if (func->base || func->info) { |
| errno = ERR_INV_CONTEXT; |
| return -1; |
| } |
| if (get_type_info(func, TI_GET_SYMTAG, &tag) < 0) return -1; |
| if (tag == SymTagFunction && get_symbol_type(func, &type) < 0) return -1; |
| if (get_type_info(type, TI_GET_CALLING_CONVENTION, &cc) < 0) return -1; |
| #if defined(__x86_64__) |
| info->scope.machine = 62; /* EM_X86_64 */ |
| info->scope.elf64 = 1; |
| #else |
| info->scope.machine = 3; /* EM_386 */ |
| #endif |
| info->scope.os_abi = (uint8_t)cc; |
| info->scope.id_type = REGNUM_DWARF; |
| info->ctx = func->ctx; |
| info->func = func; |
| info->args_cnt = args_cnt; |
| info->args = args; |
| if (get_function_call_location_expression(info) < 0) return -1; |
| *res = info; |
| return 0; |
| } |
| |
| const char * get_symbol_file_name(Context * ctx, MemoryRegion * module) { |
| IMAGEHLP_MODULE64 info; |
| HANDLE process = get_context_handle(context_get_group(ctx, CONTEXT_GROUP_PROCESS)); |
| if (module == NULL) { |
| errno = 0; |
| return NULL; |
| } |
| memset(&info, 0, sizeof(info)); |
| info.SizeOfStruct = sizeof(info); |
| if (!SymGetModuleInfo64(process, module->addr, &info)) { |
| set_win32_errno(GetLastError()); |
| return NULL; |
| } |
| errno = 0; |
| if (info.LoadedImageName[0] == 0) return NULL; |
| return tmp_strdup(info.LoadedImageName); |
| } |
| |
| static void event_context_exited(Context * ctx, void * client_data) { |
| unsigned i; |
| SymbolCacheEntry ** symbol_cache = EXT(ctx)->symbol_cache; |
| if (symbol_cache == NULL) return; |
| for (i = 0; i < SYMBOL_CACHE_SIZE; i++) { |
| while (symbol_cache[i] != NULL) { |
| SymbolCacheEntry * entry = symbol_cache[i]; |
| symbol_cache[i] = entry->next; |
| release_error_report(entry->error); |
| loc_free(entry); |
| } |
| } |
| loc_free(symbol_cache); |
| EXT(ctx)->symbol_cache = NULL; |
| } |
| |
| static void event_module_loaded(Context * ctx, void * client_data) { |
| unsigned i; |
| SymbolCacheEntry ** symbol_cache = EXT(ctx)->symbol_cache; |
| assert(ctx->mem == ctx); |
| if (symbol_cache == NULL) return; |
| for (i = 0; i < SYMBOL_CACHE_SIZE; i++) { |
| SymbolCacheEntry * prev = NULL; |
| SymbolCacheEntry * next = symbol_cache[i]; |
| while (next != NULL) { |
| SymbolCacheEntry * entry = next; |
| next = next->next; |
| if (entry->error) { |
| if (prev) prev->next = next; |
| else symbol_cache[i] = next; |
| release_error_report(entry->error); |
| loc_free(entry); |
| } |
| else { |
| prev = entry; |
| } |
| } |
| } |
| } |
| |
| static void event_module_unloaded(Context * ctx, void * client_data) { |
| unsigned i; |
| SymbolCacheEntry ** symbol_cache = EXT(ctx)->symbol_cache; |
| if (symbol_cache == NULL) return; |
| for (i = 0; i < SYMBOL_CACHE_SIZE; i++) { |
| while (symbol_cache[i] != NULL) { |
| SymbolCacheEntry * entry = symbol_cache[i]; |
| symbol_cache[i] = entry->next; |
| release_error_report(entry->error); |
| loc_free(entry); |
| } |
| } |
| } |
| |
| #if ENABLE_SymbolsMux |
| static int reader_is_valid(Context * ctx, ContextAddress addr) { |
| IMAGEHLP_MODULE64 info; |
| HANDLE process = get_context_handle(context_get_group(ctx, CONTEXT_GROUP_PROCESS)); |
| memset(&info, 0, sizeof(info)); |
| info.SizeOfStruct = sizeof(info); |
| if (!SymGetModuleInfo64(process, addr, &info)) return 0; |
| return info.LoadedImageName[0] != 0; |
| } |
| #endif |
| |
| void ini_symbols_lib(void) { |
| static ContextEventListener ctx_listener = { |
| NULL, |
| event_context_exited, |
| }; |
| static MemoryMapEventListener map_listener = { |
| event_module_loaded, |
| NULL, |
| event_module_unloaded |
| }; |
| add_context_event_listener(&ctx_listener, NULL); |
| add_memory_map_event_listener(&map_listener, NULL); |
| SymSetOptions(SymGetOptions() | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); |
| context_extension_offset = context_extension(sizeof(ContextExtensionWinSym)); |
| #if ENABLE_SymbolsMux |
| add_symbols_reader(&symbol_reader); |
| #endif |
| } |
| |
| |
| #endif /* SERVICE_Symbols && (!ENABLE_SymbolsProxy || ENABLE_LineNumbersMux) && ENABLE_PE */ |