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 that */ } 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; }
void FunctionResolver::resolveParameters(const ULONG64& functionAddress, const ULONG64& modBase, const ULONG& typeIndex, std::vector<FunctionParameter>& resolvedParameters) { IMAGEHLP_STACK_FRAME sf; sf.InstructionOffset = functionAddress; if (!SymSetContext(this->m_hProcess, &sf, 0)) { throw; } // Retrieve all parameters of this function. SymEnumSymbols(this->m_hProcess, NULL, NULL, EnumParamsCallback, &resolvedParameters); }
static BOOL stack_set_frame_internal(int newframe) { if (newframe >= dbg_curr_thread->num_frames) newframe = dbg_curr_thread->num_frames - 1; if (newframe < 0) newframe = 0; if (dbg_curr_thread->curr_frame != newframe) { IMAGEHLP_STACK_FRAME ihsf; dbg_curr_thread->curr_frame = newframe; stack_get_current_frame(&ihsf); SymSetContext(dbg_curr_process->handle, &ihsf, NULL); } return TRUE; }
static void stack_print_addr_and_args(int nf) { char buffer[sizeof(SYMBOL_INFO) + 256]; SYMBOL_INFO* si = (SYMBOL_INFO*)buffer; IMAGEHLP_STACK_FRAME ihsf; IMAGEHLP_LINE64 il; IMAGEHLP_MODULE im; DWORD64 disp64; print_bare_address(&dbg_curr_thread->frames[nf].addr_pc); stack_get_frame(nf, &ihsf); /* grab module where symbol is. If we don't have a module, we cannot print more */ im.SizeOfStruct = sizeof(im); if (!SymGetModuleInfo(dbg_curr_process->handle, ihsf.InstructionOffset, &im)) return; si->SizeOfStruct = sizeof(*si); si->MaxNameLen = 256; if (SymFromAddr(dbg_curr_process->handle, ihsf.InstructionOffset, &disp64, si)) { struct sym_enum se; DWORD disp; dbg_printf(" %s", si->Name); if (disp64) dbg_printf("+0x%lx", (DWORD_PTR)disp64); SymSetContext(dbg_curr_process->handle, &ihsf, NULL); se.first = TRUE; se.frame = ihsf.FrameOffset; dbg_printf("("); SymEnumSymbols(dbg_curr_process->handle, 0, NULL, sym_enum_cb, &se); dbg_printf(")"); il.SizeOfStruct = sizeof(il); if (SymGetLineFromAddr64(dbg_curr_process->handle, ihsf.InstructionOffset, &disp, &il)) dbg_printf(" [%s:%u]", il.FileName, il.LineNumber); dbg_printf(" in %s", im.ModuleName); } else dbg_printf(" in %s (+0x%lx)", im.ModuleName, (DWORD_PTR)(ihsf.InstructionOffset - im.BaseOfImage)); }
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(ctx->parent == NULL ? ctx : ctx->parent); 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 does that */ } 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; }
/****************************************************************** * backtrace * * Do a backtrace on the current thread */ static void backtrace(void) { unsigned cf = dbg_curr_thread->curr_frame; IMAGEHLP_STACK_FRAME ihsf; dbg_printf("Backtrace:\n"); for (dbg_curr_thread->curr_frame = 0; dbg_curr_thread->curr_frame < dbg_curr_thread->num_frames; dbg_curr_thread->curr_frame++) { dbg_printf("%s%d ", (cf == dbg_curr_thread->curr_frame ? "=>" : " "), dbg_curr_thread->curr_frame); stack_print_addr_and_args(dbg_curr_thread->curr_frame); dbg_printf(" ("); print_bare_address(&dbg_curr_thread->frames[dbg_curr_thread->curr_frame].addr_frame); dbg_printf(")\n"); } /* reset context to current stack frame */ dbg_curr_thread->curr_frame = cf; if (!dbg_curr_thread->frames) return; stack_get_frame(dbg_curr_thread->curr_frame, &ihsf); SymSetContext(dbg_curr_process->handle, &ihsf, NULL); }
HRESULT ParseImageSymbols( _In_ HMODULE hmod, _Inout_ PEXPORT_DATA pExportData) { DWORD64 dwModuleBase; ULONG i; IMAGEHLP_STACK_FRAME StackFrame; SYMINFO_EX sym; dwModuleBase = (DWORD_PTR)hmod; /* Loop through all exports */ for (i = 0; i < pExportData->cNumberOfExports; i++) { PEXPORT pExport = &pExportData->aExports[i]; ULONG64 ullFunction = dwModuleBase + pExportData->aExports[i].ulRva; ULONG64 ullDisplacement; /* Check if this is a forwarder */ if (pExport->pszForwarder != NULL) { /* Load the module and get the function address */ ullFunction = GetFunctionFromForwarder(pExport->pszForwarder); if (ullFunction == 0) { printf("Failed to get function for forwarder '%s'. Skipping.\n", pExport->pszForwarder); continue; } } RtlZeroMemory(&sym, sizeof(sym)); sym.si.SizeOfStruct = sizeof(SYMBOL_INFO); sym.si.MaxNameLen = MAX_SYMBOL_NAME; /* Try to find the symbol */ if (!SymFromAddr(ghProcess, ullFunction, &ullDisplacement, &sym.si)) { error("Error: SymFromAddr() failed."); continue; } /* Get the symbol name */ pExport->pszSymbol = _strdup(sym.si.Name); /* Check if it is a function */ if (sym.si.Tag == SymTagFunction) { /* Get the calling convention */ if (!SymGetTypeInfo(ghProcess, dwModuleBase, sym.si.TypeIndex, TI_GET_CALLING_CONVENTION, &pExport->dwCallingConvention)) { /* Fall back to __stdcall */ pExport->dwCallingConvention = CV_CALL_NEAR_STD; } /* Set the context to the function address */ RtlZeroMemory(&StackFrame, sizeof(StackFrame)); StackFrame.InstructionOffset = ullFunction; if (!SymSetContext(ghProcess, &StackFrame, NULL)) { error("SymSetContext failed for i = %u.", i); continue; } /* Enumerate all symbols for this function */ if (!SymEnumSymbols(ghProcess, 0, // use SymSetContext NULL, EnumParametersCallback, pExport)) { error("SymEnumSymbols failed for i = %u.", i); continue; } } else if (sym.si.Tag == SymTagPublicSymbol) { pExport->dwCallingConvention = CV_CALL_NEAR_STD; } else if (sym.si.Tag == SymTagData) { pExport->fData = TRUE; } } return S_OK; }
void write_stack_trace(PCONTEXT pContext, TextOutputStream& outputStream) { HANDLE m_hProcess = GetCurrentProcess(); DWORD dwMachineType = 0; CONTEXT context = *pContext; // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag if ( !SymInitialize( m_hProcess, (PSTR)environment_get_app_path(), TRUE ) ) { return; } STACKFRAME sf; memset( &sf, 0, sizeof(sf) ); #ifdef _M_IX86 // Initialize the STACKFRAME structure for the first call. This is only // necessary for Intel CPUs, and isn't mentioned in the documentation. sf.AddrPC.Offset = context.Eip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrStack.Offset = context.Esp; sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = context.Ebp; sf.AddrFrame.Mode = AddrModeFlat; dwMachineType = IMAGE_FILE_MACHINE_I386; #endif while ( 1 ) { // Get the next stack frame if ( ! StackWalk( dwMachineType, m_hProcess, GetCurrentThread(), &sf, &context, 0, SymFunctionTableAccess, SymGetModuleBase, 0 ) ) break; if ( 0 == sf.AddrFrame.Offset ) // Basic sanity check to make sure break; // the frame is OK. Bail if not. // Get the name of the function for this stack frame entry BYTE symbolBuffer[ sizeof(SYMBOL_INFO) + MAX_SYM_NAME ]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = MAX_SYM_NAME; DWORD64 symDisplacement = 0; // Displacement of the input address, // relative to the start of the symbol IMAGEHLP_MODULE module = { sizeof(IMAGEHLP_MODULE) }; if(SymGetModuleInfo(m_hProcess, sf.AddrPC.Offset, &module)) { outputStream << module.ModuleName << "!"; if ( SymFromAddr(m_hProcess, sf.AddrPC.Offset, &symDisplacement, pSymbol)) { char undecoratedName[MAX_SYM_NAME]; UnDecorateSymbolName(pSymbol->Name, undecoratedName, MAX_SYM_NAME, UNDNAME_COMPLETE); outputStream << undecoratedName; outputStream << "("; // Use SymSetContext to get just the locals/params for this frame IMAGEHLP_STACK_FRAME imagehlpStackFrame; imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset; SymSetContext( m_hProcess, &imagehlpStackFrame, 0 ); // Enumerate the locals/parameters EnumerateSymbolsContext context(sf, outputStream); SymEnumSymbols( m_hProcess, 0, 0, EnumerateSymbolsCallback, &context ); outputStream << ")"; outputStream << " + " << Offset(reinterpret_cast<void*>(symDisplacement)); // Get the source line for this stack frame entry IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) }; DWORD dwLineDisplacement; if ( SymGetLineFromAddr( m_hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo ) ) { outputStream << " " << lineInfo.FileName << " line " << Unsigned(lineInfo.LineNumber); } } else { outputStream << Address(reinterpret_cast<void*>(sf.AddrPC.Offset)); } } outputStream << "\n"; } SymCleanup(m_hProcess); return; }