First shot at implementing dbghelp.
This commit is contained in:
parent
7e301d8a77
commit
800864a050
|
@ -1510,6 +1510,7 @@ dlls/d3d8/Makefile
|
|||
dlls/d3d9/Makefile
|
||||
dlls/d3dim/Makefile
|
||||
dlls/d3dx8/Makefile
|
||||
dlls/dbghelp/Makefile
|
||||
dlls/dciman32/Makefile
|
||||
dlls/ddraw/Makefile
|
||||
dlls/ddraw/tests/Makefile
|
||||
|
|
|
@ -31,6 +31,7 @@ BASEDIRS = \
|
|||
crypt32 \
|
||||
ctl3d \
|
||||
d3dim \
|
||||
dbghelp \
|
||||
dciman32 \
|
||||
devenum \
|
||||
dinput \
|
||||
|
@ -243,6 +244,7 @@ SYMLINKS_SO = \
|
|||
crypt32.dll.so \
|
||||
ctl3d32.dll.so \
|
||||
d3dim.dll.so \
|
||||
dbghelp.dll.so \
|
||||
dciman32.dll.so \
|
||||
devenum.dll.so \
|
||||
dinput.dll.so \
|
||||
|
@ -443,6 +445,9 @@ d3dim.dll.so: d3dim/d3dim.dll.so
|
|||
d3dx8.dll.so: d3dx8/d3dx8.dll.so
|
||||
$(RM) $@ && $(LN_S) d3dx8/d3dx8.dll.so $@
|
||||
|
||||
dbghelp.dll.so: dbghelp/dbghelp.dll.so
|
||||
$(RM) $@ && $(LN_S) dbghelp/dbghelp.dll.so $@
|
||||
|
||||
dciman32.dll.so: dciman32/dciman32.dll.so
|
||||
$(RM) $@ && $(LN_S) dciman32/dciman32.dll.so $@
|
||||
|
||||
|
@ -926,6 +931,7 @@ IMPORT_LIBS = \
|
|||
libd3d9 \
|
||||
libd3dim \
|
||||
libd3dx8 \
|
||||
libdbghelp \
|
||||
libdciman32 \
|
||||
libddraw \
|
||||
libdevenum \
|
||||
|
@ -1123,6 +1129,11 @@ libd3dx8.def: d3dx8/d3dx8.spec.def
|
|||
libd3dx8.a: d3dx8/d3dx8.spec.def
|
||||
$(DLLTOOL) -k -l $@ -d d3dx8/d3dx8.spec.def
|
||||
|
||||
libdbghelp.def: dbghelp/dbghelp.spec.def
|
||||
$(RM) $@ && $(LN_S) dbghelp/dbghelp.spec.def $@
|
||||
libdbghelp.a: dbghelp/dbghelp.spec.def
|
||||
$(DLLTOOL) -k -l $@ -d dbghelp/dbghelp.spec.def
|
||||
|
||||
libdciman32.def: dciman32/dciman32.spec.def
|
||||
$(RM) $@ && $(LN_S) dciman32/dciman32.spec.def $@
|
||||
libdciman32.a: dciman32/dciman32.spec.def
|
||||
|
@ -1626,6 +1637,7 @@ d3d8/d3d8.spec.def: $(WINEBUILD)
|
|||
d3d9/d3d9.spec.def: $(WINEBUILD)
|
||||
d3dim/d3dim.spec.def: $(WINEBUILD)
|
||||
d3dx8/d3dx8.spec.def: $(WINEBUILD)
|
||||
dbghelp/dbghelp.spec.def: $(WINEBUILD)
|
||||
dciman32/dciman32.spec.def: $(WINEBUILD)
|
||||
ddraw/ddraw.spec.def: $(WINEBUILD)
|
||||
devenum/devenum.spec.def: $(WINEBUILD)
|
||||
|
@ -1747,6 +1759,7 @@ d3d8/d3d8.dll.so: d3d8
|
|||
d3d9/d3d9.dll.so: d3d9
|
||||
d3dim/d3dim.dll.so: d3dim
|
||||
d3dx8/d3dx8.dll.so: d3dx8
|
||||
dbghelp/dbghelp.dll.so: dbghelp
|
||||
dciman32/dciman32.dll.so: dciman32
|
||||
ddraw/ddraw.dll.so: ddraw
|
||||
devenum/devenum.dll.so: devenum
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Makefile
|
||||
dbghelp.dll.dbg.c
|
||||
dbghelp.spec.def
|
|
@ -0,0 +1,27 @@
|
|||
TOPSRCDIR = @top_srcdir@
|
||||
TOPOBJDIR = ../..
|
||||
SRCDIR = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
MODULE = dbghelp.dll
|
||||
IMPORTS = psapi kernel32 ntdll
|
||||
|
||||
C_SRCS = \
|
||||
dbghelp.c \
|
||||
elf_module.c \
|
||||
image.c \
|
||||
memory.c \
|
||||
minidump.c \
|
||||
module.c \
|
||||
msc.c \
|
||||
path.c \
|
||||
pe_module.c \
|
||||
source.c \
|
||||
stabs.c \
|
||||
stack.c \
|
||||
storage.c \
|
||||
symbol.c \
|
||||
type.c
|
||||
|
||||
@MAKE_DLL_RULES@
|
||||
|
||||
### Dependencies:
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* File dbghelp.c - generic routines (process) for dbghelp DLL
|
||||
*
|
||||
* Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
#include "winerror.h"
|
||||
#include "psapi.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
/* TODO
|
||||
* - support for symbols' types is still partly missing
|
||||
* + debug start/stop in functions
|
||||
* + parameters in function prototype...
|
||||
* + C++ support
|
||||
* - most options (dbghelp_options) are not used (loading lines, decoration,
|
||||
* deferring reading of module symbols, public symbols...)
|
||||
* - (un)decoration is not handled (should make winedump's code a (.a) library
|
||||
* and link it to winedump, and potentially to msvcrt and dbghelp (check best
|
||||
* way not to duplicate code in msvcrt & dbghelp)
|
||||
* - msc:
|
||||
* + handle the debug_start & debug_end information block
|
||||
* + get rid of MSC reading FIXME:s (lots of types are not defined)
|
||||
* + C++ management
|
||||
* - stabs:
|
||||
* + we should add parameters' types to the function's signature
|
||||
* while processing a function's parameters
|
||||
* + should generate the func debug_{start,end} statements (black magic ?)
|
||||
* + should identify the relay code in Wine and mark it as thunk type
|
||||
* + C++ management
|
||||
* - implement the callback notification mechanism
|
||||
*/
|
||||
|
||||
unsigned dbghelp_options = SYMOPT_UNDNAME;
|
||||
|
||||
/***********************************************************************
|
||||
* DllMain (DEBUGHLP.@)
|
||||
*/
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH: break;
|
||||
case DLL_PROCESS_DETACH: break;
|
||||
case DLL_THREAD_ATTACH: break;
|
||||
case DLL_THREAD_DETACH: break;
|
||||
default: break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static struct process* process_first /* = NULL */;
|
||||
|
||||
/******************************************************************
|
||||
* process_find_by_handle
|
||||
*
|
||||
*/
|
||||
struct process* process_find_by_handle(HANDLE hProcess)
|
||||
{
|
||||
struct process* p;
|
||||
|
||||
for (p = process_first; p && p->handle != hProcess; p = p->next);
|
||||
if (!p) SetLastError(ERROR_INVALID_HANDLE);
|
||||
return p;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymSetSearchPath (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PSTR searchPath)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
if (!searchPath) return FALSE;
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, pcs->search_path);
|
||||
pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(searchPath) + 1),
|
||||
searchPath);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymGetSearchPath (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath,
|
||||
DWORD SearchPathLength)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
if (!pcs) return FALSE;
|
||||
|
||||
strncpy(szSearchPath, pcs->search_path, SearchPathLength);
|
||||
szSearchPath[SearchPathLength - 1] = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* invade_process
|
||||
*
|
||||
* SymInitialize helper: loads in dbghelp all known (and loaded modules)
|
||||
* this assumes that hProcess is a handle on a valid process
|
||||
*/
|
||||
static BOOL process_invade(HANDLE hProcess)
|
||||
{
|
||||
HMODULE hMods[256];
|
||||
char img[256], mod[256];
|
||||
DWORD i, sz;
|
||||
MODULEINFO mi;
|
||||
|
||||
if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &sz))
|
||||
return FALSE; /* FIXME should grow hMods */
|
||||
|
||||
for (i = 0; i < sz / sizeof(HMODULE); i++)
|
||||
{
|
||||
if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
|
||||
!GetModuleFileNameExA(hProcess, hMods[i], img, sizeof(img)) ||
|
||||
!GetModuleBaseNameA(hProcess, hMods[i], mod, sizeof(mod)) ||
|
||||
!SymLoadModule(hProcess, 0, img, mod, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return sz != 0;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymInitialize (DBGHELP.@)
|
||||
*
|
||||
* The initialisation of a dbghelp's context.
|
||||
* Note that hProcess doesn't need to be a valid process handle (except
|
||||
* when fInvadeProcess is TRUE).
|
||||
* Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries
|
||||
* containing PE (and NE) module(s), here's how we handle it:
|
||||
* - we load every module (ELF, NE, PE) passed in SymLoadModule
|
||||
* - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
|
||||
* synchronization: hProcess should be a valid process handle, and we hook
|
||||
* ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
|
||||
* our internal ELF modules representation (loading / unloading). This way,
|
||||
* we'll pair every loaded builtin PE module with its ELF counterpart (and
|
||||
* access its debug information).
|
||||
* - if fInvadeProcess (in SymInitialize) is FALSE, we won't be able to
|
||||
* make the peering between a builtin PE module and its ELF counterpart, hence
|
||||
* we won't be able to provide the requested debug information. We'll
|
||||
* however be able to load native PE modules (and their debug information)
|
||||
* without any trouble.
|
||||
* Note also that this scheme can be intertwined with the deferred loading
|
||||
* mechanism (ie only load the debug information when we actually need it).
|
||||
*/
|
||||
BOOL WINAPI SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess)
|
||||
{
|
||||
struct process* pcs;
|
||||
|
||||
TRACE("(%p %s %u)\n", hProcess, debugstr_a(UserSearchPath), fInvadeProcess);
|
||||
|
||||
if (process_find_by_handle(hProcess))
|
||||
FIXME("what to do ??\n");
|
||||
|
||||
pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
|
||||
if (!pcs) return FALSE;
|
||||
|
||||
pcs->handle = hProcess;
|
||||
|
||||
if (UserSearchPath)
|
||||
{
|
||||
pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath) + 1),
|
||||
UserSearchPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned size;
|
||||
unsigned len;
|
||||
|
||||
pcs->search_path = HeapAlloc(GetProcessHeap(), 0, len = MAX_PATH);
|
||||
while ((size = GetCurrentDirectoryA(len, pcs->search_path)) >= len)
|
||||
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, len *= 2);
|
||||
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1);
|
||||
|
||||
len = GetEnvironmentVariableA("_NT_SYMBOL_PATH", NULL, 0);
|
||||
if (len)
|
||||
{
|
||||
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
|
||||
pcs->search_path[size] = ';';
|
||||
GetEnvironmentVariableA("_NT_SYMBOL_PATH", pcs->search_path + size + 1, len);
|
||||
size += 1 + len;
|
||||
}
|
||||
len = GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", NULL, 0);
|
||||
if (len)
|
||||
{
|
||||
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
|
||||
pcs->search_path[size] = ';';
|
||||
GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", pcs->search_path + size + 1, len);
|
||||
size += 1 + len;
|
||||
}
|
||||
}
|
||||
|
||||
pcs->lmodules = NULL;
|
||||
pcs->dbg_hdr_addr = 0;
|
||||
pcs->next = process_first;
|
||||
process_first = pcs;
|
||||
|
||||
if (fInvadeProcess)
|
||||
{
|
||||
pcs->dbg_hdr_addr = elf_read_wine_loader_dbg_info(pcs);
|
||||
if (pcs->dbg_hdr_addr == 0)
|
||||
{
|
||||
SymCleanup(hProcess);
|
||||
return FALSE;
|
||||
}
|
||||
process_invade(hProcess);
|
||||
elf_synchronize_module_list(pcs);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymCleanup (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymCleanup(HANDLE hProcess)
|
||||
{
|
||||
struct process** ppcs;
|
||||
struct process* next;
|
||||
|
||||
for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
|
||||
{
|
||||
if ((*ppcs)->handle == hProcess)
|
||||
{
|
||||
while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
|
||||
next = (*ppcs)->next;
|
||||
HeapFree(GetProcessHeap(), 0, *ppcs);
|
||||
*ppcs = next;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymSetOptions (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
DWORD WINAPI SymSetOptions(DWORD opts)
|
||||
{
|
||||
return dbghelp_options = opts;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymGetOptions (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
DWORD WINAPI SymGetOptions(void)
|
||||
{
|
||||
return dbghelp_options;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymSetContext (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
|
||||
PIMAGEHLP_CONTEXT Context)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
if (!pcs) return FALSE;
|
||||
|
||||
pcs->ctx_frame = *StackFrame;
|
||||
/* MSDN states that Context is not (no longer?) used */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymRegisterCallback (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
|
||||
PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
|
||||
PVOID UserContext)
|
||||
{
|
||||
FIXME("(%p, %p, %p): stub\n", hProcess, CallbackFunction, UserContext);
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* This is imagehlp version not dbghelp !! */
|
||||
static API_VERSION api_version = { 4, 0, 2, 0 };
|
||||
|
||||
/***********************************************************************
|
||||
* ImagehlpApiVersion (DBGHELP.@)
|
||||
*/
|
||||
LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
|
||||
{
|
||||
return &api_version;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* ImagehlpApiVersionEx (DBGHELP.@)
|
||||
*/
|
||||
LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
|
||||
{
|
||||
if (!AppVersion) return NULL;
|
||||
|
||||
AppVersion->MajorVersion = api_version.MajorVersion;
|
||||
AppVersion->MinorVersion = api_version.MinorVersion;
|
||||
AppVersion->Revision = api_version.Revision;
|
||||
AppVersion->Reserved = api_version.Reserved;
|
||||
|
||||
return AppVersion;
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
@ stub DbgHelpCreateUserDump
|
||||
@ stub DbgHelpCreateUserDumpW
|
||||
@ stdcall EnumerateLoadedModules(long ptr ptr)
|
||||
@ stub EnumerateLoadedModules64
|
||||
@ stub ExtensionApiVersion
|
||||
@ stdcall FindDebugInfoFile(str str ptr)
|
||||
@ stdcall FindDebugInfoFileEx(str str ptr ptr ptr)
|
||||
@ stdcall FindExecutableImage(str str str)
|
||||
@ stub FindExecutableImageEx
|
||||
@ stub FindFileInPath
|
||||
@ stub FindFileInSearchPath
|
||||
@ stdcall GetTimestampForLoadedLibrary(long)
|
||||
@ stub ImageDirectoryEntryToData
|
||||
@ stub ImageDirectoryEntryToDataEx
|
||||
@ stdcall ImageNtHeader(ptr) ntdll.RtlImageNtHeader
|
||||
@ stdcall ImageRvaToSection(ptr ptr long) ntdll.RtlImageRvaToSection
|
||||
@ stdcall ImageRvaToVa(ptr ptr long ptr) ntdll.RtlImageRvaToVa
|
||||
@ stdcall ImagehlpApiVersion()
|
||||
@ stdcall ImagehlpApiVersionEx(ptr)
|
||||
@ stdcall MakeSureDirectoryPathExists(str)
|
||||
@ stdcall MapDebugInformation(long str str long)
|
||||
@ stub MiniDumpReadDumpStream
|
||||
@ stub MiniDumpWriteDump
|
||||
@ stdcall SearchTreeForFile(str str str)
|
||||
@ stdcall StackWalk(long long long ptr ptr ptr ptr ptr ptr)
|
||||
@ stub StackWalk64
|
||||
@ stdcall SymCleanup(long)
|
||||
@ stdcall SymEnumSourceFiles(long long str ptr ptr)
|
||||
@ stub SymEnumSym
|
||||
@ stdcall SymEnumSymbols(long long str ptr ptr)
|
||||
@ stdcall SymEnumTypes(long long ptr ptr)
|
||||
@ stdcall SymEnumerateModules(long ptr ptr)
|
||||
@ stub SymEnumerateModules64
|
||||
@ stdcall SymEnumerateSymbols(long long ptr ptr)
|
||||
@ stub SymEnumerateSymbols64
|
||||
@ stub SymEnumerateSymbolsW
|
||||
@ stub SymEnumerateSymbolsW64
|
||||
@ stub SymFindFileInPath
|
||||
@ stdcall SymFromAddr(long long ptr ptr)
|
||||
@ stdcall SymFromName(long str ptr)
|
||||
@ stdcall SymFunctionTableAccess(long long)
|
||||
@ stub SymFunctionTableAccess64
|
||||
@ stub SymGetFileLineOffsets64
|
||||
@ stdcall SymGetLineFromAddr(long long ptr ptr)
|
||||
@ stub SymGetLineFromAddr64
|
||||
@ stub SymGetLineFromName
|
||||
@ stub SymGetLineFromName64
|
||||
@ stdcall SymGetLineNext(long ptr)
|
||||
@ stub SymGetLineNext64
|
||||
@ stdcall SymGetLinePrev(long ptr)
|
||||
@ stub SymGetLinePrev64
|
||||
@ stdcall SymGetModuleBase(long long)
|
||||
@ stub SymGetModuleBase64
|
||||
@ stdcall SymGetModuleInfo(long long ptr)
|
||||
@ stub SymGetModuleInfo64
|
||||
@ stub SymGetModuleInfoW
|
||||
@ stub SymGetModuleInfoW64
|
||||
@ stdcall SymGetOptions()
|
||||
@ stdcall SymGetSearchPath(long str long)
|
||||
@ stdcall SymGetSymFromAddr(long long ptr ptr)
|
||||
@ stub SymGetSymFromAddr64
|
||||
@ stdcall SymGetSymFromName(long str ptr)
|
||||
@ stub SymGetSymFromName64
|
||||
@ stdcall SymGetSymNext(long ptr)
|
||||
@ stub SymGetSymNext64
|
||||
@ stdcall SymGetSymPrev(long ptr)
|
||||
@ stub SymGetSymPrev64
|
||||
@ stdcall SymGetTypeFromName(long long str ptr)
|
||||
@ stdcall SymGetTypeInfo(long long long long ptr)
|
||||
@ stdcall SymInitialize(long str long)
|
||||
@ stdcall SymLoadModule(long long str str long long)
|
||||
@ stub SymLoadModule64
|
||||
@ stub SymLoadModuleEx
|
||||
@ stub SymMatchFileName
|
||||
@ stub SymMatchString
|
||||
@ stdcall SymRegisterCallback(long ptr ptr)
|
||||
@ stub SymRegisterCallback64
|
||||
@ stub SymRegisterFunctionEntryCallback
|
||||
@ stub SymRegisterFunctionEntryCallback64
|
||||
@ stdcall SymSetContext(long ptr ptr)
|
||||
@ stdcall SymSetOptions(long)
|
||||
@ stdcall SymSetSearchPath(long str)
|
||||
@ stub SymSetSymWithAddr64
|
||||
@ stdcall SymUnDName(ptr str long)
|
||||
@ stub SymUnDName64
|
||||
@ stdcall SymUnloadModule(long long)
|
||||
@ stub SymUnloadModule64
|
||||
@ stdcall UnDecorateSymbolName(str str long long)
|
||||
@ stdcall UnmapDebugInformation(ptr)
|
||||
@ stub WinDbgExtensionDllInit
|
||||
#@ stub dbghelp
|
||||
#@ stub dh
|
||||
#@ stub lm
|
||||
#@ stub lmi
|
||||
#@ stub omap
|
||||
#@ stub srcfiles
|
||||
#@ stub sym
|
||||
#@ stub vc7fpo
|
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
* File dbghelp_private.h - dbghelp internal definitions
|
||||
*
|
||||
* Copyright (C) 1995, Alexandre Julliard
|
||||
* Copyright (C) 1996, Eric Youngdale.
|
||||
* Copyright (C) 1999-2000, Ulrich Weigand.
|
||||
* Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winver.h"
|
||||
#include "dbghelp.h"
|
||||
|
||||
#include "cvconst.h"
|
||||
|
||||
/* #define USE_STATS */
|
||||
|
||||
struct pool /* poor's man */
|
||||
{
|
||||
struct pool_arena* first;
|
||||
unsigned arena_size;
|
||||
};
|
||||
|
||||
void pool_init(struct pool* a, unsigned arena_size);
|
||||
void pool_destroy(struct pool* a);
|
||||
void* pool_alloc(struct pool* a, unsigned len);
|
||||
/* void* pool_realloc(struct pool* a, void* p,
|
||||
unsigned old_size, unsigned new_size); */
|
||||
char* pool_strdup(struct pool* a, const char* str);
|
||||
|
||||
struct vector
|
||||
{
|
||||
void** buckets;
|
||||
unsigned elt_size : 24, shift : 8;
|
||||
unsigned num_elts : 20, num_buckets : 12;
|
||||
};
|
||||
|
||||
void vector_init(struct vector* v, unsigned elt_sz, unsigned bucket_sz);
|
||||
unsigned vector_length(const struct vector* v);
|
||||
void* vector_at(const struct vector* v, unsigned pos);
|
||||
void* vector_add(struct vector* v, struct pool* pool);
|
||||
/*void vector_pool_normalize(struct vector* v, struct pool* pool); */
|
||||
void* vector_iter_up(const struct vector* v, void* elt);
|
||||
void* vector_iter_down(const struct vector* v, void* elt);
|
||||
|
||||
struct hash_table_elt
|
||||
{
|
||||
const char* name;
|
||||
struct hash_table_elt* next;
|
||||
};
|
||||
|
||||
struct hash_table
|
||||
{
|
||||
unsigned num_buckets;
|
||||
struct hash_table_elt** buckets;
|
||||
};
|
||||
|
||||
void hash_table_init(struct pool* pool, struct hash_table* ht,
|
||||
unsigned num_buckets);
|
||||
void hash_table_destroy(struct hash_table* ht);
|
||||
void hash_table_add(struct hash_table* ht, struct hash_table_elt* elt);
|
||||
void* hash_table_find(const struct hash_table* ht, const char* name);
|
||||
unsigned hash_table_hash(const char* name, unsigned num_buckets);
|
||||
|
||||
struct hash_table_iter
|
||||
{
|
||||
const struct hash_table* ht;
|
||||
struct hash_table_elt* element;
|
||||
int index;
|
||||
int last;
|
||||
};
|
||||
|
||||
void hash_table_iter_init(const struct hash_table* ht,
|
||||
struct hash_table_iter* hti, const char* name);
|
||||
void* hash_table_iter_up(struct hash_table_iter* hti);
|
||||
|
||||
#define GET_ENTRY(__i, __t, __f) \
|
||||
((__t*)((char*)(__i) - (unsigned int)(&((__t*)0)->__f)))
|
||||
|
||||
|
||||
extern unsigned dbghelp_options;
|
||||
|
||||
struct symt
|
||||
{
|
||||
enum SymTagEnum tag;
|
||||
};
|
||||
|
||||
struct symt_ht
|
||||
{
|
||||
struct symt symt;
|
||||
struct hash_table_elt hash_elt; /* if global symbol or type */
|
||||
};
|
||||
|
||||
/* lexical tree */
|
||||
struct symt_block
|
||||
{
|
||||
struct symt symt;
|
||||
unsigned long address;
|
||||
unsigned long size;
|
||||
struct symt* container; /* block, or func */
|
||||
struct vector vchildren; /* sub-blocks & local variables */
|
||||
};
|
||||
|
||||
struct symt_compiland
|
||||
{
|
||||
struct symt symt;
|
||||
unsigned source;
|
||||
struct vector vchildren; /* global variables & functions */
|
||||
};
|
||||
|
||||
struct symt_data
|
||||
{
|
||||
struct symt symt;
|
||||
struct hash_table_elt hash_elt; /* if global symbol */
|
||||
enum DataKind kind;
|
||||
struct symt* container;
|
||||
struct symt* type;
|
||||
enum LocationType location;
|
||||
union /* depends on location */
|
||||
{
|
||||
unsigned long address; /* used by Static, Tls, ThisRel */
|
||||
int offset; /* used by RegRel */
|
||||
unsigned reg_id; /* used by Enregistered */
|
||||
struct
|
||||
{
|
||||
unsigned position;
|
||||
unsigned length;
|
||||
} bitfield; /* used by BitField */
|
||||
#if 1
|
||||
unsigned value; /* LocIsConstant */
|
||||
#else
|
||||
VARIANT value; /* LocIsConstant */
|
||||
#endif
|
||||
} u;
|
||||
};
|
||||
|
||||
struct symt_function
|
||||
{
|
||||
struct symt symt;
|
||||
struct hash_table_elt hash_elt; /* if global symbol */
|
||||
unsigned long addr;
|
||||
struct symt* container; /* compiland */
|
||||
struct symt* type; /* points to function_signature */
|
||||
unsigned long size;
|
||||
struct vector vlines;
|
||||
struct vector vchildren; /* locals, params, blocks */
|
||||
};
|
||||
|
||||
struct symt_public
|
||||
{
|
||||
struct symt symt;
|
||||
struct hash_table_elt hash_elt;
|
||||
struct symt* container; /* compiland */
|
||||
unsigned long address;
|
||||
unsigned long size;
|
||||
unsigned in_code : 1,
|
||||
is_function : 1;
|
||||
};
|
||||
|
||||
/* class tree */
|
||||
struct symt_array
|
||||
{
|
||||
struct symt symt;
|
||||
int start;
|
||||
int end;
|
||||
struct symt* basetype;
|
||||
};
|
||||
|
||||
struct symt_basic
|
||||
{
|
||||
struct symt symt;
|
||||
struct hash_table_elt hash_elt;
|
||||
enum BasicType bt;
|
||||
unsigned long size;
|
||||
};
|
||||
|
||||
struct symt_enum
|
||||
{
|
||||
struct symt symt;
|
||||
const char* name;
|
||||
struct vector vchildren;
|
||||
};
|
||||
|
||||
struct symt_function_signature
|
||||
{
|
||||
struct symt symt;
|
||||
struct symt* rettype;
|
||||
};
|
||||
|
||||
struct symt_pointer
|
||||
{
|
||||
struct symt symt;
|
||||
struct symt* pointsto;
|
||||
};
|
||||
|
||||
struct symt_typedef
|
||||
{
|
||||
struct symt symt;
|
||||
struct hash_table_elt hash_elt;
|
||||
struct symt* type;
|
||||
};
|
||||
|
||||
struct symt_udt
|
||||
{
|
||||
struct symt symt;
|
||||
struct hash_table_elt hash_elt;
|
||||
enum UdtKind kind;
|
||||
int size;
|
||||
struct vector vchildren;
|
||||
};
|
||||
|
||||
enum DbgModuleType {DMT_UNKNOWN, DMT_ELF, DMT_NE, DMT_PE};
|
||||
|
||||
struct module
|
||||
{
|
||||
IMAGEHLP_MODULE module;
|
||||
struct module* next;
|
||||
enum DbgModuleType type;
|
||||
unsigned short elf_mark : 1;
|
||||
struct tagELF_DBG_INFO* elf_dbg_info;
|
||||
|
||||
/* memory allocation pool */
|
||||
struct pool pool;
|
||||
|
||||
/* symbol tables */
|
||||
int sortlist_valid;
|
||||
struct symt_ht** addr_sorttab;
|
||||
struct hash_table ht_symbols;
|
||||
|
||||
/* types */
|
||||
struct hash_table ht_types;
|
||||
|
||||
/* source files */
|
||||
unsigned sources_used;
|
||||
unsigned sources_alloc;
|
||||
char* sources;
|
||||
};
|
||||
|
||||
struct process
|
||||
{
|
||||
struct process* next;
|
||||
HANDLE handle;
|
||||
char* search_path;
|
||||
|
||||
struct module* lmodules;
|
||||
unsigned long dbg_hdr_addr;
|
||||
|
||||
IMAGEHLP_STACK_FRAME ctx_frame;
|
||||
};
|
||||
|
||||
/* dbghelp.c */
|
||||
extern struct process* process_find_by_handle(HANDLE hProcess);
|
||||
|
||||
/* elf_module.c */
|
||||
extern SYM_TYPE elf_load_debug_info(struct module* module);
|
||||
extern struct module*
|
||||
elf_load_module(struct process* pcs, const char* name);
|
||||
extern unsigned long
|
||||
elf_read_wine_loader_dbg_info(struct process* pcs);
|
||||
extern BOOL elf_synchronize_module_list(struct process* pcs);
|
||||
|
||||
/* memory.c */
|
||||
struct memory_access
|
||||
{
|
||||
BOOL (*read_mem)(HANDLE hProcess, DWORD addr, void* buf, DWORD len);
|
||||
BOOL (*write_mem)(HANDLE hProcess, DWORD addr, void* buf, DWORD len);
|
||||
};
|
||||
|
||||
extern struct memory_access mem_access;
|
||||
#define read_mem(p,a,b,l) (mem_access.read_mem)((p),(a),(b),(l))
|
||||
#define write_mem(p,a,b,l) (mem_access.write_mem)((p),(a),(b),(l))
|
||||
extern unsigned long WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr);
|
||||
|
||||
/* module.c */
|
||||
extern struct module*
|
||||
module_find_by_addr(const struct process* pcs, unsigned long addr,
|
||||
enum DbgModuleType type);
|
||||
extern struct module*
|
||||
module_find_by_name(const struct process* pcs,
|
||||
const char* name, enum DbgModuleType type);
|
||||
extern struct module*
|
||||
module_get_debug(const struct process* pcs, struct module*);
|
||||
extern struct module*
|
||||
module_new(struct process* pcs, const char* name,
|
||||
enum DbgModuleType type, unsigned long addr,
|
||||
unsigned long size, unsigned long stamp,
|
||||
unsigned long checksum);
|
||||
|
||||
extern BOOL module_remove(struct process* pcs,
|
||||
struct module* module);
|
||||
/* msc.c */
|
||||
extern SYM_TYPE pe_load_debug_directory(const struct process* pcs,
|
||||
struct module* module,
|
||||
const BYTE* file_map,
|
||||
PIMAGE_DEBUG_DIRECTORY dbg, int nDbg);
|
||||
/* pe_module.c */
|
||||
extern struct module*
|
||||
pe_load_module(struct process* pcs, char* name,
|
||||
HANDLE hFile, DWORD base, DWORD size);
|
||||
extern struct module*
|
||||
pe_load_module_from_pcs(struct process* pcs, const char* name,
|
||||
const char* mod_name, DWORD base, DWORD size);
|
||||
extern SYM_TYPE pe_load_debug_info(const struct process* pcs,
|
||||
struct module* module);
|
||||
/* source.c */
|
||||
extern unsigned source_new(struct module* module, const char* source);
|
||||
extern const char* source_get(const struct module* module, unsigned idx);
|
||||
|
||||
/* stabs.c */
|
||||
extern SYM_TYPE stabs_parse(struct module* module, const char* addr,
|
||||
unsigned long load_offset,
|
||||
unsigned int staboff, int stablen,
|
||||
unsigned int strtaboff, int strtablen);
|
||||
|
||||
/* symbol.c */
|
||||
extern const char* symt_get_name(const struct symt* sym);
|
||||
extern int symt_cmp_addr(const void* p1, const void* p2);
|
||||
extern struct symt_compiland*
|
||||
symt_new_compiland(struct module* module,
|
||||
const char* filename);
|
||||
extern struct symt_public*
|
||||
symt_new_public(struct module* module,
|
||||
struct symt_compiland* parent,
|
||||
const char* typename,
|
||||
unsigned long address, unsigned size,
|
||||
BOOL in_code, BOOL is_func);
|
||||
extern struct symt_data*
|
||||
symt_new_global_variable(struct module* module,
|
||||
struct symt_compiland* parent,
|
||||
const char* name, unsigned is_static,
|
||||
unsigned long addr, unsigned long size,
|
||||
struct symt* type);
|
||||
extern struct symt_function*
|
||||
symt_new_function(struct module* module,
|
||||
struct symt_compiland* parent,
|
||||
const char* name,
|
||||
unsigned long addr, unsigned long size,
|
||||
struct symt* type);
|
||||
extern BOOL symt_normalize_function(struct module* module,
|
||||
struct symt_function* func);
|
||||
extern void symt_add_func_line(struct module* module,
|
||||
struct symt_function* func,
|
||||
unsigned source_idx, int line_num,
|
||||
unsigned long offset);
|
||||
extern struct symt_data*
|
||||
symt_add_func_local(struct module* module,
|
||||
struct symt_function* func,
|
||||
int regno, int offset,
|
||||
struct symt_block* block,
|
||||
struct symt* type, const char* name);
|
||||
extern struct symt_block*
|
||||
symt_open_func_block(struct module* module,
|
||||
struct symt_function* func,
|
||||
struct symt_block* block, unsigned pc);
|
||||
extern struct symt_block*
|
||||
symt_close_func_block(struct module* module,
|
||||
struct symt_function* func,
|
||||
struct symt_block* block, unsigned pc);
|
||||
|
||||
/* type.c */
|
||||
extern void symt_init_basic(struct module* module);
|
||||
extern BOOL symt_get_info(const struct symt* type,
|
||||
IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo);
|
||||
extern struct symt_basic*
|
||||
symt_new_basic(struct module* module, enum BasicType,
|
||||
const char* typename, unsigned size);
|
||||
extern struct symt_udt*
|
||||
symt_new_udt(struct module* module, const char* typename,
|
||||
unsigned size, enum UdtKind kind);
|
||||
extern BOOL symt_set_udt_size(struct module* module,
|
||||
struct symt_udt* type, unsigned size);
|
||||
extern BOOL symt_add_udt_element(struct module* module,
|
||||
struct symt_udt* udt_type,
|
||||
const char* name,
|
||||
struct symt* elt_type, unsigned offset,
|
||||
unsigned size);
|
||||
extern struct symt_enum*
|
||||
symt_new_enum(struct module* module, const char* typename);
|
||||
extern BOOL symt_add_enum_element(struct module* module,
|
||||
struct symt_enum* enum_type,
|
||||
const char* name, unsigned value);
|
||||
extern struct symt_array*
|
||||
symt_new_array(struct module* module, int min, int max,
|
||||
struct symt* base);
|
||||
extern struct symt_function_signature*
|
||||
symt_new_function_signature(struct module* module,
|
||||
struct symt* ret_type);
|
||||
extern struct symt_pointer*
|
||||
symt_new_pointer(struct module* module,
|
||||
struct symt* ref_type);
|
|
@ -0,0 +1,638 @@
|
|||
/*
|
||||
* File elf.c - processing of ELF files
|
||||
*
|
||||
* Copyright (C) 1996, Eric Youngdale.
|
||||
* 1999-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX MAX_PATH
|
||||
#endif
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
|
||||
#if defined(__svr4__) || defined(__sun)
|
||||
#define __ELF__
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ELF_H
|
||||
# include <elf.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_ELF32_H
|
||||
# include <sys/elf32.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_EXEC_ELF_H
|
||||
# include <sys/exec_elf.h>
|
||||
#endif
|
||||
#if !defined(DT_NUM)
|
||||
# if defined(DT_COUNT)
|
||||
# define DT_NUM DT_COUNT
|
||||
# else
|
||||
/* this seems to be a satisfactory value on Solaris, which doesn't support this AFAICT */
|
||||
# define DT_NUM 24
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_LINK_H
|
||||
# include <link.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_LINK_H
|
||||
# include <sys/link.h>
|
||||
#endif
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
typedef struct tagELF_DBG_INFO
|
||||
{
|
||||
unsigned long elf_addr;
|
||||
} ELF_DBG_INFO;
|
||||
|
||||
#ifdef __ELF__
|
||||
|
||||
#define ELF_INFO_DEBUG_HEADER 0x0001
|
||||
#define ELF_INFO_MODULE 0x0002
|
||||
|
||||
struct elf_info
|
||||
{
|
||||
unsigned flags; /* IN one (or several) of the ELF_INFO constants */
|
||||
unsigned long dbg_hdr_addr; /* OUT address of debug header (if ELF_INFO_DEBUG_HEADER is set) */
|
||||
struct module* module; /* OUT loaded module (if ELF_INFO_MODULE is set) */
|
||||
};
|
||||
|
||||
/******************************************************************
|
||||
* elf_load_symtab
|
||||
*
|
||||
* Walk through the entire symbol table and add any symbols we find there.
|
||||
* This can be used in cases where we have stripped ELF shared libraries,
|
||||
* or it can be used in cases where we have data symbols for which the address
|
||||
* isn't encoded in the stabs.
|
||||
*
|
||||
* This is all really quite easy, since we don't have to worry about line
|
||||
* numbers or local data variables.
|
||||
*/
|
||||
static int elf_load_symtab(struct module* module, const char* addr,
|
||||
unsigned long load_addr, const Elf32_Shdr* symtab,
|
||||
const Elf32_Shdr* strtab)
|
||||
{
|
||||
int i, nsym;
|
||||
const char* strp;
|
||||
const char* symname;
|
||||
const Elf32_Sym* symp;
|
||||
struct symt_compiland* compiland = NULL;
|
||||
|
||||
symp = (Elf32_Sym*)(addr + symtab->sh_offset);
|
||||
nsym = symtab->sh_size / sizeof(*symp);
|
||||
strp = (char*)(addr + strtab->sh_offset);
|
||||
|
||||
for (i = 0; i < nsym; i++, symp++)
|
||||
{
|
||||
/* Ignore certain types of entries which really aren't of that much
|
||||
* interest.
|
||||
*/
|
||||
if (ELF32_ST_TYPE(symp->st_info) == STT_SECTION ||
|
||||
symp->st_shndx == SHN_UNDEF)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
symname = strp + symp->st_name;
|
||||
|
||||
if (ELF32_ST_TYPE(symp->st_info) == STT_FILE)
|
||||
{
|
||||
compiland = symt_new_compiland(module, symname);
|
||||
continue;
|
||||
}
|
||||
symt_new_public(module, compiland, symname,
|
||||
load_addr + symp->st_value, symp->st_size,
|
||||
TRUE /* FIXME */, ELF32_ST_TYPE(symp->st_info) == STT_FUNC);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* elf_load_debug_info
|
||||
*
|
||||
* Loads the symbolic information from ELF module stored in 'filename'
|
||||
* the module has been loaded at 'load_offset' address, so symbols' address
|
||||
* relocation is performed
|
||||
* returns
|
||||
* -1 if the file cannot be found/opened
|
||||
* 0 if the file doesn't contain symbolic info (or this info cannot be
|
||||
* read or parsed)
|
||||
* 1 on success
|
||||
*/
|
||||
SYM_TYPE elf_load_debug_info(struct module* module)
|
||||
{
|
||||
SYM_TYPE sym_type = -1;
|
||||
char* addr = (char*)0xffffffff;
|
||||
int fd = -1;
|
||||
struct stat statbuf;
|
||||
const Elf32_Ehdr* ehptr;
|
||||
const Elf32_Shdr* spnt;
|
||||
const char* shstrtab;
|
||||
int i;
|
||||
int stabsect, stabstrsect, debugsect;
|
||||
int symsect, dynsect;
|
||||
|
||||
if (module->type != DMT_ELF || !module->elf_dbg_info)
|
||||
{
|
||||
ERR("Bad elf module '%s'\n", module->module.LoadedImageName);
|
||||
return sym_type;
|
||||
}
|
||||
|
||||
TRACE("%s\n", module->module.LoadedImageName);
|
||||
/* check that the file exists, and that the module hasn't been loaded yet */
|
||||
if (stat(module->module.LoadedImageName, &statbuf) == -1) goto leave;
|
||||
if (S_ISDIR(statbuf.st_mode)) goto leave;
|
||||
|
||||
/*
|
||||
* Now open the file, so that we can mmap() it.
|
||||
*/
|
||||
if ((fd = open(module->module.LoadedImageName, O_RDONLY)) == -1) goto leave;
|
||||
|
||||
/*
|
||||
* Now mmap() the file.
|
||||
*/
|
||||
addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (addr == (char*)0xffffffff) goto leave;
|
||||
|
||||
sym_type = SymNone;
|
||||
/*
|
||||
* Next, we need to find a few of the internal ELF headers within
|
||||
* this thing. We need the main executable header, and the section
|
||||
* table.
|
||||
*/
|
||||
ehptr = (Elf32_Ehdr*)addr;
|
||||
spnt = (Elf32_Shdr*)(addr + ehptr->e_shoff);
|
||||
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
|
||||
|
||||
symsect = dynsect = stabsect = stabstrsect = debugsect = -1;
|
||||
|
||||
for (i = 0; i < ehptr->e_shnum; i++)
|
||||
{
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".stab") == 0)
|
||||
stabsect = i;
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".stabstr") == 0)
|
||||
stabstrsect = i;
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".debug_info") == 0)
|
||||
debugsect = i;
|
||||
if ((strcmp(shstrtab + spnt[i].sh_name, ".symtab") == 0) &&
|
||||
(spnt[i].sh_type == SHT_SYMTAB))
|
||||
symsect = i;
|
||||
if ((strcmp(shstrtab + spnt[i].sh_name, ".dynsym") == 0) &&
|
||||
(spnt[i].sh_type == SHT_DYNSYM))
|
||||
dynsect = i;
|
||||
}
|
||||
/* start loading dynamic symbol info (so that we can get the correct address) */
|
||||
if (symsect != -1)
|
||||
elf_load_symtab(module, addr, module->elf_dbg_info->elf_addr,
|
||||
spnt + symsect, spnt + spnt[symsect].sh_link);
|
||||
else if (dynsect != -1)
|
||||
elf_load_symtab(module, addr, module->elf_dbg_info->elf_addr,
|
||||
spnt + dynsect, spnt + spnt[dynsect].sh_link);
|
||||
sym_type = SymExport;
|
||||
|
||||
if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
|
||||
{
|
||||
if (stabsect != -1 && stabstrsect != -1)
|
||||
{
|
||||
/* OK, now just parse all of the stabs. */
|
||||
sym_type = stabs_parse(module, addr, module->elf_dbg_info->elf_addr,
|
||||
spnt[stabsect].sh_offset, spnt[stabsect].sh_size,
|
||||
spnt[stabstrsect].sh_offset,
|
||||
spnt[stabstrsect].sh_size);
|
||||
if (sym_type == -1)
|
||||
{
|
||||
WARN("Couldn't read correctly read stabs\n");
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else if (debugsect != -1)
|
||||
{
|
||||
/* Dwarf 2 debug information */
|
||||
FIXME("Unsupported Dwarf2 information\n");
|
||||
sym_type = SymNone;
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
if (addr != (char*)0xffffffff) munmap(addr, statbuf.st_size);
|
||||
if (fd != -1) close(fd);
|
||||
|
||||
return module->module.SymType = sym_type;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* is_dt_flag_valid
|
||||
* returns true iff the section tag is valid
|
||||
*/
|
||||
static unsigned is_dt_flag_valid(unsigned d_tag)
|
||||
{
|
||||
#ifndef DT_PROCNUM
|
||||
#define DT_PROCNUM 0
|
||||
#endif
|
||||
#ifndef DT_EXTRANUM
|
||||
#define DT_EXTRANUM 0
|
||||
#endif
|
||||
return (d_tag >= 0 && d_tag < DT_NUM + DT_PROCNUM + DT_EXTRANUM)
|
||||
#if defined(DT_LOOS) && defined(DT_HIOS)
|
||||
|| (d_tag >= DT_LOOS && d_tag < DT_HIOS)
|
||||
#endif
|
||||
#if defined(DT_LOPROC) && defined(DT_HIPROC)
|
||||
|| (d_tag >= DT_LOPROC && d_tag < DT_HIPROC)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* elf_load_file
|
||||
*
|
||||
* Loads the information for ELF module stored in 'filename'
|
||||
* the module has been loaded at 'load_offset' address
|
||||
* returns
|
||||
* -1 if the file cannot be found/opened
|
||||
* 0 if the file doesn't contain symbolic info (or this info cannot be
|
||||
* read or parsed)
|
||||
* 1 on success
|
||||
*/
|
||||
static SYM_TYPE elf_load_file(struct process* pcs, const char* filename,
|
||||
unsigned long load_offset, struct elf_info* elf_info)
|
||||
{
|
||||
static const BYTE elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
|
||||
SYM_TYPE sym_type = -1;
|
||||
const char* addr = (char*)0xffffffff;
|
||||
int fd = -1;
|
||||
struct stat statbuf;
|
||||
const Elf32_Ehdr* ehptr;
|
||||
const Elf32_Shdr* spnt;
|
||||
const Elf32_Phdr* ppnt;
|
||||
const char* shstrtab;
|
||||
int i;
|
||||
DWORD delta, size;
|
||||
|
||||
TRACE("Processing elf file '%s' at %08lx\n", filename, load_offset);
|
||||
|
||||
/* check that the file exists, and that the module hasn't been loaded yet */
|
||||
if (stat(filename, &statbuf) == -1) goto leave;
|
||||
|
||||
/* Now open the file, so that we can mmap() it. */
|
||||
if ((fd = open(filename, O_RDONLY)) == -1) goto leave;
|
||||
|
||||
/* Now mmap() the file. */
|
||||
addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (addr == (char*)-1) goto leave;
|
||||
|
||||
sym_type = SymNone;
|
||||
|
||||
/* Next, we need to find a few of the internal ELF headers within
|
||||
* this thing. We need the main executable header, and the section
|
||||
* table.
|
||||
*/
|
||||
ehptr = (Elf32_Ehdr*)addr;
|
||||
if (memcmp(ehptr->e_ident, elf_signature, sizeof(elf_signature))) goto leave;
|
||||
|
||||
spnt = (Elf32_Shdr*)(addr + ehptr->e_shoff);
|
||||
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
|
||||
|
||||
/* if non relocatable ELF, then remove fixed address from computation
|
||||
* otherwise, all addresses are zero based
|
||||
*/
|
||||
delta = (load_offset == 0) ? ehptr->e_entry : 0;
|
||||
|
||||
/* grab size of module once loaded in memory */
|
||||
ppnt = (Elf32_Phdr*)(addr + ehptr->e_phoff);
|
||||
size = 0;
|
||||
for (i = 0; i < ehptr->e_phnum; i++)
|
||||
{
|
||||
if (ppnt[i].p_type == PT_LOAD)
|
||||
{
|
||||
size += (ppnt[i].p_align <= 1) ? ppnt[i].p_memsz :
|
||||
(ppnt[i].p_memsz + ppnt[i].p_align - 1) & ~(ppnt[i].p_align - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (elf_info->flags & ELF_INFO_DEBUG_HEADER)
|
||||
{
|
||||
for (i = 0; i < ehptr->e_shnum; i++)
|
||||
{
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".dynamic") == 0 &&
|
||||
spnt[i].sh_type == SHT_DYNAMIC)
|
||||
{
|
||||
Elf32_Dyn dyn;
|
||||
char* ptr = (char*)spnt[i].sh_addr;
|
||||
unsigned long len;
|
||||
|
||||
do
|
||||
{
|
||||
if (!ReadProcessMemory(pcs->handle, ptr, &dyn, sizeof(dyn), &len) ||
|
||||
len != sizeof(dyn) || !is_dt_flag_valid(dyn.d_tag))
|
||||
dyn.d_tag = DT_NULL;
|
||||
ptr += sizeof(dyn);
|
||||
} while (dyn.d_tag != DT_DEBUG && dyn.d_tag != DT_NULL);
|
||||
if (dyn.d_tag == DT_NULL)
|
||||
{
|
||||
sym_type = -1;
|
||||
goto leave;
|
||||
}
|
||||
elf_info->dbg_hdr_addr = dyn.d_un.d_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (elf_info->flags & ELF_INFO_MODULE)
|
||||
{
|
||||
elf_info->module = module_new(pcs, filename, DMT_ELF,
|
||||
(load_offset) ? load_offset : ehptr->e_entry,
|
||||
size, 0, 0);
|
||||
if (elf_info->module)
|
||||
{
|
||||
if ((elf_info->module->elf_dbg_info = HeapAlloc(GetProcessHeap(), 0, sizeof(ELF_DBG_INFO))) == NULL)
|
||||
{
|
||||
ERR("OOM\n");
|
||||
exit(0); /* FIXME */
|
||||
}
|
||||
elf_info->module->elf_dbg_info->elf_addr = load_offset;
|
||||
elf_info->module->module.SymType = sym_type =
|
||||
(dbghelp_options & SYMOPT_DEFERRED_LOADS) ? SymDeferred :
|
||||
elf_load_debug_info(elf_info->module);
|
||||
elf_info->module->elf_mark = 1;
|
||||
}
|
||||
else sym_type = -1;
|
||||
}
|
||||
|
||||
leave:
|
||||
if (addr != (char*)0xffffffff) munmap((void*)addr, statbuf.st_size);
|
||||
if (fd != -1) close(fd);
|
||||
|
||||
return sym_type;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* elf_load_file_from_path
|
||||
* tries to load an ELF file from a set of paths (separated by ':')
|
||||
*/
|
||||
static SYM_TYPE elf_load_file_from_path(HANDLE hProcess,
|
||||
const char* filename,
|
||||
unsigned long load_offset,
|
||||
const char* path,
|
||||
struct elf_info* elf_info)
|
||||
{
|
||||
SYM_TYPE sym_type = -1;
|
||||
char *s, *t, *fn;
|
||||
char* paths = NULL;
|
||||
|
||||
if (!path) return sym_type;
|
||||
|
||||
paths = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(path) + 1), path);
|
||||
for (s = paths; s && *s; s = (t) ? (t+1) : NULL)
|
||||
{
|
||||
t = strchr(s, ':');
|
||||
if (t) *t = '\0';
|
||||
fn = HeapAlloc(GetProcessHeap(), 0, strlen(filename) + 1 + strlen(s) + 1);
|
||||
if (!fn) break;
|
||||
strcpy(fn, s);
|
||||
strcat(fn, "/");
|
||||
strcat(fn, filename);
|
||||
sym_type = elf_load_file(hProcess, fn, load_offset, elf_info);
|
||||
HeapFree(GetProcessHeap(), 0, fn);
|
||||
if (sym_type != -1) break;
|
||||
s = (t) ? (t+1) : NULL;
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, paths);
|
||||
return sym_type;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* elf_search_and_load_file
|
||||
*
|
||||
* lookup a file in standard ELF locations, and if found, load it
|
||||
*/
|
||||
static SYM_TYPE elf_search_and_load_file(struct process* pcs, const char* filename,
|
||||
unsigned long load_offset, struct elf_info* elf_info)
|
||||
{
|
||||
SYM_TYPE sym_type = -1;
|
||||
struct module* module;
|
||||
|
||||
if (filename == NULL || *filename == '\0') return sym_type;
|
||||
if ((module = module_find_by_name(pcs, filename, DMT_ELF)))
|
||||
{
|
||||
elf_info->module = module;
|
||||
module->elf_mark = 1;
|
||||
return module->module.SymType;
|
||||
}
|
||||
|
||||
if (strstr(filename, "libstdc++")) return -1; /* We know we can't do it */
|
||||
sym_type = elf_load_file(pcs, filename, load_offset, elf_info);
|
||||
/* if relative pathname, try some absolute base dirs */
|
||||
if (sym_type == -1 && !strchr(filename, '/'))
|
||||
{
|
||||
sym_type = elf_load_file_from_path(pcs, filename, load_offset,
|
||||
getenv("PATH"), elf_info);
|
||||
if (sym_type == -1)
|
||||
sym_type = elf_load_file_from_path(pcs, filename, load_offset,
|
||||
getenv("LD_LIBRARY_PATH"), elf_info);
|
||||
if (sym_type == -1)
|
||||
sym_type = elf_load_file_from_path(pcs, filename, load_offset,
|
||||
getenv("WINEDLLPATH"), elf_info);
|
||||
}
|
||||
|
||||
return sym_type;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* elf_synchronize_module_list
|
||||
*
|
||||
* this functions rescans the debuggee module's list and synchronizes it with
|
||||
* the one from 'pcs', ie:
|
||||
* - if a module is in debuggee and not in pcs, it's loaded into pcs
|
||||
* - if a module is in pcs and not in debuggee, it's unloaded from pcs
|
||||
*/
|
||||
BOOL elf_synchronize_module_list(struct process* pcs)
|
||||
{
|
||||
struct r_debug dbg_hdr;
|
||||
void* lm_addr;
|
||||
struct link_map lm;
|
||||
char bufstr[256];
|
||||
struct elf_info elf_info;
|
||||
struct module* module;
|
||||
|
||||
if (!pcs->dbg_hdr_addr) return FALSE;
|
||||
if (!read_mem(pcs->handle, pcs->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr)) ||
|
||||
dbg_hdr.r_state != RT_CONSISTENT)
|
||||
return FALSE;
|
||||
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (module->type == DMT_ELF) module->elf_mark = 0;
|
||||
}
|
||||
|
||||
elf_info.flags = ELF_INFO_MODULE;
|
||||
/* Now walk the linked list. In all known ELF implementations,
|
||||
* the dynamic loader maintains this linked list for us. In some
|
||||
* cases the first entry doesn't appear with a name, in other cases it
|
||||
* does.
|
||||
*/
|
||||
for (lm_addr = (void*)dbg_hdr.r_map; lm_addr; lm_addr = (void*)lm.l_next)
|
||||
{
|
||||
if (!read_mem(pcs->handle, (ULONG)lm_addr, &lm, sizeof(lm)))
|
||||
return FALSE;
|
||||
|
||||
if (lm.l_prev != NULL && /* skip first entry, normally debuggee itself */
|
||||
lm.l_name != NULL &&
|
||||
read_mem(pcs->handle, (ULONG)lm.l_name, bufstr, sizeof(bufstr)))
|
||||
{
|
||||
bufstr[sizeof(bufstr) - 1] = '\0';
|
||||
elf_search_and_load_file(pcs, bufstr, lm.l_addr, &elf_info);
|
||||
}
|
||||
}
|
||||
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (module->type == DMT_ELF && !module->elf_mark)
|
||||
{
|
||||
module_remove(pcs, module);
|
||||
/* restart all over */
|
||||
module = pcs->lmodules;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* elf_read_wine_loader_dbg_info
|
||||
*
|
||||
* Try to find a decent wine executable which could have loader the debuggee
|
||||
*/
|
||||
unsigned long elf_read_wine_loader_dbg_info(struct process* pcs)
|
||||
{
|
||||
const char* ptr;
|
||||
SYM_TYPE sym_type;
|
||||
struct elf_info elf_info;
|
||||
|
||||
elf_info.flags = ELF_INFO_DEBUG_HEADER;
|
||||
/* All binaries are loaded with WINELOADER (if run from tree) or by the
|
||||
* main executable (either wine-kthread or wine-pthread)
|
||||
* Note: the heuristic use to know wether we need to load wine-pthread or
|
||||
* wine-kthread is not 100% safe
|
||||
*/
|
||||
if ((ptr = getenv("WINELOADER")))
|
||||
sym_type = elf_search_and_load_file(pcs, ptr, 0, &elf_info);
|
||||
else
|
||||
{
|
||||
if ((sym_type = elf_search_and_load_file(pcs, "wine-kthread", 0, &elf_info)) == -1)
|
||||
sym_type = elf_search_and_load_file(pcs, "wine-pthread", 0, &elf_info);
|
||||
}
|
||||
return (sym_type < 0) ? 0 : elf_info.dbg_hdr_addr;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* elf_load_module
|
||||
*
|
||||
* loads an ELF module and stores it in process' module list
|
||||
* if 'sync' is TRUE, let's find module real name and load address from
|
||||
* the real loaded modules list in pcs address space
|
||||
*/
|
||||
struct module* elf_load_module(struct process* pcs, const char* name)
|
||||
{
|
||||
struct elf_info elf_info;
|
||||
SYM_TYPE sym_type = -1;
|
||||
const char* p;
|
||||
const char* xname;
|
||||
struct r_debug dbg_hdr;
|
||||
void* lm_addr;
|
||||
struct link_map lm;
|
||||
char bufstr[256];
|
||||
|
||||
TRACE("(%p %s)\n", pcs, name);
|
||||
|
||||
elf_info.flags = ELF_INFO_MODULE;
|
||||
|
||||
/* do only the lookup from the filename, not the path (as we lookup module name
|
||||
* in the process' loaded module list)
|
||||
*/
|
||||
xname = strrchr(name, '/');
|
||||
if (!xname++) xname = name;
|
||||
|
||||
if (!read_mem(pcs->handle, pcs->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr)) ||
|
||||
dbg_hdr.r_state != RT_CONSISTENT)
|
||||
return NULL;
|
||||
|
||||
for (lm_addr = (void*)dbg_hdr.r_map; lm_addr; lm_addr = (void*)lm.l_next)
|
||||
{
|
||||
if (!read_mem(pcs->handle, (ULONG)lm_addr, &lm, sizeof(lm)))
|
||||
return NULL;
|
||||
|
||||
if (lm.l_prev != NULL && /* skip first entry, normally debuggee itself */
|
||||
lm.l_name != NULL &&
|
||||
read_mem(pcs->handle, (ULONG)lm.l_name, bufstr, sizeof(bufstr)))
|
||||
{
|
||||
bufstr[sizeof(bufstr) - 1] = '\0';
|
||||
/* memcmp is needed for matches when bufstr contains also version information
|
||||
* name: libc.so, bufstr: libc.so.6.0
|
||||
*/
|
||||
p = strrchr(bufstr, '/');
|
||||
if (!p++) p = bufstr;
|
||||
if (!memcmp(p, xname, strlen(xname)))
|
||||
{
|
||||
sym_type = elf_search_and_load_file(pcs, bufstr, lm.l_addr, &elf_info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!lm_addr || sym_type == -1) return NULL;
|
||||
assert(elf_info.module);
|
||||
return elf_info.module;
|
||||
}
|
||||
|
||||
#else /* !__ELF__ */
|
||||
|
||||
BOOL elf_synchronize_module_list(struct process* pcs)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SYM_TYPE elf_read_wine_loader_dbg_info(struct process pcs, struct elf_info* elf_info)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct module* elf_load_module(struct process* pcs, const char* name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SYM_TYPE elf_load_debug_info(struct module* module)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif /* __ELF__ */
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* File image.c - managing images
|
||||
*
|
||||
* Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
#include "winreg.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
/***********************************************************************
|
||||
* GetTimestampForLoadedLibrary (DBGHELP.@)
|
||||
*/
|
||||
DWORD WINAPI GetTimestampForLoadedLibrary(HMODULE Module)
|
||||
{
|
||||
IMAGE_NT_HEADERS* nth = RtlImageNtHeader(Module);
|
||||
return (nth) ? nth->FileHeader.TimeDateStamp : 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MapDebugInformation (DBGHELP.@)
|
||||
*/
|
||||
PIMAGE_DEBUG_INFORMATION WINAPI MapDebugInformation(HANDLE FileHandle, LPSTR FileName,
|
||||
LPSTR SymbolPath, DWORD ImageBase)
|
||||
{
|
||||
FIXME("(%p, %s, %s, 0x%08lx): stub\n", FileHandle, FileName, SymbolPath, ImageBase);
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* UnmapDebugInformation (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI UnmapDebugInformation(PIMAGE_DEBUG_INFORMATION DebugInfo)
|
||||
{
|
||||
FIXME("(%p): stub\n", DebugInfo);
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* File memory.c - managing memory
|
||||
*
|
||||
* Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include "dbghelp_private.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
BOOL win32_read_mem(HANDLE hProcess, DWORD addr, void* buf, DWORD len)
|
||||
{
|
||||
return ReadProcessMemory(hProcess, (void*)addr, buf, len, NULL);
|
||||
}
|
||||
|
||||
BOOL win32_write_mem(HANDLE hProcess, DWORD addr, void* buf, DWORD len)
|
||||
{
|
||||
return WriteProcessMemory(hProcess, (void*)addr, buf, len, NULL);
|
||||
}
|
||||
|
||||
/* standard routines for reading / writing memory. Can be overriden for some
|
||||
* minidump usage
|
||||
*/
|
||||
struct memory_access mem_access = {win32_read_mem, win32_write_mem};
|
||||
|
||||
/******************************************************************
|
||||
* addr_to_linear
|
||||
*
|
||||
* converts an address into its linear value
|
||||
*/
|
||||
unsigned long WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr)
|
||||
{
|
||||
LDT_ENTRY le;
|
||||
|
||||
switch (addr->Mode)
|
||||
{
|
||||
case AddrMode1616:
|
||||
if (GetThreadSelectorEntry(hThread, addr->Segment, &le))
|
||||
return (le.HighWord.Bits.BaseHi << 24) +
|
||||
(le.HighWord.Bits.BaseMid << 16) + le.BaseLow + LOWORD(addr->Offset);
|
||||
break;
|
||||
case AddrMode1632:
|
||||
if (GetThreadSelectorEntry(hThread, addr->Segment, &le))
|
||||
return (le.HighWord.Bits.BaseHi << 24) +
|
||||
(le.HighWord.Bits.BaseMid << 16) + le.BaseLow + addr->Offset;
|
||||
break;
|
||||
case AddrModeReal:
|
||||
return (DWORD)(LOWORD(addr->Segment) << 4) + addr->Offset;
|
||||
case AddrModeFlat:
|
||||
return addr->Offset;
|
||||
default:
|
||||
FIXME("Unsupported (yet) mode (%x)\n", addr->Mode);
|
||||
return 0;
|
||||
}
|
||||
FIXME("Failed to linearize address %04x:%08lx (mode %x)\n",
|
||||
addr->Segment, addr->Offset, addr->Mode);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* File minidump.c - management of dumps (read & write)
|
||||
*
|
||||
* Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define NONAMELESSSTRUCT
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
#if 0
|
||||
/* hard to see how we can generate this very easily (how to grab latest exception
|
||||
* in a process ?)
|
||||
*/
|
||||
static void DumpException(struct process* pcs, HANDLE hFile, RVA* rva)
|
||||
{
|
||||
MINIDUMP_EXCEPTION_STREAM mdExcpt;
|
||||
|
||||
mdExcpt.ThreadId = DEBUG_CurrThread->tid;
|
||||
mdExcpt.__alignment = 0;
|
||||
mdExcpt.ExceptionRecord.
|
||||
|
||||
ULONG ExceptionCode;
|
||||
ULONG ExceptionFlags;
|
||||
ULONGLONG ExceptionRecord;
|
||||
ULONGLONG ExceptionAddress;
|
||||
ULONG NumberParameters;
|
||||
ULONG __unusedAlignment;
|
||||
ULONGLONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************
|
||||
* dump_modules
|
||||
*
|
||||
* Write in File the modules from pcs
|
||||
*/
|
||||
static void dump_modules(struct process* pcs, HANDLE hFile, RVA* rva)
|
||||
{
|
||||
MINIDUMP_MODULE mdModule;
|
||||
MINIDUMP_MODULE_LIST mdModuleList;
|
||||
DWORD written;
|
||||
struct module* module = NULL;
|
||||
|
||||
mdModuleList.NumberOfModules = 0;
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
mdModuleList.NumberOfModules++;
|
||||
WriteFile(hFile, &mdModuleList.NumberOfModules,
|
||||
sizeof(mdModuleList.NumberOfModules), &written, NULL);
|
||||
*rva += sizeof(mdModuleList.NumberOfModules) +
|
||||
sizeof(mdModule) * mdModuleList.NumberOfModules;
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
mdModule.BaseOfImage = (DWORD)module->module.BaseOfImage;
|
||||
mdModule.SizeOfImage = module->module.ImageSize;
|
||||
mdModule.CheckSum = module->module.CheckSum;
|
||||
mdModule.TimeDateStamp = module->module.TimeDateStamp;
|
||||
mdModule.ModuleNameRva = *rva;
|
||||
*rva += strlen(module->module.ModuleName) + 1;
|
||||
memset(&mdModule.VersionInfo, 0, sizeof(mdModule.VersionInfo)); /* FIXME */
|
||||
mdModule.CvRecord.DataSize = 0; /* FIXME */
|
||||
mdModule.CvRecord.Rva = 0; /* FIXME */
|
||||
mdModule.MiscRecord.DataSize = 0; /* FIXME */
|
||||
mdModule.MiscRecord.Rva = 0; /* FIXME */
|
||||
mdModule.Reserved0 = 0;
|
||||
mdModule.Reserved1 = 0;
|
||||
WriteFile(hFile, &mdModule, sizeof(mdModule), &written, NULL);
|
||||
}
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
WriteFile(hFile, module->module.ModuleName,
|
||||
strlen(module->module.ModuleName) + 1, &written, NULL);
|
||||
FIXME("CV and misc records not written\n");
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* dump_system_info
|
||||
*
|
||||
* Dumps into File the information about the system
|
||||
*/
|
||||
static void dump_system_info(struct process* pcs, HANDLE hFile, RVA* rva)
|
||||
{
|
||||
MINIDUMP_SYSTEM_INFO mdSysInfo;
|
||||
SYSTEM_INFO sysInfo;
|
||||
OSVERSIONINFOA osInfo;
|
||||
DWORD written;
|
||||
|
||||
GetSystemInfo(&sysInfo);
|
||||
GetVersionExA(&osInfo);
|
||||
|
||||
mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
|
||||
mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
|
||||
mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
|
||||
mdSysInfo.Reserved0 = 0;
|
||||
|
||||
mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
|
||||
mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
|
||||
mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
|
||||
mdSysInfo.PlatformId = osInfo.dwPlatformId;
|
||||
|
||||
mdSysInfo.CSDVersionRva = *rva + sizeof(mdSysInfo);
|
||||
mdSysInfo.Reserved1 = 0;
|
||||
|
||||
WriteFile(hFile, &mdSysInfo, sizeof(mdSysInfo), &written, NULL);
|
||||
*rva += sizeof(mdSysInfo);
|
||||
WriteFile(hFile, osInfo.szCSDVersion, strlen(osInfo.szCSDVersion) + 1,
|
||||
&written, NULL);
|
||||
*rva += strlen(osInfo.szCSDVersion) + 1;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* dump_threads
|
||||
*
|
||||
* Dumps into File the information about running threads
|
||||
*/
|
||||
static void dump_threads(struct process* pcs, HANDLE hFile, RVA* rva)
|
||||
{
|
||||
#if 0
|
||||
MINIDUMP_THREAD mdThd;
|
||||
MINIDUMP_THREAD_LIST mdThdList;
|
||||
DWORD written;
|
||||
DBG_THREAD* thd;
|
||||
|
||||
mdThdList.NumberOfThreads = pcs->num_threads;
|
||||
WriteFile(hFile, &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads),
|
||||
&written, NULL);
|
||||
*rva += sizeof(mdThdList.NumberOfThreads) +
|
||||
mdThdList.NumberOfThreads * sizeof(mdThd);
|
||||
for (thd = pcs->threads; thd; thd = thd->next)
|
||||
{
|
||||
mdThd.ThreadId = thd->tid;
|
||||
mdThd.SuspendCount = 0; /* FIXME */
|
||||
mdThd.PriorityClass = 0; /* FIXME */
|
||||
mdThd.Priority = 0; /* FIXME */
|
||||
mdThd.Teb = 0; /* FIXME */
|
||||
mdThd.Stack.StartOfMemoryRange = 0; /* FIXME */
|
||||
mdThd.Stack.Memory.DataSize = 0; /* FIXME */
|
||||
mdThd.Stack.Memory.Rva = 0; /* FIXME */
|
||||
mdThd.ThreadContext.DataSize = 0;/* FIXME */
|
||||
mdThd.ThreadContext.Rva = 0; /* FIXME */
|
||||
|
||||
WriteFile(hFile, &mdThd, sizeof(mdThd), &written, NULL);
|
||||
FIXME("Stack & thread context not written\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* MiniDumpWriteDump (DEBUGHLP.@)
|
||||
*
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
|
||||
MINIDUMP_TYPE DumpType,
|
||||
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
PMINIDUMP_CALLBACK_INFORMATION CallbackParam)
|
||||
{
|
||||
struct process* pcs;
|
||||
MINIDUMP_HEADER mdHead;
|
||||
MINIDUMP_DIRECTORY mdDir;
|
||||
DWORD currRva, written;
|
||||
DWORD i, nStream, addStream;
|
||||
RVA rva;
|
||||
|
||||
pcs = process_find_by_handle(hProcess);
|
||||
if (!pcs) return FALSE; /* FIXME: should try to load it ??? */
|
||||
|
||||
/* 1) init */
|
||||
|
||||
nStream = UserStreamParam ? UserStreamParam->UserStreamCount : 0;
|
||||
addStream = 0;
|
||||
if (DumpType & MiniDumpNormal)
|
||||
addStream += 3; /* sure ? thread stack back trace */
|
||||
|
||||
if (DumpType & MiniDumpWithDataSegs)
|
||||
FIXME("NIY MiniDumpWithDataSegs\n");
|
||||
if (DumpType & MiniDumpWithFullMemory)
|
||||
FIXME("NIY MiniDumpWithFullMemory\n");
|
||||
if (DumpType & MiniDumpWithHandleData)
|
||||
FIXME("NIY MiniDumpWithHandleData\n");
|
||||
if (DumpType & MiniDumpFilterMemory)
|
||||
FIXME("NIY MiniDumpFilterMemory\n");
|
||||
if (DumpType & MiniDumpScanMemory)
|
||||
FIXME("NIY MiniDumpScanMemory\n");
|
||||
|
||||
/* 2) write header */
|
||||
rva = sizeof(mdHead);
|
||||
mdHead.Signature = MINIDUMP_SIGNATURE;
|
||||
mdHead.Version = MINIDUMP_VERSION;
|
||||
mdHead.NumberOfStreams = nStream + addStream;
|
||||
mdHead.StreamDirectoryRva = rva;
|
||||
mdHead.u.TimeDateStamp = time(NULL);
|
||||
mdHead.Flags = DumpType;
|
||||
WriteFile(hFile, &mdHead, sizeof(mdHead), &written, NULL);
|
||||
|
||||
/* 3) write stream directories */
|
||||
rva += (nStream + addStream) * sizeof(mdDir);
|
||||
/* 3.1) write data stream directories */
|
||||
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
|
||||
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
|
||||
mdDir.StreamType = ModuleListStream;
|
||||
mdDir.Location.Rva = rva;
|
||||
dump_modules(pcs, hFile, &rva);
|
||||
mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva;
|
||||
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
|
||||
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
|
||||
|
||||
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
|
||||
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
|
||||
mdDir.StreamType = ThreadListStream;
|
||||
mdDir.Location.Rva = rva;
|
||||
dump_threads(pcs, hFile, &rva);
|
||||
mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva;
|
||||
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
|
||||
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
|
||||
|
||||
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
|
||||
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
|
||||
mdDir.StreamType = SystemInfoStream;
|
||||
mdDir.Location.Rva = rva;
|
||||
dump_system_info(pcs, hFile, &rva);
|
||||
mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva;
|
||||
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
|
||||
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
|
||||
|
||||
/* 3.2) write user define stream */
|
||||
for (i = 0; i < nStream; i++)
|
||||
{
|
||||
mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
|
||||
mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
|
||||
mdDir.Location.Rva = rva;
|
||||
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
|
||||
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
|
||||
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
|
||||
WriteFile(hFile,
|
||||
UserStreamParam->UserStreamArray[i].Buffer,
|
||||
UserStreamParam->UserStreamArray[i].BufferSize,
|
||||
&written, NULL);
|
||||
rva += UserStreamParam->UserStreamArray[i].BufferSize;
|
||||
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* File module.c - module handling for the wine debugger
|
||||
*
|
||||
* Copyright (C) 1993, Eric Youngdale.
|
||||
* 2000-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
#include "psapi.h"
|
||||
#include "winreg.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
/***********************************************************************
|
||||
* Creates and links a new module to a process
|
||||
*/
|
||||
struct module* module_new(struct process* pcs, const char* name,
|
||||
enum DbgModuleType type,
|
||||
unsigned long mod_addr, unsigned long size,
|
||||
unsigned long stamp, unsigned long checksum)
|
||||
{
|
||||
struct module* module;
|
||||
const char* ptr;
|
||||
|
||||
if (!(module = HeapAlloc(GetProcessHeap(), 0, sizeof(*module))))
|
||||
return NULL;
|
||||
|
||||
memset(module, 0, sizeof(*module));
|
||||
|
||||
module->next = pcs->lmodules;
|
||||
pcs->lmodules = module;
|
||||
|
||||
TRACE("=> %s %08lx-%08lx %s\n",
|
||||
type == DMT_ELF ? "ELF" : (type == DMT_PE ? "PE" : "---"),
|
||||
mod_addr, mod_addr + size, name);
|
||||
|
||||
pool_init(&module->pool, 65536);
|
||||
|
||||
module->module.SizeOfStruct = sizeof(module->module);
|
||||
module->module.BaseOfImage = mod_addr;
|
||||
module->module.ImageSize = size;
|
||||
for (ptr = name + strlen(name) - 1;
|
||||
*ptr != '/' && *ptr != '\\' && ptr >= name;
|
||||
ptr--);
|
||||
if (ptr < name || *ptr == '/' || *ptr == '\\') ptr++;
|
||||
strncpy(module->module.ModuleName, ptr, sizeof(module->module.ModuleName));
|
||||
module->module.ModuleName[sizeof(module->module.ModuleName) - 1] = '\0';
|
||||
module->module.ImageName[0] = '\0';
|
||||
strncpy(module->module.LoadedImageName, name,
|
||||
sizeof(module->module.LoadedImageName));
|
||||
module->module.LoadedImageName[sizeof(module->module.LoadedImageName) - 1] = '\0';
|
||||
module->module.SymType = SymNone;
|
||||
module->module.NumSyms = 0;
|
||||
module->module.TimeDateStamp = stamp;
|
||||
module->module.CheckSum = checksum;
|
||||
|
||||
module->type = type;
|
||||
module->sortlist_valid = FALSE;
|
||||
module->addr_sorttab = NULL;
|
||||
/* FIXME: this seems a bit too high (on a per module basis)
|
||||
* need some statistics about this
|
||||
*/
|
||||
hash_table_init(&module->pool, &module->ht_symbols, 4096);
|
||||
hash_table_init(&module->pool, &module->ht_types, 4096);
|
||||
|
||||
module->sources_used = 0;
|
||||
module->sources_alloc = 0;
|
||||
module->sources = 0;
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* module_find_by_name
|
||||
*
|
||||
*/
|
||||
struct module* module_find_by_name(const struct process* pcs,
|
||||
const char* name, enum DbgModuleType type)
|
||||
{
|
||||
struct module* module;
|
||||
|
||||
if (type == DMT_UNKNOWN)
|
||||
{
|
||||
if ((module = module_find_by_name(pcs, name, DMT_PE)) ||
|
||||
(module = module_find_by_name(pcs, name, DMT_ELF)))
|
||||
return module;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (type == module->type && !strcasecmp(name, module->module.LoadedImageName))
|
||||
return module;
|
||||
}
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (type == module->type && !strcasecmp(name, module->module.ModuleName))
|
||||
return module;
|
||||
}
|
||||
}
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* module_has_container
|
||||
*
|
||||
*/
|
||||
static struct module* module_get_container(const struct process* pcs,
|
||||
const struct module* inner)
|
||||
{
|
||||
struct module* module;
|
||||
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (module != inner &&
|
||||
module->module.BaseOfImage <= inner->module.BaseOfImage &&
|
||||
module->module.BaseOfImage + module->module.ImageSize >=
|
||||
inner->module.BaseOfImage + inner->module.ImageSize)
|
||||
return module;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* module_get_debug
|
||||
*
|
||||
* get the debug information from a module:
|
||||
* - if the module's type is deferred, then force loading of debug info (and return
|
||||
* the module itself)
|
||||
* - if the module has no debug info and has an ELF container, then return the ELF
|
||||
* container (and also force the ELF container's debug info loading if deferred)
|
||||
* - otherwise return the module itself if it has some debug info
|
||||
*/
|
||||
struct module* module_get_debug(const struct process* pcs, struct module* module)
|
||||
{
|
||||
if (!module) return NULL;
|
||||
switch (module->module.SymType)
|
||||
{
|
||||
case -1: break;
|
||||
case SymNone:
|
||||
module = module_get_container(pcs, module);
|
||||
if (!module || module->module.SymType != SymDeferred) break;
|
||||
/* fall through */
|
||||
case SymDeferred:
|
||||
switch (module->type)
|
||||
{
|
||||
case DMT_ELF:
|
||||
elf_load_debug_info(module);
|
||||
break;
|
||||
case DMT_PE:
|
||||
pe_load_debug_info(pcs, module);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return (module && module->module.SymType > SymNone) ? module : NULL;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* module_find_by_addr
|
||||
*
|
||||
* either the addr where module is loaded, or any address inside the
|
||||
* module
|
||||
*/
|
||||
struct module* module_find_by_addr(const struct process* pcs, unsigned long addr,
|
||||
enum DbgModuleType type)
|
||||
{
|
||||
struct module* module;
|
||||
|
||||
if (type == DMT_UNKNOWN)
|
||||
{
|
||||
if ((module = module_find_by_addr(pcs, addr, DMT_PE)) ||
|
||||
(module = module_find_by_addr(pcs, addr, DMT_ELF)))
|
||||
return module;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (type == module->type && addr >= module->module.BaseOfImage &&
|
||||
addr < module->module.BaseOfImage + module->module.ImageSize)
|
||||
return module;
|
||||
}
|
||||
}
|
||||
SetLastError(ERROR_INVALID_ADDRESS);
|
||||
return module;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymLoadModule (DBGHELP.@)
|
||||
*/
|
||||
DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, char* ImageName,
|
||||
char* ModuleName, DWORD BaseOfDll, DWORD SizeOfDll)
|
||||
{
|
||||
struct process* pcs;
|
||||
struct module* module = NULL;
|
||||
|
||||
TRACE("(%p %p %s %s %08lx %08lx)\n",
|
||||
hProcess, hFile, debugstr_a(ImageName), debugstr_a(ModuleName),
|
||||
BaseOfDll, SizeOfDll);
|
||||
|
||||
pcs = process_find_by_handle(hProcess);
|
||||
if (!pcs) return FALSE;
|
||||
|
||||
if (!(module = pe_load_module(pcs, ImageName, hFile, BaseOfDll, SizeOfDll)))
|
||||
{
|
||||
unsigned len = strlen(ImageName);
|
||||
|
||||
if (!strcmp(ImageName + len - 3, ".so") &&
|
||||
(module = elf_load_module(pcs, ImageName))) goto done;
|
||||
if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll)))
|
||||
goto done;
|
||||
WARN("Couldn't locate %s\n", ImageName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
done:
|
||||
/* by default pe_load_module fills module.ModuleName from a derivation
|
||||
* of ImageName. Overwrite it, if we have better information
|
||||
*/
|
||||
if (ModuleName)
|
||||
{
|
||||
strncpy(module->module.ModuleName, ModuleName,
|
||||
sizeof(module->module.ModuleName));
|
||||
module->module.ModuleName[sizeof(module->module.ModuleName) - 1] = '\0';
|
||||
}
|
||||
strncpy(module->module.ImageName, ImageName, sizeof(module->module.ImageName));
|
||||
module->module.ImageName[sizeof(module->module.ImageName) - 1] = '\0';
|
||||
/* force transparent ELF loading / unloading */
|
||||
if (module->type != DMT_ELF) elf_synchronize_module_list(pcs);
|
||||
|
||||
return module->module.BaseOfImage;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* module_remove
|
||||
*
|
||||
*/
|
||||
BOOL module_remove(struct process* pcs, struct module* module)
|
||||
{
|
||||
struct module** p;
|
||||
|
||||
TRACE("%s (%p)\n", module->module.ModuleName, module);
|
||||
hash_table_destroy(&module->ht_symbols);
|
||||
hash_table_destroy(&module->ht_types);
|
||||
HeapFree(GetProcessHeap(), 0, (char*)module->sources);
|
||||
HeapFree(GetProcessHeap(), 0, module->addr_sorttab);
|
||||
pool_destroy(&module->pool);
|
||||
|
||||
for (p = &pcs->lmodules; *p; p = &(*p)->next)
|
||||
{
|
||||
if (*p == module)
|
||||
{
|
||||
*p = module->next;
|
||||
HeapFree(GetProcessHeap(), 0, module);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
FIXME("This shouldn't happen\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymUnloadModule (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymUnloadModule(HANDLE hProcess, DWORD BaseOfDll)
|
||||
{
|
||||
struct process* pcs;
|
||||
struct module* module;
|
||||
|
||||
pcs = process_find_by_handle(hProcess);
|
||||
if (!pcs) return FALSE;
|
||||
module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
|
||||
if (!module) return FALSE;
|
||||
return module_remove(pcs, module);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymEnumerateModules (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymEnumerateModules(HANDLE hProcess,
|
||||
PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,
|
||||
PVOID UserContext)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
struct module* module;
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (module->type != DMT_PE) continue;
|
||||
if (!EnumModulesCallback(module->module.ModuleName,
|
||||
module->module.BaseOfImage, UserContext))
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* EnumerateLoadedModules (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI EnumerateLoadedModules(HANDLE hProcess,
|
||||
PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,
|
||||
PVOID UserContext)
|
||||
{
|
||||
HMODULE* hMods;
|
||||
char img[256], mod[256];
|
||||
DWORD i, sz;
|
||||
MODULEINFO mi;
|
||||
|
||||
hMods = HeapAlloc(GetProcessHeap(), 0, sz);
|
||||
if (!hMods) return FALSE;
|
||||
|
||||
if (!EnumProcessModules(hProcess, hMods, 256 * sizeof(hMods[0]), &sz))
|
||||
{
|
||||
/* hProcess should also be a valid process handle !! */
|
||||
FIXME("If this happens, bump the number in mod\n");
|
||||
HeapFree(GetProcessHeap(), 0, hMods);
|
||||
return FALSE;
|
||||
}
|
||||
sz /= sizeof(HMODULE);
|
||||
for (i = 0; i < sz; i++)
|
||||
{
|
||||
if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
|
||||
!GetModuleFileNameExA(hProcess, hMods[i], img, sizeof(img)) ||
|
||||
!GetModuleBaseNameA(hProcess, hMods[i], mod, sizeof(mod)))
|
||||
break;
|
||||
EnumLoadedModulesCallback(mod, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage,
|
||||
UserContext);
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, hMods);
|
||||
|
||||
return sz != 0 && i == sz;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymGetModuleInfo (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymGetModuleInfo(HANDLE hProcess, DWORD dwAddr,
|
||||
PIMAGEHLP_MODULE ModuleInfo)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
struct module* module;
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
if (ModuleInfo->SizeOfStruct < sizeof(*ModuleInfo)) return FALSE;
|
||||
module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
|
||||
if (!module) return FALSE;
|
||||
|
||||
*ModuleInfo = module->module;
|
||||
if (module->module.SymType <= SymNone)
|
||||
{
|
||||
module = module_get_container(pcs, module);
|
||||
if (module && module->module.SymType > SymNone)
|
||||
ModuleInfo->SymType = module->module.SymType;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymGetModuleBase (IMAGEHLP.@)
|
||||
*/
|
||||
DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
struct module* module;
|
||||
|
||||
if (!pcs) return 0;
|
||||
module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
|
||||
if (!module) return 0;
|
||||
return module->module.BaseOfImage;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* File path.c - managing path in debugging environments
|
||||
*
|
||||
* Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
/******************************************************************
|
||||
* FindDebugInfoFile (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
HANDLE WINAPI FindDebugInfoFile(PSTR FileName, PSTR SymbolPath, PSTR DebugFilePath)
|
||||
{
|
||||
HANDLE h;
|
||||
|
||||
h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
const char* p = strrchr(FileName, '/');
|
||||
if (!p) p = FileName;
|
||||
if (!SearchPathA(SymbolPath, p, NULL, MAX_PATH, DebugFilePath, NULL))
|
||||
return NULL;
|
||||
h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
}
|
||||
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* FindDebugInfoFileEx (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
HANDLE WINAPI FindDebugInfoFileEx(PSTR FileName, PSTR SymbolPath,
|
||||
PSTR DebugFilePath,
|
||||
PFIND_DEBUG_FILE_CALLBACK Callback,
|
||||
PVOID CallerData)
|
||||
{
|
||||
FIXME("(%s %s %p %p %p): stub\n",
|
||||
FileName, SymbolPath, DebugFilePath, Callback, CallerData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* FindExecutableImage (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
HANDLE WINAPI FindExecutableImage(PSTR FileName, PSTR SymbolPath, PSTR ImageFilePath)
|
||||
{
|
||||
HANDLE h;
|
||||
if (!SearchPathA(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
|
||||
return NULL;
|
||||
h = CreateFileA(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MakeSureDirectoryPathExists (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI MakeSureDirectoryPathExists(LPCSTR DirPath)
|
||||
{
|
||||
if (CreateDirectoryA(DirPath, NULL)) return TRUE;
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SearchTreeForFile (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI SearchTreeForFile(LPSTR RootPath, LPSTR InputPathName,
|
||||
LPSTR OutputPathBuffer)
|
||||
{
|
||||
FIXME("(%s, %s, %s): stub\n",
|
||||
debugstr_a(RootPath), debugstr_a(InputPathName),
|
||||
debugstr_a(OutputPathBuffer));
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
* File pe_module.c - handle PE module information
|
||||
*
|
||||
* Copyright (C) 1996, Eric Youngdale.
|
||||
* Copyright (C) 1999-2000, Ulrich Weigand.
|
||||
* Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
#include "winreg.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
/******************************************************************
|
||||
* pe_load_stabs
|
||||
*
|
||||
* look for stabs information in PE header (it's how the mingw compiler provides
|
||||
* its debugging information)
|
||||
*/
|
||||
static SYM_TYPE pe_load_stabs(const struct process* pcs, struct module* module,
|
||||
const void* mapping, IMAGE_NT_HEADERS* nth)
|
||||
{
|
||||
IMAGE_SECTION_HEADER* section;
|
||||
int i, stabsize = 0, stabstrsize = 0;
|
||||
unsigned int stabs = 0, stabstr = 0;
|
||||
SYM_TYPE sym_type = SymNone;
|
||||
|
||||
section = (IMAGE_SECTION_HEADER*)
|
||||
((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
|
||||
for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
|
||||
{
|
||||
if (!strcasecmp(section->Name, ".stab"))
|
||||
{
|
||||
stabs = section->VirtualAddress;
|
||||
stabsize = section->SizeOfRawData;
|
||||
}
|
||||
else if (!strncasecmp(section->Name, ".stabstr", 8))
|
||||
{
|
||||
stabstr = section->VirtualAddress;
|
||||
stabstrsize = section->SizeOfRawData;
|
||||
}
|
||||
}
|
||||
|
||||
if (stabstrsize && stabsize)
|
||||
{
|
||||
sym_type = stabs_parse(module, mapping, module->module.BaseOfImage,
|
||||
stabs, stabsize, stabstr, stabstrsize);
|
||||
}
|
||||
return sym_type;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* pe_load_dbg_file
|
||||
*
|
||||
* loads a .dbg file
|
||||
*/
|
||||
static SYM_TYPE pe_load_dbg_file(const struct process* pcs, struct module* module,
|
||||
char* dbg_name, DWORD timestamp)
|
||||
{
|
||||
char tmp[MAX_PATH];
|
||||
HANDLE hFile, hMap = 0;
|
||||
const BYTE* dbg_mapping = NULL;
|
||||
PIMAGE_SEPARATE_DEBUG_HEADER hdr;
|
||||
PIMAGE_DEBUG_DIRECTORY dbg;
|
||||
SYM_TYPE sym_type = -1;
|
||||
|
||||
WINE_TRACE("Processing DBG file %s\n", dbg_name);
|
||||
|
||||
if ((hFile = FindDebugInfoFile(dbg_name, pcs->search_path, tmp)) != NULL &&
|
||||
((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) &&
|
||||
((dbg_mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL))
|
||||
{
|
||||
hdr = (PIMAGE_SEPARATE_DEBUG_HEADER)dbg_mapping;
|
||||
if (hdr->TimeDateStamp != timestamp)
|
||||
{
|
||||
WINE_ERR("Warning - %s has incorrect internal timestamp\n",
|
||||
dbg_name);
|
||||
/*
|
||||
* Well, sometimes this happens to DBG files which ARE REALLY the
|
||||
* right .DBG files but nonetheless this check fails. Anyway,
|
||||
* WINDBG (debugger for Windows by Microsoft) loads debug symbols
|
||||
* which have incorrect timestamps.
|
||||
*/
|
||||
}
|
||||
dbg = (PIMAGE_DEBUG_DIRECTORY)
|
||||
(dbg_mapping + sizeof(*hdr) +
|
||||
hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
|
||||
hdr->ExportedNamesSize);
|
||||
|
||||
sym_type = pe_load_debug_directory(pcs, module, dbg_mapping, dbg,
|
||||
hdr->DebugDirectorySize / sizeof(*dbg));
|
||||
}
|
||||
else
|
||||
{
|
||||
WINE_ERR("-Unable to peruse .DBG file %s (%s)\n",
|
||||
dbg_name, debugstr_a(tmp));
|
||||
}
|
||||
if (dbg_mapping) UnmapViewOfFile((void*)dbg_mapping);
|
||||
if (hMap) CloseHandle(hMap);
|
||||
if (hFile != NULL) CloseHandle(hFile);
|
||||
return sym_type;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* pe_load_msc_debug_info
|
||||
*
|
||||
* Process MSC debug information in PE file.
|
||||
*/
|
||||
static SYM_TYPE pe_load_msc_debug_info(const struct process* pcs,
|
||||
struct module* module,
|
||||
const void* mapping, IMAGE_NT_HEADERS* nth)
|
||||
{
|
||||
SYM_TYPE sym_type = -1;
|
||||
PIMAGE_DATA_DIRECTORY dir;
|
||||
PIMAGE_DEBUG_DIRECTORY dbg = NULL;
|
||||
int nDbg;
|
||||
|
||||
/* Read in debug directory */
|
||||
dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
|
||||
nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY);
|
||||
if (!nDbg) return sym_type;
|
||||
|
||||
dbg = (PIMAGE_DEBUG_DIRECTORY)((char*)mapping + dir->VirtualAddress);
|
||||
|
||||
/* Parse debug directory */
|
||||
if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
|
||||
{
|
||||
/* Debug info is stripped to .DBG file */
|
||||
PIMAGE_DEBUG_MISC misc = (PIMAGE_DEBUG_MISC)
|
||||
((char*)mapping + dbg->PointerToRawData);
|
||||
|
||||
if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC ||
|
||||
misc->DataType != IMAGE_DEBUG_MISC_EXENAME)
|
||||
{
|
||||
WINE_ERR("-Debug info stripped, but no .DBG file in module %s\n",
|
||||
module->module.ModuleName);
|
||||
}
|
||||
else
|
||||
{
|
||||
sym_type = pe_load_dbg_file(pcs, module, misc->Data, nth->FileHeader.TimeDateStamp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Debug info is embedded into PE module */
|
||||
sym_type = pe_load_debug_directory(pcs, module, mapping, dbg, nDbg);
|
||||
}
|
||||
|
||||
return sym_type;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* pe_load_export_debug_info
|
||||
*/
|
||||
static SYM_TYPE pe_load_export_debug_info(const struct process* pcs,
|
||||
struct module* module,
|
||||
const void* mapping, IMAGE_NT_HEADERS* nth)
|
||||
{
|
||||
char buffer[512];
|
||||
unsigned int i;
|
||||
IMAGE_DATA_DIRECTORY* dir;
|
||||
DWORD base = module->module.BaseOfImage;
|
||||
ADDRESS addr;
|
||||
|
||||
addr.Mode = AddrModeFlat;
|
||||
addr.Segment = 0;
|
||||
|
||||
#if 0
|
||||
/* Add start of DLL (better use the (yet unimplemented) Exe SymTag for this) */
|
||||
/* FIXME: module.ModuleName isn't correctly set yet if it's passed in SymLoadModule */
|
||||
symt_new_public(module, NULL, module->module.ModuleName, base, 0,
|
||||
TRUE /* FIXME */, TRUE /* FIXME */);
|
||||
#endif
|
||||
|
||||
/* Add entry point */
|
||||
snprintf(buffer, sizeof(buffer), "%s.EntryPoint", module->module.ModuleName);
|
||||
symt_new_public(module, NULL, buffer,
|
||||
base + nth->OptionalHeader.AddressOfEntryPoint, 0,
|
||||
TRUE /* FIXME */, TRUE /* FIXME */);
|
||||
|
||||
#if 0
|
||||
IMAGE_SECTION_HEADER* section;
|
||||
/* Add start of sections */
|
||||
section = (IMAGE_SECTION_HEADER*)
|
||||
((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
|
||||
for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
|
||||
{
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s",
|
||||
module->module.ModuleName, section->Name);
|
||||
symt_new_public(module, NULL, buffer, base + section->VirtualAddress, 0,
|
||||
TRUE /* FIXME */, TRUE /* FIXME */);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Add exported functions */
|
||||
if ((dir = RtlImageDirectoryEntryToData((void*)mapping, TRUE,
|
||||
IMAGE_DIRECTORY_ENTRY_EXPORT, NULL)))
|
||||
{
|
||||
IMAGE_EXPORT_DIRECTORY* exports;
|
||||
WORD* ordinals = NULL;
|
||||
void** functions = NULL;
|
||||
DWORD* names = NULL;
|
||||
unsigned int j;
|
||||
|
||||
exports = (void*)((char*)mapping + dir->VirtualAddress);
|
||||
functions = (void*)((char*)mapping + exports->AddressOfFunctions);
|
||||
ordinals = (void*)((char*)mapping + exports->AddressOfNameOrdinals);
|
||||
names = (void*)((char*)mapping + exports->AddressOfNames);
|
||||
|
||||
for (i = 0; i < exports->NumberOfNames; i++)
|
||||
{
|
||||
if (!names[i]) continue;
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s",
|
||||
module->module.ModuleName, (char*)base + names[i]);
|
||||
symt_new_public(module, NULL, buffer,
|
||||
base + (DWORD)functions[ordinals[i]], 0,
|
||||
TRUE /* FIXME */, TRUE /* FIXME */);
|
||||
}
|
||||
|
||||
for (i = 0; i < exports->NumberOfFunctions; i++)
|
||||
{
|
||||
if (!functions[i]) continue;
|
||||
/* Check if we already added it with a name */
|
||||
for (j = 0; j < exports->NumberOfNames; j++)
|
||||
if ((ordinals[j] == i) && names[j]) break;
|
||||
if (j < exports->NumberOfNames) continue;
|
||||
snprintf(buffer, sizeof(buffer), "%s.%ld",
|
||||
module->module.ModuleName, i + exports->Base);
|
||||
symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 0,
|
||||
TRUE /* FIXME */, TRUE /* FIXME */);
|
||||
}
|
||||
}
|
||||
/* no real debug info, only entry points */
|
||||
return module->module.SymType = SymExport;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* pe_load_debug_info
|
||||
*
|
||||
*/
|
||||
SYM_TYPE pe_load_debug_info(const struct process* pcs, struct module* module)
|
||||
{
|
||||
SYM_TYPE sym_type = -1;
|
||||
HANDLE hFile;
|
||||
HANDLE hMap;
|
||||
void* mapping;
|
||||
IMAGE_NT_HEADERS* nth;
|
||||
|
||||
hFile = CreateFileA(module->module.LoadedImageName, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) return -1;
|
||||
if ((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0)
|
||||
{
|
||||
if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
|
||||
{
|
||||
nth = RtlImageNtHeader(mapping);
|
||||
|
||||
if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
|
||||
{
|
||||
sym_type = pe_load_stabs(pcs, module, mapping, nth);
|
||||
if (sym_type <= SymNone)
|
||||
sym_type = pe_load_msc_debug_info(pcs, module, mapping, nth);
|
||||
/* if we still have no debug info (we could only get SymExport at this
|
||||
* point), then do the SymExport except if we have an ELF container,
|
||||
* in which case we'll rely on the export's on the ELF side
|
||||
*/
|
||||
}
|
||||
if (sym_type <= SymNone && !module_get_debug(pcs, module))
|
||||
sym_type = pe_load_export_debug_info(pcs, module, mapping, nth);
|
||||
UnmapViewOfFile(mapping);
|
||||
}
|
||||
CloseHandle(hMap);
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
|
||||
module->module.SymType = (sym_type >= SymNone) ? sym_type : SymNone;
|
||||
return sym_type;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* pe_load_module
|
||||
*
|
||||
*/
|
||||
struct module* pe_load_module(struct process* pcs, char* name,
|
||||
HANDLE hFile, DWORD base, DWORD size)
|
||||
{
|
||||
struct module* module = NULL;
|
||||
BOOL opened = FALSE;
|
||||
HANDLE hMap;
|
||||
void* mapping;
|
||||
char loaded_name[MAX_PATH];
|
||||
|
||||
loaded_name[0] = '\0';
|
||||
if (!hFile)
|
||||
{
|
||||
if (!name)
|
||||
{
|
||||
/* FIXME SetLastError */
|
||||
return NULL;
|
||||
}
|
||||
if ((hFile = FindExecutableImage(name, NULL, loaded_name)) == NULL)
|
||||
return NULL;
|
||||
opened = TRUE;
|
||||
}
|
||||
else if (name) strcpy(loaded_name, name);
|
||||
else if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
|
||||
FIXME("Trouble ahead (no module name passed in deferred mode)\n");
|
||||
if ((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0)
|
||||
{
|
||||
if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
|
||||
{
|
||||
IMAGE_NT_HEADERS* nth = RtlImageNtHeader(mapping);
|
||||
|
||||
if (nth)
|
||||
{
|
||||
if (!base) base = nth->OptionalHeader.ImageBase;
|
||||
if (!size) size = nth->OptionalHeader.SizeOfImage;
|
||||
|
||||
module = module_new(pcs, loaded_name, DMT_PE, base, size,
|
||||
nth->FileHeader.TimeDateStamp,
|
||||
nth->OptionalHeader.CheckSum);
|
||||
if (module)
|
||||
{
|
||||
module->module.SymType = (dbghelp_options & SYMOPT_DEFERRED_LOADS) ?
|
||||
SymDeferred : pe_load_debug_info(pcs, module);
|
||||
}
|
||||
}
|
||||
UnmapViewOfFile(mapping);
|
||||
}
|
||||
CloseHandle(hMap);
|
||||
}
|
||||
if (opened) CloseHandle(hFile);
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* pe_load_module_from_pcs
|
||||
*
|
||||
*/
|
||||
struct module* pe_load_module_from_pcs(struct process* pcs, const char* name,
|
||||
const char* mod_name, DWORD base, DWORD size)
|
||||
{
|
||||
struct module* module;
|
||||
const char* ptr;
|
||||
|
||||
if ((module = module_find_by_name(pcs, name, DMT_PE))) return module;
|
||||
if (mod_name) ptr = mod_name;
|
||||
else
|
||||
{
|
||||
for (ptr = name + strlen(name) - 1; ptr >= name; ptr--)
|
||||
{
|
||||
if (*ptr == '/' || *ptr == '\\')
|
||||
{
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ptr && (module = module_find_by_name(pcs, ptr, DMT_PE))) return module;
|
||||
if (base && pcs->dbg_hdr_addr)
|
||||
{
|
||||
IMAGE_DOS_HEADER dos;
|
||||
IMAGE_NT_HEADERS nth;
|
||||
|
||||
if (read_mem(pcs->handle, base, &dos, sizeof(dos)) &&
|
||||
dos.e_magic == IMAGE_DOS_SIGNATURE &&
|
||||
read_mem(pcs->handle, base + dos.e_lfanew, &nth, sizeof(nth)) &&
|
||||
nth.Signature == IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
if (!size) size = nth.OptionalHeader.SizeOfImage;
|
||||
module = module_new(pcs, name, DMT_PE, base, size,
|
||||
nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum);
|
||||
}
|
||||
}
|
||||
return module;
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* File source.c - source files management
|
||||
*
|
||||
* Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
/******************************************************************
|
||||
* source_find
|
||||
*
|
||||
* check whether a source file has already been stored
|
||||
*/
|
||||
static unsigned source_find(const struct module* module, const char* name)
|
||||
{
|
||||
char* ptr = module->sources;
|
||||
|
||||
while (*ptr)
|
||||
{
|
||||
if (strcmp(ptr, name) == 0) return ptr - module->sources;
|
||||
ptr += strlen(ptr) + 1;
|
||||
}
|
||||
return (unsigned)-1;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* source_new
|
||||
*
|
||||
* checks if source exists. if not, add it
|
||||
*/
|
||||
unsigned source_new(struct module* module, const char* name)
|
||||
{
|
||||
int len;
|
||||
unsigned ret;
|
||||
|
||||
if (!name) return (unsigned)-1;
|
||||
if (module->sources && (ret = source_find(module, name)) != (unsigned)-1)
|
||||
return ret;
|
||||
|
||||
len = strlen(name) + 1;
|
||||
if (module->sources_used + len + 1 > module->sources_alloc)
|
||||
{
|
||||
/* Alloc by block of 256 bytes */
|
||||
module->sources_alloc = (module->sources_used + len + 1 + 255) & ~255;
|
||||
if (!module->sources)
|
||||
module->sources = HeapAlloc(GetProcessHeap(), 0, module->sources_alloc);
|
||||
else
|
||||
module->sources = HeapReAlloc(GetProcessHeap(), 0, module->sources,
|
||||
module->sources_alloc);
|
||||
}
|
||||
ret = module->sources_used;
|
||||
strcpy(module->sources + module->sources_used, name);
|
||||
module->sources_used += len;
|
||||
module->sources[module->sources_used] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* source_get
|
||||
*
|
||||
* returns a stored source file name
|
||||
*/
|
||||
const char* source_get(const struct module* module, unsigned idx)
|
||||
{
|
||||
if (idx == -1) return "";
|
||||
assert(module->sources);
|
||||
return module->sources + idx;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymEnumSourceFiles (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG ModBase, LPSTR Mask,
|
||||
PSYM_ENUMSOURCFILES_CALLBACK cbSrcFiles,
|
||||
void* UserContext)
|
||||
{
|
||||
struct process* pcs;
|
||||
struct module* module;
|
||||
SOURCEFILE sf;
|
||||
char* ptr;
|
||||
|
||||
if (!cbSrcFiles) return FALSE;
|
||||
pcs = process_find_by_handle(hProcess);
|
||||
if (!pcs) return FALSE;
|
||||
|
||||
if (ModBase)
|
||||
{
|
||||
module = module_find_by_addr(pcs, ModBase, DMT_UNKNOWN);
|
||||
if (!(module = module_get_debug(pcs, module))) return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Mask[0] == '!')
|
||||
{
|
||||
module = module_find_by_name(pcs, Mask + 1, DMT_UNKNOWN);
|
||||
if (!(module = module_get_debug(pcs, module))) return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("Unsupported yet (should get info from current context)\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (!module->sources) return FALSE;
|
||||
for (ptr = module->sources; *ptr; ptr += strlen(ptr) + 1)
|
||||
{
|
||||
/* FIXME: not using Mask */
|
||||
sf.ModBase = ModBase;
|
||||
sf.FileName = ptr;
|
||||
if (!cbSrcFiles(&sf, UserContext)) break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Stack walking
|
||||
*
|
||||
* Copyright 1995 Alexandre Julliard
|
||||
* Copyright 1996 Eric Youngdale
|
||||
* Copyright 1999 Ove Kåven
|
||||
* Copyright 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
#include "winreg.h"
|
||||
#include "ntstatus.h"
|
||||
#include "thread.h" /* FIXME: must be included before winternl.h */
|
||||
#include "winternl.h"
|
||||
#include "wine/debug.h"
|
||||
#include "stackframe.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done};
|
||||
|
||||
static const char* wine_dbgstr_addr(const ADDRESS* addr)
|
||||
{
|
||||
if (!addr) return "(null)";
|
||||
switch (addr->Mode)
|
||||
{
|
||||
case AddrModeFlat:
|
||||
return wine_dbg_sprintf("flat<%08lx>", addr->Offset);
|
||||
case AddrMode1616:
|
||||
return wine_dbg_sprintf("1616<%04x:%04lx>", addr->Segment, addr->Offset);
|
||||
case AddrMode1632:
|
||||
return wine_dbg_sprintf("1632<%04x:%08lx>", addr->Segment, addr->Offset);
|
||||
case AddrModeReal:
|
||||
return wine_dbg_sprintf("real<%04x:%04lx>", addr->Segment, addr->Offset);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* indexes in Reserved array */
|
||||
#define __CurrentMode 0
|
||||
#define __CurrentSwitch 1
|
||||
#define __NextSwitch 2
|
||||
|
||||
#define curr_mode (frame->Reserved[__CurrentMode])
|
||||
#define curr_switch (frame->Reserved[__CurrentSwitch])
|
||||
#define next_switch (frame->Reserved[__NextSwitch])
|
||||
|
||||
/***********************************************************************
|
||||
* StackWalk (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
|
||||
LPSTACKFRAME frame, LPVOID _ctx,
|
||||
PREAD_PROCESS_MEMORY_ROUTINE f_read_mem,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
|
||||
PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
|
||||
PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr)
|
||||
{
|
||||
CONTEXT* ctx = (CONTEXT*)_ctx;
|
||||
STACK32FRAME frame32;
|
||||
STACK16FRAME frame16;
|
||||
char ch;
|
||||
ADDRESS tmp;
|
||||
DWORD p;
|
||||
WORD val;
|
||||
BOOL do_switch;
|
||||
|
||||
TRACE("(%ld, %p, %p, %p, %p, %p, %p, %p, %p)\n",
|
||||
MachineType, hProcess, hThread, frame, _ctx,
|
||||
f_read_mem, FunctionTableAccessRoutine,
|
||||
GetModuleBaseRoutine, f_xlat_adr);
|
||||
|
||||
if (MachineType != IMAGE_FILE_MACHINE_I386)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
if (curr_mode >= stm_done) return FALSE;
|
||||
|
||||
if (!f_read_mem) f_read_mem = ReadProcessMemory;
|
||||
if (!f_xlat_adr) f_xlat_adr = addr_to_linear;
|
||||
|
||||
TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08lx nSwitch=%08lx\n",
|
||||
wine_dbgstr_addr(&frame->AddrPC),
|
||||
wine_dbgstr_addr(&frame->AddrFrame),
|
||||
wine_dbgstr_addr(&frame->AddrReturn),
|
||||
wine_dbgstr_addr(&frame->AddrStack),
|
||||
curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
|
||||
curr_switch, next_switch);
|
||||
|
||||
if (curr_mode == stm_start)
|
||||
{
|
||||
THREAD_BASIC_INFORMATION info;
|
||||
|
||||
/* Init done */
|
||||
curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ?
|
||||
stm_32bit : stm_16bit;
|
||||
|
||||
/* Get the current ESP (don't know if this is valid) */
|
||||
if (ctx)
|
||||
{
|
||||
frame->AddrStack.Segment = 0;
|
||||
frame->AddrStack.Offset = ctx->Esp;
|
||||
frame->AddrStack.Mode = AddrModeFlat;
|
||||
}
|
||||
/* cur_switch holds address of curr_stack's field in TEB in debuggee
|
||||
* address space
|
||||
*/
|
||||
if (NtQueryInformationThread(hThread, ThreadBasicInformation, &info,
|
||||
sizeof(info), NULL) != STATUS_SUCCESS)
|
||||
goto done_err;
|
||||
curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, cur_stack);
|
||||
if (!f_read_mem(hProcess, (void*)curr_switch, &next_switch,
|
||||
sizeof(next_switch), NULL))
|
||||
{
|
||||
WARN("Can't read TEB:cur_stack\n");
|
||||
goto done_err;
|
||||
}
|
||||
if (curr_mode == stm_16bit)
|
||||
{
|
||||
if (!f_read_mem(hProcess, (void*)next_switch, &frame32,
|
||||
sizeof(frame32), NULL))
|
||||
{
|
||||
WARN("Bad stack frame 0x%08lx\n", next_switch);
|
||||
goto done_err;
|
||||
}
|
||||
curr_switch = (DWORD)frame32.frame16;
|
||||
tmp.Mode = AddrMode1616;
|
||||
tmp.Segment = SELECTOROF(curr_switch);
|
||||
tmp.Offset = OFFSETOF(curr_switch);
|
||||
if (!f_read_mem(hProcess, (void*)f_xlat_adr(hProcess, hThread, &tmp),
|
||||
&ch, sizeof(ch), NULL))
|
||||
curr_switch = 0xFFFFFFFF;
|
||||
frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrMode1616;
|
||||
/* "pop up" previous BP value */
|
||||
if (!f_read_mem(hProcess, (void*)frame->AddrFrame.Offset,
|
||||
&val, sizeof(WORD), NULL))
|
||||
goto done_err;
|
||||
frame->AddrFrame.Offset = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp.Mode = AddrMode1616;
|
||||
tmp.Segment = SELECTOROF(next_switch);
|
||||
tmp.Offset = OFFSETOF(next_switch);
|
||||
p = f_xlat_adr(hProcess, hThread, &tmp);
|
||||
if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
|
||||
{
|
||||
WARN("Bad stack frame 0x%08lx\n", p);
|
||||
goto done_err;
|
||||
}
|
||||
curr_switch = (DWORD)frame16.frame32;
|
||||
|
||||
if (!f_read_mem(hProcess, (void*)curr_switch, &ch, sizeof(ch), NULL))
|
||||
curr_switch = 0xFFFFFFFF;
|
||||
frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrModeFlat;
|
||||
/* "pop up" previous EBP value */
|
||||
if (!f_read_mem(hProcess, (void*)frame->AddrFrame.Offset,
|
||||
&frame->AddrFrame.Offset, sizeof(DWORD), NULL))
|
||||
goto done_err;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (frame->AddrFrame.Offset == 0) goto done_err;
|
||||
if (frame->AddrFrame.Mode == AddrModeFlat)
|
||||
{
|
||||
assert(curr_mode == stm_32bit);
|
||||
do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(curr_mode == stm_16bit);
|
||||
do_switch = OFFSETOF(curr_switch) &&
|
||||
frame->AddrFrame.Segment == SELECTOROF(curr_switch) &&
|
||||
frame->AddrFrame.Offset >= OFFSETOF(curr_switch);
|
||||
}
|
||||
|
||||
if (do_switch)
|
||||
{
|
||||
if (curr_mode == stm_16bit)
|
||||
{
|
||||
if (!f_read_mem(hProcess, (void*)next_switch, &frame32,
|
||||
sizeof(frame32), NULL))
|
||||
{
|
||||
WARN("Bad stack frame 0x%08lx\n", next_switch);
|
||||
goto done_err;
|
||||
}
|
||||
|
||||
frame->AddrPC.Mode = AddrModeFlat;
|
||||
frame->AddrPC.Segment = 0;
|
||||
frame->AddrPC.Offset = frame32.retaddr;
|
||||
frame->AddrFrame.Mode = AddrModeFlat;
|
||||
frame->AddrFrame.Segment = 0;
|
||||
frame->AddrFrame.Offset = frame32.ebp;
|
||||
|
||||
frame->AddrStack.Mode = AddrModeFlat;
|
||||
frame->AddrStack.Segment = 0;
|
||||
frame->AddrReturn.Mode = AddrModeFlat;
|
||||
frame->AddrReturn.Segment = 0;
|
||||
|
||||
next_switch = curr_switch;
|
||||
tmp.Mode = AddrMode1616;
|
||||
tmp.Segment = SELECTOROF(next_switch);
|
||||
tmp.Offset = OFFSETOF(next_switch);
|
||||
p = f_xlat_adr(hProcess, hThread, &tmp);
|
||||
|
||||
if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
|
||||
{
|
||||
WARN("Bad stack frame 0x%08lx\n", p);
|
||||
goto done_err;
|
||||
}
|
||||
curr_switch = (DWORD)frame16.frame32;
|
||||
curr_mode = stm_32bit;
|
||||
if (!f_read_mem(hProcess, (void*)curr_switch, &ch, sizeof(ch), NULL))
|
||||
curr_switch = 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp.Mode = AddrMode1616;
|
||||
tmp.Segment = SELECTOROF(next_switch);
|
||||
tmp.Offset = OFFSETOF(next_switch);
|
||||
p = f_xlat_adr(hProcess, hThread, &tmp);
|
||||
|
||||
if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
|
||||
{
|
||||
WARN("Bad stack frame 0x%08lx\n", p);
|
||||
goto done_err;
|
||||
}
|
||||
|
||||
TRACE("Got a 16 bit stack switch:"
|
||||
"\n\tframe32: %08lx"
|
||||
"\n\tedx:%08lx ecx:%08lx ebp:%08lx"
|
||||
"\n\tds:%04x es:%04x fs:%04x gs:%04x"
|
||||
"\n\tcall_from_ip:%08lx module_cs:%04lx relay=%08lx"
|
||||
"\n\tentry_ip:%04x entry_point:%08lx"
|
||||
"\n\tbp:%04x ip:%04x cs:%04x\n",
|
||||
(unsigned long)frame16.frame32,
|
||||
frame16.edx, frame16.ecx, frame16.ebp,
|
||||
frame16.ds, frame16.es, frame16.fs, frame16.gs,
|
||||
frame16.callfrom_ip, frame16.module_cs, frame16.relay,
|
||||
frame16.entry_ip, frame16.entry_point,
|
||||
frame16.bp, frame16.ip, frame16.cs);
|
||||
|
||||
|
||||
frame->AddrPC.Mode = AddrMode1616;
|
||||
frame->AddrPC.Segment = frame16.cs;
|
||||
frame->AddrPC.Offset = frame16.ip;
|
||||
|
||||
frame->AddrFrame.Mode = AddrMode1616;
|
||||
frame->AddrFrame.Segment = SELECTOROF(next_switch);
|
||||
frame->AddrFrame.Offset = frame16.bp;
|
||||
|
||||
frame->AddrStack.Mode = AddrMode1616;
|
||||
frame->AddrStack.Segment = SELECTOROF(next_switch);
|
||||
|
||||
frame->AddrReturn.Mode = AddrMode1616;
|
||||
frame->AddrReturn.Segment = frame16.cs;
|
||||
|
||||
next_switch = curr_switch;
|
||||
if (!f_read_mem(hProcess, (void*)next_switch, &frame32, sizeof(frame32),
|
||||
NULL))
|
||||
{
|
||||
WARN("Bad stack frame 0x%08lx\n", next_switch);
|
||||
goto done_err;
|
||||
}
|
||||
curr_switch = (DWORD)frame32.frame16;
|
||||
tmp.Mode = AddrMode1616;
|
||||
tmp.Segment = SELECTOROF(curr_switch);
|
||||
tmp.Offset = OFFSETOF(curr_switch);
|
||||
|
||||
if (!f_read_mem(hProcess, (void*)f_xlat_adr(hProcess, hThread, &tmp),
|
||||
&ch, sizeof(ch), NULL))
|
||||
curr_switch = 0xFFFFFFFF;
|
||||
curr_mode = stm_16bit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frame->AddrPC = frame->AddrReturn;
|
||||
if (curr_mode == stm_16bit)
|
||||
{
|
||||
frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD);
|
||||
/* "pop up" previous BP value */
|
||||
if (!f_read_mem(hProcess,
|
||||
(void*)f_xlat_adr(hProcess, hThread, &frame->AddrFrame),
|
||||
&val, sizeof(WORD), NULL))
|
||||
goto done_err;
|
||||
frame->AddrFrame.Offset = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD);
|
||||
/* "pop up" previous EBP value */
|
||||
if (!f_read_mem(hProcess, (void*)frame->AddrFrame.Offset,
|
||||
&frame->AddrFrame.Offset, sizeof(DWORD), NULL))
|
||||
goto done_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_mode == stm_16bit)
|
||||
{
|
||||
int i;
|
||||
|
||||
p = f_xlat_adr(hProcess, hThread, &frame->AddrFrame);
|
||||
if (!f_read_mem(hProcess, (void*)(p + sizeof(WORD)), &val, sizeof(WORD), NULL))
|
||||
goto done_err;
|
||||
frame->AddrReturn.Offset = val;
|
||||
/* get potential cs if a far call was used */
|
||||
if (!f_read_mem(hProcess, (void*)(p + 2 * sizeof(WORD)),
|
||||
&val, sizeof(WORD), NULL))
|
||||
goto done_err;
|
||||
if (frame->AddrFrame.Offset & 1)
|
||||
frame->AddrReturn.Segment = val; /* far call assumed */
|
||||
else
|
||||
{
|
||||
/* not explicitly marked as far call,
|
||||
* but check whether it could be anyway
|
||||
*/
|
||||
if ((val & 7) == 7 && val != frame->AddrReturn.Segment)
|
||||
{
|
||||
LDT_ENTRY le;
|
||||
|
||||
if (GetThreadSelectorEntry(hThread, val, &le) &&
|
||||
(le.HighWord.Bits.Type & 0x08)) /* code segment */
|
||||
{
|
||||
/* it is very uncommon to push a code segment cs as
|
||||
* a parameter, so this should work in most cases
|
||||
*/
|
||||
frame->AddrReturn.Segment = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
frame->AddrFrame.Offset &= ~1;
|
||||
/* we "pop" paramaters as 16 bit entities... of course, this won't
|
||||
* work if the parameter is in fact bigger than 16bit, but
|
||||
* there's no way to know that here
|
||||
*/
|
||||
for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
|
||||
{
|
||||
f_read_mem(hProcess, (void*)(p + (2 + i) * sizeof(WORD)),
|
||||
&val, sizeof(val), NULL);
|
||||
frame->Params[i] = val;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!f_read_mem(hProcess,
|
||||
(void*)(frame->AddrFrame.Offset + sizeof(DWORD)),
|
||||
&frame->AddrReturn.Offset, sizeof(DWORD), NULL))
|
||||
goto done_err;
|
||||
f_read_mem(hProcess,
|
||||
(void*)(frame->AddrFrame.Offset + 2 * sizeof(DWORD)),
|
||||
frame->Params, sizeof(frame->Params), NULL);
|
||||
}
|
||||
|
||||
frame->Far = FALSE;
|
||||
frame->Virtual = FALSE;
|
||||
|
||||
TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08lx nSwitch=%08lx\n",
|
||||
wine_dbgstr_addr(&frame->AddrPC),
|
||||
wine_dbgstr_addr(&frame->AddrFrame),
|
||||
wine_dbgstr_addr(&frame->AddrReturn),
|
||||
wine_dbgstr_addr(&frame->AddrStack),
|
||||
curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
|
||||
curr_switch, next_switch);
|
||||
|
||||
return TRUE;
|
||||
done_err:
|
||||
curr_mode = stm_done;
|
||||
return FALSE;
|
||||
}
|
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* Various storage structures (pool allocation, vector, hash table)
|
||||
*
|
||||
* Copyright (C) 1993, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
#ifdef USE_STATS
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
struct pool_arena
|
||||
{
|
||||
struct pool_arena* next;
|
||||
char* current;
|
||||
};
|
||||
|
||||
void pool_init(struct pool* a, unsigned arena_size)
|
||||
{
|
||||
a->arena_size = arena_size;
|
||||
a->first = NULL;
|
||||
}
|
||||
|
||||
void pool_destroy(struct pool* pool)
|
||||
{
|
||||
struct pool_arena* arena;
|
||||
struct pool_arena* next;
|
||||
|
||||
#ifdef USE_STATS
|
||||
unsigned alloc, used, num;
|
||||
|
||||
for (alloc = used = num = 0, arena = pool->first; arena; arena = arena->next)
|
||||
{
|
||||
alloc += pool->arena_size;
|
||||
used += arena->current - (char*)arena;
|
||||
num++;
|
||||
}
|
||||
FIXME("STATS: pool %p has allocated %u kbytes, used %u kbytes in %u arenas,\n"
|
||||
"\t\t\t\tnon-allocation ratio: %.2f%%\n",
|
||||
pool, alloc >> 10, used >> 10, num, 100.0 - (float)used / (float)alloc * 100.0);
|
||||
#endif
|
||||
|
||||
for (arena = pool->first; arena; arena = next)
|
||||
{
|
||||
next = arena->next;
|
||||
HeapFree(GetProcessHeap(), 0, arena);
|
||||
}
|
||||
pool_init(pool, 0);
|
||||
}
|
||||
|
||||
void* pool_alloc(struct pool* pool, unsigned len)
|
||||
{
|
||||
struct pool_arena** parena;
|
||||
struct pool_arena* arena;
|
||||
void* ret;
|
||||
|
||||
len = (len + 3) & ~3; /* round up size on DWORD boundary */
|
||||
assert(sizeof(struct pool_arena) + len <= pool->arena_size && len);
|
||||
|
||||
for (parena = &pool->first; *parena; parena = &(*parena)->next)
|
||||
{
|
||||
if ((char*)(*parena) + pool->arena_size - (*parena)->current >= len)
|
||||
{
|
||||
ret = (*parena)->current;
|
||||
(*parena)->current += len;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
arena = HeapAlloc(GetProcessHeap(), 0, pool->arena_size);
|
||||
if (!arena) {FIXME("OOM\n");return NULL;}
|
||||
|
||||
*parena = arena;
|
||||
|
||||
ret = (char*)arena + sizeof(*arena);
|
||||
arena->next = NULL;
|
||||
arena->current = (char*)ret + len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct pool_arena* pool_is_last(struct pool* pool, void* p, unsigned old_size)
|
||||
{
|
||||
struct pool_arena* arena;
|
||||
|
||||
for (arena = pool->first; arena; arena = arena->next)
|
||||
{
|
||||
if (arena->current == (char*)p + old_size) return arena;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* pool_realloc(struct pool* pool, void* p, unsigned old_size, unsigned new_size)
|
||||
{
|
||||
struct pool_arena* arena;
|
||||
void* new;
|
||||
|
||||
if ((arena = pool_is_last(pool, p, old_size)) &&
|
||||
(char*)p + new_size <= (char*)arena + pool->arena_size)
|
||||
{
|
||||
arena->current = (char*)p + new_size;
|
||||
return p;
|
||||
}
|
||||
if ((new = pool_alloc(pool, new_size)) && old_size)
|
||||
memcpy(new, p, min(old_size, new_size));
|
||||
return new;
|
||||
}
|
||||
|
||||
char* pool_strdup(struct pool* pool, const char* str)
|
||||
{
|
||||
char* ret;
|
||||
if ((ret = pool_alloc(pool, strlen(str) + 1))) strcpy(ret, str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void vector_init(struct vector* v, unsigned esz, unsigned bucket_sz)
|
||||
{
|
||||
v->buckets = NULL;
|
||||
/* align size on DWORD boundaries */
|
||||
v->elt_size = (esz + 3) & ~3;
|
||||
switch (bucket_sz)
|
||||
{
|
||||
case 2: v->shift = 1; break;
|
||||
case 4: v->shift = 2; break;
|
||||
case 8: v->shift = 3; break;
|
||||
case 16: v->shift = 4; break;
|
||||
case 32: v->shift = 5; break;
|
||||
case 64: v->shift = 6; break;
|
||||
case 128: v->shift = 7; break;
|
||||
case 256: v->shift = 8; break;
|
||||
case 512: v->shift = 9; break;
|
||||
case 1024: v->shift = 10; break;
|
||||
default: assert(0);
|
||||
}
|
||||
v->num_buckets = 0;
|
||||
v->num_elts = 0;
|
||||
}
|
||||
|
||||
unsigned vector_length(const struct vector* v)
|
||||
{
|
||||
return v->num_elts;
|
||||
}
|
||||
|
||||
void* vector_at(const struct vector* v, unsigned pos)
|
||||
{
|
||||
unsigned o;
|
||||
|
||||
if (pos >= v->num_elts) return NULL;
|
||||
o = pos & ((1 << v->shift) - 1);
|
||||
return (char*)v->buckets[pos >> v->shift] + o * v->elt_size;
|
||||
}
|
||||
|
||||
void* vector_add(struct vector* v, struct pool* pool)
|
||||
{
|
||||
unsigned ncurr = v->num_elts++;
|
||||
|
||||
/* check that we don't wrap around */
|
||||
assert(v->num_elts > ncurr);
|
||||
if (ncurr == (v->num_buckets << v->shift))
|
||||
{
|
||||
v->buckets = pool_realloc(pool, v->buckets,
|
||||
v->num_buckets * sizeof(void*),
|
||||
(v->num_buckets + 1) * sizeof(void*));
|
||||
v->buckets[v->num_buckets] = pool_alloc(pool, v->elt_size << v->shift);
|
||||
return v->buckets[v->num_buckets++];
|
||||
}
|
||||
return vector_at(v, ncurr);
|
||||
}
|
||||
|
||||
static unsigned vector_position(const struct vector* v, const void* elt)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < v->num_buckets; i++)
|
||||
{
|
||||
if (v->buckets[i] <= elt &&
|
||||
(const char*)elt < (const char*)v->buckets[i] + (v->elt_size << v->shift))
|
||||
{
|
||||
return (i << v->shift) +
|
||||
((const char*)elt - (const char*)v->buckets[i]) / v->elt_size;
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void* vector_iter_up(const struct vector* v, void* elt)
|
||||
{
|
||||
unsigned pos;
|
||||
|
||||
if (!elt) return vector_at(v, 0);
|
||||
pos = vector_position(v, elt) + 1;
|
||||
if (pos >= vector_length(v)) return NULL;
|
||||
return vector_at(v, pos);
|
||||
}
|
||||
|
||||
void* vector_iter_down(const struct vector* v, void* elt)
|
||||
{
|
||||
unsigned pos;
|
||||
if (!elt) return vector_at(v, vector_length(v) - 1);
|
||||
pos = vector_position(v, elt);
|
||||
if (pos == 0) return NULL;
|
||||
return vector_at(v, pos - 1);
|
||||
}
|
||||
|
||||
unsigned hash_table_hash(const char* name, unsigned num_buckets)
|
||||
{
|
||||
unsigned hash = 0;
|
||||
while (*name)
|
||||
{
|
||||
hash += *name++;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
return hash % num_buckets;
|
||||
}
|
||||
|
||||
void hash_table_init(struct pool* pool, struct hash_table* ht, unsigned num_buckets)
|
||||
{
|
||||
ht->buckets = pool_alloc(pool, num_buckets * sizeof(struct hash_table_elt*));
|
||||
assert(ht->buckets);
|
||||
ht->num_buckets = num_buckets;
|
||||
memset(ht->buckets, 0, num_buckets * sizeof(struct hash_table_elt*));
|
||||
}
|
||||
|
||||
void hash_table_destroy(struct hash_table* ht)
|
||||
{
|
||||
#if defined(USE_STATS)
|
||||
int i;
|
||||
unsigned len;
|
||||
unsigned num = 0, min = 0xffffffff, max = 0, sq = 0;
|
||||
struct hash_table_elt* elt;
|
||||
double mean, variance;
|
||||
|
||||
for (i = 0; i < ht->num_buckets; i++)
|
||||
{
|
||||
for (len = 0, elt = ht->buckets[i]; elt; elt = elt->next) len++;
|
||||
if (len < min) min = len;
|
||||
if (len > max) max = len;
|
||||
num += len;
|
||||
sq += len * len;
|
||||
}
|
||||
mean = (double)num / ht->num_buckets;
|
||||
variance = (double)sq / ht->num_buckets - mean * mean;
|
||||
FIXME("STATS: elts[num:%-4u size:%u mean:%f] buckets[min:%-4u variance:%+f max:%-4u]\n",
|
||||
num, ht->num_buckets, mean, min, variance, max);
|
||||
#if 1
|
||||
for (i = 0; i < ht->num_buckets; i++)
|
||||
{
|
||||
for (len = 0, elt = ht->buckets[i]; elt; elt = elt->next) len++;
|
||||
if (len == max)
|
||||
{
|
||||
FIXME("Longuest bucket:\n");
|
||||
for (elt = ht->buckets[i]; elt; elt = elt->next)
|
||||
FIXME("\t%s\n", elt->name);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void hash_table_add(struct hash_table* ht, struct hash_table_elt* elt)
|
||||
{
|
||||
unsigned hash = hash_table_hash(elt->name, ht->num_buckets);
|
||||
|
||||
elt->next = ht->buckets[hash];
|
||||
ht->buckets[hash] = elt;
|
||||
}
|
||||
|
||||
void* hash_table_find(const struct hash_table* ht, const char* name)
|
||||
{
|
||||
unsigned hash = hash_table_hash(name, ht->num_buckets);
|
||||
struct hash_table_elt* elt;
|
||||
|
||||
for (elt = ht->buckets[hash]; elt; elt = elt->next)
|
||||
if (!strcmp(name, elt->name)) return elt;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hash_table_iter_init(const struct hash_table* ht,
|
||||
struct hash_table_iter* hti, const char* name)
|
||||
{
|
||||
hti->ht = ht;
|
||||
if (name)
|
||||
{
|
||||
hti->last = hash_table_hash(name, ht->num_buckets);
|
||||
hti->index = hti->last - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hti->last = ht->num_buckets - 1;
|
||||
hti->index = -1;
|
||||
}
|
||||
hti->element = NULL;
|
||||
}
|
||||
|
||||
void* hash_table_iter_up(struct hash_table_iter* hti)
|
||||
{
|
||||
if (hti->element) hti->element = hti->element->next;
|
||||
while (!hti->element && hti->index < hti->last)
|
||||
hti->element = hti->ht->buckets[++hti->index];
|
||||
return hti->element;
|
||||
}
|
|
@ -0,0 +1,999 @@
|
|||
/*
|
||||
* File symbol.c - management of symbols (lexical tree)
|
||||
*
|
||||
* Copyright (C) 1993, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <regex.h>
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symtype);
|
||||
|
||||
#define DLIT_OFFSET 0x00
|
||||
#define DLIT_FIRST 0x01
|
||||
#define DLIT_LAST 0x02
|
||||
#define DLIT_SOURCEFILE 0x04
|
||||
|
||||
struct line_info
|
||||
{
|
||||
unsigned long cookie : 3,
|
||||
line_number;
|
||||
union
|
||||
{
|
||||
unsigned long pc_offset;
|
||||
unsigned source_file;
|
||||
} u;
|
||||
};
|
||||
|
||||
inline static int cmp_addr(DWORD a1, DWORD a2)
|
||||
{
|
||||
if (a1 > a2) return 1;
|
||||
if (a1 < a2) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline static int cmp_sorttab_addr(const struct module* module, int idx, DWORD addr)
|
||||
{
|
||||
DWORD ref;
|
||||
|
||||
symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref);
|
||||
return cmp_addr(ref, addr);
|
||||
}
|
||||
|
||||
int symt_cmp_addr(const void* p1, const void* p2)
|
||||
{
|
||||
struct symt* sym1 = *(struct symt**)p1;
|
||||
struct symt* sym2 = *(struct symt**)p2;
|
||||
DWORD a1, a2;
|
||||
|
||||
symt_get_info(sym1, TI_GET_ADDRESS, &a1);
|
||||
symt_get_info(sym2, TI_GET_ADDRESS, &a2);
|
||||
return cmp_addr(a1, a2);
|
||||
}
|
||||
|
||||
struct symt_compiland* symt_new_compiland(struct module* module, const char* name)
|
||||
{
|
||||
struct symt_compiland* sym;
|
||||
|
||||
TRACE_(dbghelp_symtype)("Adding compiland symbol %s:%s\n",
|
||||
module->module.ModuleName, name);
|
||||
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
|
||||
{
|
||||
sym->symt.tag = SymTagCompiland;
|
||||
sym->source = source_new(module, name);
|
||||
vector_init(&sym->vchildren, sizeof(struct symt*), 32);
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
struct symt_public* symt_new_public(struct module* module,
|
||||
struct symt_compiland* compiland,
|
||||
const char* name,
|
||||
unsigned long address, unsigned size,
|
||||
BOOL in_code, BOOL is_func)
|
||||
{
|
||||
struct symt_public* sym;
|
||||
struct symt** p;
|
||||
|
||||
TRACE_(dbghelp_symtype)("Adding public symbol %s:%s @%lx\n",
|
||||
module->module.ModuleName, name, address);
|
||||
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
|
||||
{
|
||||
sym->symt.tag = SymTagPublicSymbol;
|
||||
sym->hash_elt.name = pool_strdup(&module->pool, name);
|
||||
hash_table_add(&module->ht_symbols, &sym->hash_elt);
|
||||
module->sortlist_valid = FALSE;
|
||||
sym->container = compiland ? &compiland->symt : NULL;
|
||||
sym->address = address;
|
||||
sym->size = size;
|
||||
sym->in_code = in_code;
|
||||
sym->is_function = is_func;
|
||||
if (compiland)
|
||||
{
|
||||
p = vector_add(&compiland->vchildren, &module->pool);
|
||||
*p = &sym->symt;
|
||||
}
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
struct symt_data* symt_new_global_variable(struct module* module,
|
||||
struct symt_compiland* compiland,
|
||||
const char* name, unsigned is_static,
|
||||
unsigned long addr, unsigned long size,
|
||||
struct symt* type)
|
||||
{
|
||||
struct symt_data* sym;
|
||||
struct symt** p;
|
||||
|
||||
TRACE_(dbghelp_symtype)("Adding global symbol %s:%s @%lx %p\n",
|
||||
module->module.ModuleName, name, addr, type);
|
||||
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
|
||||
{
|
||||
sym->symt.tag = SymTagData;
|
||||
sym->hash_elt.name = pool_strdup(&module->pool, name);
|
||||
hash_table_add(&module->ht_symbols, &sym->hash_elt);
|
||||
module->sortlist_valid = FALSE;
|
||||
sym->kind = is_static ? DataIsFileStatic : DataIsGlobal;
|
||||
sym->container = compiland ? &compiland->symt : NULL;
|
||||
sym->type = type;
|
||||
sym->location = LocIsStatic; /* FIXME */
|
||||
sym->u.address = addr;
|
||||
if (compiland)
|
||||
{
|
||||
p = vector_add(&compiland->vchildren, &module->pool);
|
||||
*p = &sym->symt;
|
||||
}
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
struct symt_function* symt_new_function(struct module* module,
|
||||
struct symt_compiland* compiland,
|
||||
const char* name,
|
||||
unsigned long addr, unsigned long size,
|
||||
struct symt* type)
|
||||
{
|
||||
struct symt_function* sym;
|
||||
struct symt** p;
|
||||
|
||||
TRACE_(dbghelp_symtype)("Adding global function %s:%s @%lx-%lx\n",
|
||||
module->module.ModuleName, name, addr, addr + size - 1);
|
||||
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
|
||||
{
|
||||
sym->symt.tag = SymTagFunction;
|
||||
sym->hash_elt.name = pool_strdup(&module->pool, name);
|
||||
hash_table_add(&module->ht_symbols, &sym->hash_elt);
|
||||
module->sortlist_valid = FALSE;
|
||||
sym->container = &compiland->symt;
|
||||
sym->addr = addr;
|
||||
sym->type = type;
|
||||
sym->size = size;
|
||||
sym->addr = addr;
|
||||
vector_init(&sym->vlines, sizeof(struct line_info), 64);
|
||||
vector_init(&sym->vchildren, sizeof(struct symt*), 8);
|
||||
if (compiland)
|
||||
{
|
||||
p = vector_add(&compiland->vchildren, &module->pool);
|
||||
*p = &sym->symt;
|
||||
}
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
void symt_add_func_line(struct module* module, struct symt_function* func,
|
||||
unsigned source_idx, int line_num, unsigned long offset)
|
||||
{
|
||||
struct line_info* dli;
|
||||
BOOL last_matches = FALSE;
|
||||
|
||||
if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;
|
||||
|
||||
TRACE_(dbghelp_symtype)("(%p)%s:%lx %s:%u\n",
|
||||
func, func->hash_elt.name, offset,
|
||||
source_get(module, source_idx), line_num);
|
||||
|
||||
assert(func->symt.tag == SymTagFunction);
|
||||
|
||||
dli = NULL;
|
||||
while ((dli = vector_iter_down(&func->vlines, dli)))
|
||||
{
|
||||
if (dli->cookie & DLIT_SOURCEFILE)
|
||||
{
|
||||
last_matches = (source_idx == dli->u.source_file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!last_matches)
|
||||
{
|
||||
/* we shouldn't have line changes on first line of function */
|
||||
dli = vector_add(&func->vlines, &module->pool);
|
||||
dli->cookie = DLIT_SOURCEFILE;
|
||||
dli->line_number = 0;
|
||||
dli->u.source_file = source_idx;
|
||||
}
|
||||
dli = vector_add(&func->vlines, &module->pool);
|
||||
dli->cookie = DLIT_OFFSET;
|
||||
dli->line_number = line_num;
|
||||
dli->u.pc_offset = func->addr + offset;
|
||||
}
|
||||
|
||||
struct symt_data* symt_add_func_local(struct module* module,
|
||||
struct symt_function* func,
|
||||
int regno, int offset,
|
||||
struct symt_block* block,
|
||||
struct symt* type, const char* name)
|
||||
{
|
||||
struct symt_data* locsym;
|
||||
struct symt** p;
|
||||
|
||||
assert(func);
|
||||
assert(func->symt.tag == SymTagFunction);
|
||||
|
||||
TRACE_(dbghelp_symtype)("Adding local symbol (%s:%s): %s %p\n",
|
||||
module->module.ModuleName, func->hash_elt.name,
|
||||
name, type);
|
||||
locsym = pool_alloc(&module->pool, sizeof(*locsym));
|
||||
locsym->symt.tag = SymTagData;
|
||||
locsym->hash_elt.name = pool_strdup(&module->pool, name);
|
||||
locsym->hash_elt.next = NULL;
|
||||
locsym->kind = DataIsLocal;
|
||||
locsym->container = &block->symt;
|
||||
locsym->type = type;
|
||||
if (regno)
|
||||
{
|
||||
locsym->location = LocIsEnregistered;
|
||||
locsym->u.reg_id = regno;
|
||||
}
|
||||
else
|
||||
{
|
||||
locsym->location = LocIsRegRel;
|
||||
locsym->u.reg_id = CV_REG_EBP;
|
||||
locsym->u.offset = offset;
|
||||
}
|
||||
if (block)
|
||||
p = vector_add(&block->vchildren, &module->pool);
|
||||
else
|
||||
p = vector_add(&func->vchildren, &module->pool);
|
||||
*p = &locsym->symt;
|
||||
return locsym;
|
||||
}
|
||||
|
||||
struct symt_block* symt_open_func_block(struct module* module,
|
||||
struct symt_function* func,
|
||||
struct symt_block* parent_block,
|
||||
unsigned pc)
|
||||
{
|
||||
struct symt_block* block;
|
||||
struct symt** p;
|
||||
|
||||
assert(func);
|
||||
assert(func->symt.tag == SymTagFunction);
|
||||
|
||||
assert(!parent_block || parent_block->symt.tag == SymTagBlock);
|
||||
block = pool_alloc(&module->pool, sizeof(*block));
|
||||
block->symt.tag = SymTagBlock;
|
||||
block->address = func->addr + pc;
|
||||
block->size = 0;
|
||||
block->container = parent_block ? &parent_block->symt : &func->symt;
|
||||
vector_init(&block->vchildren, sizeof(struct symt*), 4);
|
||||
if (parent_block)
|
||||
p = vector_add(&parent_block->vchildren, &module->pool);
|
||||
else
|
||||
p = vector_add(&func->vchildren, &module->pool);
|
||||
*p = &block->symt;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
struct symt_block* symt_close_func_block(struct module* module,
|
||||
struct symt_function* func,
|
||||
struct symt_block* block, unsigned pc)
|
||||
{
|
||||
assert(func->symt.tag == SymTagFunction);
|
||||
|
||||
block->size = func->addr + pc - block->address;
|
||||
return (block->container->tag == SymTagBlock) ?
|
||||
GET_ENTRY(block->container, struct symt_block, symt) : NULL;
|
||||
}
|
||||
|
||||
BOOL symt_normalize_function(struct module* module, struct symt_function* func)
|
||||
{
|
||||
unsigned len;
|
||||
struct line_info* dli;
|
||||
|
||||
if (!func) return TRUE;
|
||||
/* We aren't adding any more locals or line numbers to this function.
|
||||
* Free any spare memory that we might have allocated.
|
||||
*/
|
||||
assert(func->symt.tag == SymTagFunction);
|
||||
|
||||
/* EPP vector_pool_normalize(&func->vlines, &module->pool); */
|
||||
/* EPP vector_pool_normalize(&func->vchildren, &module->pool); */
|
||||
|
||||
len = vector_length(&func->vlines);
|
||||
if (len--)
|
||||
{
|
||||
dli = vector_at(&func->vlines, 0); dli->cookie |= DLIT_FIRST;
|
||||
dli = vector_at(&func->vlines, len); dli->cookie |= DLIT_LAST;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* expect sym_info->MaxNameLen to be set before being called */
|
||||
static void symt_fill_sym_info(const struct module* module,
|
||||
const struct symt* sym, SYMBOL_INFO* sym_info)
|
||||
{
|
||||
const char* name;
|
||||
|
||||
sym_info->TypeIndex = (DWORD)sym;
|
||||
sym_info->info = 0; /* TBD */
|
||||
symt_get_info(sym, TI_GET_LENGTH, &sym_info->Size);
|
||||
sym_info->ModBase = module->module.BaseOfImage;
|
||||
sym_info->Flags = 0;
|
||||
switch (sym->tag)
|
||||
{
|
||||
case SymTagData:
|
||||
{
|
||||
struct symt_data* data = (struct symt_data*)sym;
|
||||
switch (data->location)
|
||||
{
|
||||
case LocIsEnregistered:
|
||||
sym_info->Flags |= SYMFLAG_REGISTER;
|
||||
sym_info->Register = data->u.reg_id;
|
||||
sym_info->Address = 0;
|
||||
break;
|
||||
case LocIsRegRel:
|
||||
sym_info->Flags |=
|
||||
((data->u.offset < 0) ? SYMFLAG_LOCAL : SYMFLAG_PARAMETER) |
|
||||
SYMFLAG_FRAMEREL;
|
||||
sym_info->Register = data->u.reg_id;
|
||||
sym_info->Address = data->u.offset;
|
||||
break;
|
||||
case LocIsStatic:
|
||||
symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
|
||||
sym_info->Register = 0;
|
||||
break;
|
||||
case LocIsConstant:
|
||||
sym_info->Flags |= SYMFLAG_VALUEPRESENT;
|
||||
sym_info->Value = data->u.value;
|
||||
break;
|
||||
default:
|
||||
FIXME("Unhandled loc (%u) in sym data\n", data->location);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SymTagPublicSymbol:
|
||||
sym_info->Flags |= SYMFLAG_EXPORT;
|
||||
symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
|
||||
break;
|
||||
case SymTagFunction:
|
||||
sym_info->Flags |= SYMFLAG_FUNCTION;
|
||||
symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
|
||||
break;
|
||||
default:
|
||||
symt_get_info(sym, TI_GET_ADDRESS, &sym_info->Address);
|
||||
sym_info->Register = 0;
|
||||
break;
|
||||
}
|
||||
sym_info->Scope = 0; /* FIXME */
|
||||
sym_info->Tag = sym->tag;
|
||||
name = symt_get_name(sym);
|
||||
sym_info->NameLen = strlen(name) + 1;
|
||||
if (sym_info->MaxNameLen)
|
||||
{
|
||||
strncpy(sym_info->Name, name, min(sym_info->NameLen, sym_info->MaxNameLen));
|
||||
sym_info->Name[sym_info->MaxNameLen - 1] = '\0';
|
||||
}
|
||||
TRACE_(dbghelp_symtype)("%p => %s %lu %lx\n",
|
||||
sym, sym_info->Name, sym_info->Size, sym_info->Address);
|
||||
}
|
||||
|
||||
static BOOL symt_enum_module(struct module* module, const char* mask,
|
||||
PSYM_ENUMERATESYMBOLS_CALLBACK cb, PVOID user)
|
||||
{
|
||||
char buffer[sizeof(SYMBOL_INFO) + 256];
|
||||
SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer;
|
||||
void* ptr;
|
||||
struct symt_ht* sym = NULL;
|
||||
struct hash_table_iter hti;
|
||||
regex_t preg;
|
||||
|
||||
assert(mask);
|
||||
assert(mask[0] != '!');
|
||||
regcomp(&preg, mask, REG_NOSUB);
|
||||
hash_table_iter_init(&module->ht_symbols, &hti, NULL);
|
||||
while ((ptr = hash_table_iter_up(&hti)))
|
||||
{
|
||||
sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
|
||||
/* FIXME: this is not true, we should only drop the public
|
||||
* symbol iff no other one is found
|
||||
*/
|
||||
if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) &&
|
||||
sym->symt.tag == SymTagPublicSymbol) continue;
|
||||
|
||||
if (sym->hash_elt.name &&
|
||||
regexec(&preg, sym->hash_elt.name, 0, NULL, 0) == 0)
|
||||
{
|
||||
sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
|
||||
symt_fill_sym_info(module, &sym->symt, sym_info);
|
||||
if (!cb(sym_info, sym_info->Size, user)) break;
|
||||
}
|
||||
}
|
||||
regfree(&preg);
|
||||
return sym ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* resort_symbols
|
||||
*
|
||||
* Rebuild sorted list of symbols for a module.
|
||||
*/
|
||||
static BOOL resort_symbols(struct module* module)
|
||||
{
|
||||
int nsym = 0;
|
||||
void* ptr;
|
||||
struct symt_ht* sym;
|
||||
struct hash_table_iter hti;
|
||||
|
||||
hash_table_iter_init(&module->ht_symbols, &hti, NULL);
|
||||
while ((ptr = hash_table_iter_up(&hti)))
|
||||
nsym++;
|
||||
|
||||
if (!(module->module.NumSyms = nsym)) return FALSE;
|
||||
|
||||
if (module->addr_sorttab)
|
||||
module->addr_sorttab = HeapReAlloc(GetProcessHeap(), 0,
|
||||
module->addr_sorttab,
|
||||
nsym * sizeof(struct symt_ht*));
|
||||
else
|
||||
module->addr_sorttab = HeapAlloc(GetProcessHeap(), 0,
|
||||
nsym * sizeof(struct symt_ht*));
|
||||
if (!module->addr_sorttab) return FALSE;
|
||||
|
||||
nsym = 0;
|
||||
hash_table_iter_init(&module->ht_symbols, &hti, NULL);
|
||||
while ((ptr = hash_table_iter_up(&hti)))
|
||||
{
|
||||
sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
|
||||
assert(sym);
|
||||
module->addr_sorttab[nsym++] = sym;
|
||||
}
|
||||
|
||||
qsort(module->addr_sorttab, nsym, sizeof(struct symt_ht*), symt_cmp_addr);
|
||||
return module->sortlist_valid = TRUE;
|
||||
}
|
||||
|
||||
/* assume addr is in module */
|
||||
static int symt_find_nearest(struct module* module, DWORD addr)
|
||||
{
|
||||
int mid, high, low;
|
||||
|
||||
if (!module->sortlist_valid && !resort_symbols(module)) return -1;
|
||||
|
||||
/*
|
||||
* Binary search to find closest symbol.
|
||||
*/
|
||||
low = 0;
|
||||
high = module->module.NumSyms;
|
||||
|
||||
while (high > low + 1)
|
||||
{
|
||||
mid = (high + low) / 2;
|
||||
if (cmp_sorttab_addr(module, mid, addr) < 0)
|
||||
low = mid;
|
||||
else
|
||||
high = mid;
|
||||
}
|
||||
if (low != high && high != module->module.NumSyms &&
|
||||
cmp_sorttab_addr(module, high, addr) <= 0)
|
||||
low = high;
|
||||
|
||||
/* If found symbol is a public symbol, check if there are any other entries that
|
||||
* might also have the same address, but would get better information
|
||||
*/
|
||||
if (module->addr_sorttab[low]->symt.tag == SymTagPublicSymbol)
|
||||
{
|
||||
DWORD ref;
|
||||
|
||||
symt_get_info(&module->addr_sorttab[low]->symt, TI_GET_ADDRESS, &ref);
|
||||
if (low > 0 &&
|
||||
module->addr_sorttab[low - 1]->symt.tag != SymTagPublicSymbol &&
|
||||
!cmp_sorttab_addr(module, low - 1, ref))
|
||||
low--;
|
||||
else if (low < module->module.NumSyms - 1 &&
|
||||
module->addr_sorttab[low + 1]->symt.tag != SymTagPublicSymbol &&
|
||||
!cmp_sorttab_addr(module, low + 1, ref))
|
||||
low++;
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
static BOOL symt_enum_locals_helper(struct process* pcs, struct module* module,
|
||||
regex_t* preg, PSYM_ENUMERATESYMBOLS_CALLBACK cb,
|
||||
PVOID user, SYMBOL_INFO* sym_info,
|
||||
struct vector* v)
|
||||
{
|
||||
struct symt** plsym = NULL;
|
||||
struct symt* lsym = NULL;
|
||||
DWORD pc = pcs->ctx_frame.InstructionOffset;
|
||||
|
||||
while ((plsym = vector_iter_up(v, plsym)))
|
||||
{
|
||||
lsym = *plsym;
|
||||
switch (lsym->tag)
|
||||
{
|
||||
case SymTagBlock:
|
||||
{
|
||||
struct symt_block* block = (struct symt_block*)lsym;
|
||||
if (pc < block->address || block->address + block->size <= pc)
|
||||
continue;
|
||||
if (!symt_enum_locals_helper(pcs, module, preg, cb, user,
|
||||
sym_info, &block->vchildren))
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case SymTagData:
|
||||
if (regexec(preg, symt_get_name(lsym), 0, NULL, 0) == 0)
|
||||
{
|
||||
symt_fill_sym_info(module, lsym, sym_info);
|
||||
if (!cb(sym_info, sym_info->Size, user))
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL symt_enum_locals(struct process* pcs, const char* mask,
|
||||
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
|
||||
PVOID UserContext)
|
||||
{
|
||||
struct module* module;
|
||||
struct symt_ht* sym;
|
||||
char buffer[sizeof(SYMBOL_INFO) + 256];
|
||||
SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer;
|
||||
DWORD pc = pcs->ctx_frame.InstructionOffset;
|
||||
int idx;
|
||||
|
||||
sym_info->SizeOfStruct = sizeof(*sym_info);
|
||||
sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
|
||||
|
||||
module = module_find_by_addr(pcs, pc, DMT_UNKNOWN);
|
||||
if (!(module = module_get_debug(pcs, module))) return FALSE;
|
||||
if ((idx = symt_find_nearest(module, pc)) == -1) return FALSE;
|
||||
|
||||
sym = module->addr_sorttab[idx];
|
||||
if (sym->symt.tag == SymTagFunction)
|
||||
{
|
||||
BOOL ret;
|
||||
regex_t preg;
|
||||
|
||||
regcomp(&preg, mask ? mask : ".*", REG_NOSUB);
|
||||
ret = symt_enum_locals_helper(pcs, module, &preg, EnumSymbolsCallback,
|
||||
UserContext, sym_info,
|
||||
&((struct symt_function*)sym)->vchildren);
|
||||
regfree(&preg);
|
||||
return ret;
|
||||
|
||||
}
|
||||
symt_fill_sym_info(module, &sym->symt, sym_info);
|
||||
return EnumSymbolsCallback(sym_info, sym_info->Size, UserContext);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymEnumSymbols (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG BaseOfDll, PCSTR Mask,
|
||||
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
|
||||
PVOID UserContext)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
struct module* module;
|
||||
|
||||
TRACE("(%p %08lx %s %p %p)\n",
|
||||
hProcess, BaseOfDll, debugstr_a(Mask), EnumSymbolsCallback, UserContext);
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
|
||||
if (BaseOfDll == 0)
|
||||
{
|
||||
if (Mask && Mask[0] == '!')
|
||||
{
|
||||
if (!Mask[1])
|
||||
{
|
||||
/* FIXME: is this really what's intended ??? */
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (module->module.SymType != SymNone &&
|
||||
!symt_enum_module(module, ".*", EnumSymbolsCallback, UserContext))
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
module = module_find_by_name(pcs, &Mask[1], DMT_UNKNOWN);
|
||||
Mask++;
|
||||
}
|
||||
else return symt_enum_locals(pcs, Mask, EnumSymbolsCallback, UserContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
|
||||
if (Mask && Mask[0] == '!')
|
||||
{
|
||||
if (!Mask[1] ||
|
||||
strcmp(&Mask[1], module->module.ModuleName))
|
||||
{
|
||||
FIXME("Strange call mode\n");
|
||||
return FALSE;
|
||||
}
|
||||
Mask = ".*";
|
||||
}
|
||||
else if (!Mask) Mask = ".*";
|
||||
}
|
||||
if ((module = module_get_debug(pcs, module)))
|
||||
symt_enum_module(module, Mask, EnumSymbolsCallback, UserContext);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct sym_enumerate
|
||||
{
|
||||
void* ctx;
|
||||
PSYM_ENUMSYMBOLS_CALLBACK cb;
|
||||
};
|
||||
|
||||
static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx)
|
||||
{
|
||||
struct sym_enumerate* se = (struct sym_enumerate*)ctx;
|
||||
return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymEnumerateSymbols (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll,
|
||||
PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback,
|
||||
PVOID UserContext)
|
||||
{
|
||||
struct sym_enumerate se;
|
||||
|
||||
se.ctx = UserContext;
|
||||
se.cb = EnumSymbolsCallback;
|
||||
|
||||
return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymFromAddr (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD Address,
|
||||
DWORD* Displacement, PSYMBOL_INFO Symbol)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
struct module* module;
|
||||
struct symt_ht* sym;
|
||||
int idx;
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
module = module_find_by_addr(pcs, Address, DMT_UNKNOWN);
|
||||
if (!(module = module_get_debug(pcs, module))) return FALSE;
|
||||
if ((idx = symt_find_nearest(module, Address)) == -1) return FALSE;
|
||||
|
||||
sym = module->addr_sorttab[idx];
|
||||
|
||||
symt_fill_sym_info(module, &sym->symt, Symbol);
|
||||
if (Displacement) *Displacement = Address - Symbol->Address;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymGetSymFromAddr (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address,
|
||||
PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol)
|
||||
{
|
||||
char buffer[sizeof(SYMBOL_INFO) + 256];
|
||||
SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
|
||||
size_t len;
|
||||
|
||||
if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
|
||||
si->SizeOfStruct = sizeof(*si);
|
||||
si->MaxNameLen = 256;
|
||||
if (!SymFromAddr(hProcess, Address, Displacement, si))
|
||||
return FALSE;
|
||||
|
||||
Symbol->Address = si->Address;
|
||||
Symbol->Size = si->Size;
|
||||
Symbol->Flags = si->Flags;
|
||||
len = min(Symbol->MaxNameLength, si->MaxNameLen);
|
||||
strncpy(Symbol->Name, si->Name, len);
|
||||
Symbol->Name[len - 1] = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymFromName (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymFromName(HANDLE hProcess, LPSTR Name, PSYMBOL_INFO Symbol)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
struct module* module;
|
||||
struct hash_table_iter hti;
|
||||
void* ptr;
|
||||
struct symt_ht* sym = NULL;
|
||||
|
||||
TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol);
|
||||
if (!pcs) return FALSE;
|
||||
if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (module->module.SymType != SymNone)
|
||||
{
|
||||
if (module->module.SymType == SymDeferred)
|
||||
{
|
||||
struct module* xmodule = module_get_debug(pcs, module);
|
||||
if (!xmodule) continue;
|
||||
module = xmodule;
|
||||
}
|
||||
hash_table_iter_init(&module->ht_symbols, &hti, Name);
|
||||
while ((ptr = hash_table_iter_up(&hti)))
|
||||
{
|
||||
sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
|
||||
|
||||
if (!strcmp(sym->hash_elt.name, Name))
|
||||
{
|
||||
symt_fill_sym_info(module, &sym->symt, Symbol);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymGetSymFromName (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI SymGetSymFromName(HANDLE hProcess, LPSTR Name, PIMAGEHLP_SYMBOL Symbol)
|
||||
{
|
||||
char buffer[sizeof(SYMBOL_INFO) + 256];
|
||||
SYMBOL_INFO*si = (SYMBOL_INFO*)buffer;
|
||||
size_t len;
|
||||
|
||||
if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE;
|
||||
si->SizeOfStruct = sizeof(*si);
|
||||
si->MaxNameLen = 256;
|
||||
if (!SymFromName(hProcess, Name, si)) return FALSE;
|
||||
|
||||
Symbol->Address = si->Address;
|
||||
Symbol->Size = si->Size;
|
||||
Symbol->Flags = si->Flags;
|
||||
len = min(Symbol->MaxNameLength, si->MaxNameLen);
|
||||
strncpy(Symbol->Name, si->Name, len);
|
||||
Symbol->Name[len - 1] = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* fill_line_info
|
||||
*
|
||||
* fills information about a file
|
||||
*/
|
||||
static BOOL fill_line_info(struct module* module, struct symt_function* func,
|
||||
DWORD addr, IMAGEHLP_LINE* line)
|
||||
{
|
||||
struct line_info* dli = NULL;
|
||||
BOOL found = FALSE;
|
||||
|
||||
assert(func->symt.tag == SymTagFunction);
|
||||
|
||||
while ((dli = vector_iter_down(&func->vlines, dli)))
|
||||
{
|
||||
if (!(dli->cookie & DLIT_SOURCEFILE))
|
||||
{
|
||||
if (found || dli->u.pc_offset > addr) continue;
|
||||
line->LineNumber = dli->line_number;
|
||||
line->Address = dli->u.pc_offset;
|
||||
line->Key = dli;
|
||||
found = TRUE;
|
||||
continue;
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
line->FileName = (char*)source_get(module, dli->u.source_file);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymGetSymNext (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
|
||||
{
|
||||
/* algo:
|
||||
* get module from Symbol.Address
|
||||
* get index in module.addr_sorttab of Symbol.Address
|
||||
* increment index
|
||||
* if out of module bounds, move to next module in process address space
|
||||
*/
|
||||
FIXME("(%p, %p): stub\n", hProcess, Symbol);
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymGetSymPrev (DBGHELP.@)
|
||||
*/
|
||||
|
||||
BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol)
|
||||
{
|
||||
FIXME("(%p, %p): stub\n", hProcess, Symbol);
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymGetLineFromAddr (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr,
|
||||
PDWORD pdwDisplacement, PIMAGEHLP_LINE Line)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
struct module* module;
|
||||
int idx;
|
||||
|
||||
TRACE("%p %08lx %p %p\n", hProcess, dwAddr, pdwDisplacement, Line);
|
||||
|
||||
if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
|
||||
if (!(module = module_get_debug(pcs, module))) return FALSE;
|
||||
if ((idx = symt_find_nearest(module, dwAddr)) == -1) return FALSE;
|
||||
|
||||
if (module->addr_sorttab[idx]->symt.tag != SymTagFunction) return FALSE;
|
||||
if (!fill_line_info(module,
|
||||
(struct symt_function*)module->addr_sorttab[idx],
|
||||
dwAddr, Line)) return FALSE;
|
||||
if (pdwDisplacement) *pdwDisplacement = dwAddr - Line->Address;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymGetLinePrev (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
struct module* module;
|
||||
struct line_info* li;
|
||||
BOOL in_search = FALSE;
|
||||
|
||||
TRACE("(%p %p)\n", hProcess, Line);
|
||||
|
||||
if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
module = module_find_by_addr(pcs, Line->Address, DMT_UNKNOWN);
|
||||
if (!(module = module_get_debug(pcs, module))) return FALSE;
|
||||
|
||||
if (Line->Key == 0) return FALSE;
|
||||
li = (struct line_info*)Line->Key;
|
||||
/* things are a bit complicated because when we encounter a DLIT_SOURCEFILE
|
||||
* element we have to go back until we find the prev one to get the real
|
||||
* source file name for the DLIT_OFFSET element just before
|
||||
* the first DLIT_SOURCEFILE
|
||||
*/
|
||||
while (!(li->cookie & DLIT_FIRST))
|
||||
{
|
||||
li--;
|
||||
if (!(li->cookie & DLIT_SOURCEFILE))
|
||||
{
|
||||
Line->LineNumber = li->line_number;
|
||||
Line->Address = li->u.pc_offset;
|
||||
Line->Key = li;
|
||||
if (!in_search) return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (in_search)
|
||||
{
|
||||
Line->FileName = (char*)source_get(module, li->u.source_file);
|
||||
return TRUE;
|
||||
}
|
||||
in_search = TRUE;
|
||||
}
|
||||
}
|
||||
SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymGetLineNext (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
struct module* module;
|
||||
struct line_info* li;
|
||||
|
||||
TRACE("(%p %p)\n", hProcess, Line);
|
||||
|
||||
if (Line->SizeOfStruct < sizeof(*Line)) return FALSE;
|
||||
if (!pcs) return FALSE;
|
||||
module = module_find_by_addr(pcs, Line->Address, DMT_UNKNOWN);
|
||||
if (!(module = module_get_debug(pcs, module))) return FALSE;
|
||||
|
||||
if (Line->Key == 0) return FALSE;
|
||||
li = (struct line_info*)Line->Key;
|
||||
while (!(li->cookie & DLIT_LAST))
|
||||
{
|
||||
li++;
|
||||
if (!(li->cookie & DLIT_SOURCEFILE))
|
||||
{
|
||||
Line->LineNumber = li->line_number;
|
||||
Line->Address = li->u.pc_offset;
|
||||
Line->Key = li;
|
||||
return TRUE;
|
||||
}
|
||||
Line->FileName = (char*)source_get(module, li->u.source_file);
|
||||
}
|
||||
SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymFunctionTableAccess (DBGHELP.@)
|
||||
*/
|
||||
PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase)
|
||||
{
|
||||
FIXME("(%p, 0x%08lx): stub\n", hProcess, AddrBase);
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymUnDName (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, LPSTR UnDecName, DWORD UnDecNameLength)
|
||||
{
|
||||
FIXME("(%p %s %lu): stub\n", sym, UnDecName, UnDecNameLength);
|
||||
return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength,
|
||||
UNDNAME_COMPLETE);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* UnDecorateSymbolName (DBGHELP.@)
|
||||
*/
|
||||
DWORD WINAPI UnDecorateSymbolName(LPCSTR DecoratedName, LPSTR UnDecoratedName,
|
||||
DWORD UndecoratedLength, DWORD Flags)
|
||||
{
|
||||
FIXME("(%s, %p, %ld, 0x%08lx): stub\n",
|
||||
debugstr_a(DecoratedName), UnDecoratedName, UndecoratedLength, Flags);
|
||||
|
||||
strncpy(UnDecoratedName, DecoratedName, UndecoratedLength);
|
||||
UnDecoratedName[UndecoratedLength - 1] = '\0';
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,674 @@
|
|||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winreg.h"
|
||||
#include "winnls.h"
|
||||
#include "wine/debug.h"
|
||||
#include "dbghelp_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symtype);
|
||||
|
||||
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 ((struct symt_data*)sym)->hash_elt.name;
|
||||
case SymTagFunction: return ((struct symt_function*)sym)->hash_elt.name;
|
||||
case SymTagPublicSymbol: return ((struct symt_public*)sym)->hash_elt.name;
|
||||
case SymTagBaseType: return ((struct symt_basic*)sym)->hash_elt.name;
|
||||
/* hierarchy tree */
|
||||
case SymTagEnum: return ((struct symt_enum*)sym)->name;
|
||||
case SymTagTypedef: return ((struct symt_typedef*)sym)->hash_elt.name;
|
||||
case SymTagUDT: return ((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;
|
||||
}
|
||||
}
|
||||
|
||||
static struct symt* symt_find_type_by_name(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 = GET_ENTRY(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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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_symtype)("Adding udt %s:%s\n", 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);
|
||||
}
|
||||
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_symtype)("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_symtype)("Adding %s to UDT %s\n", name, udt_type->hash_elt.name);
|
||||
p = NULL;
|
||||
while ((p = vector_iter_up(&udt_type->vchildren, p)))
|
||||
{
|
||||
m = (struct symt_data*)*p;
|
||||
assert(m);
|
||||
assert(m->symt.tag == SymTagData);
|
||||
if (m->hash_elt.name[0] == name[0] && 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 = pool_strdup(&module->pool, name);
|
||||
m->hash_elt.next = NULL;
|
||||
|
||||
m->kind = DataIsMember;
|
||||
m->container = &udt_type->symt;
|
||||
m->type = elt_type;
|
||||
if (!(offset & 7) && !(size & 7))
|
||||
{
|
||||
m->location = LocIsThisRel;
|
||||
m->u.offset = offset >> 3;
|
||||
/* we could check that elt_type's size is actually size */
|
||||
}
|
||||
else
|
||||
{
|
||||
m->location = LocIsBitField;
|
||||
m->u.bitfield.position = offset;
|
||||
m->u.bitfield.length = 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_enum* sym;
|
||||
|
||||
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
|
||||
{
|
||||
sym->symt.tag = SymTagEnum;
|
||||
sym->name = pool_strdup(&module->pool, typename);
|
||||
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, unsigned 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;
|
||||
/* CV defines the underlying type for the enumeration */
|
||||
e->type = &symt_new_basic(module, btInt, "int", 4)->symt;
|
||||
e->location = LocIsConstant;
|
||||
e->u.value = value; /* FIXME: use variant */
|
||||
|
||||
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_array* sym;
|
||||
|
||||
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
|
||||
{
|
||||
sym->symt.tag = SymTagArrayType;
|
||||
sym->start = min;
|
||||
sym->end = max;
|
||||
sym->basetype = base;
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
struct symt_function_signature* symt_new_function_signature(struct module* module,
|
||||
struct symt* ret_type)
|
||||
{
|
||||
struct symt_function_signature* sym;
|
||||
|
||||
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
|
||||
{
|
||||
sym->symt.tag = SymTagFunctionType;
|
||||
sym->rettype = ret_type;
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
struct symt_pointer* symt_new_pointer(struct module* module, struct symt* ref_type)
|
||||
{
|
||||
struct symt_pointer* sym;
|
||||
|
||||
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
|
||||
{
|
||||
sym->symt.tag = SymTagPointerType;
|
||||
sym->pointsto = ref_type;
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymEnumTypes (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymEnumTypes(HANDLE hProcess, unsigned long BaseOfDll,
|
||||
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
|
||||
void* UserContext)
|
||||
{
|
||||
struct process* pcs;
|
||||
struct module* module;
|
||||
struct symt_ht* type;
|
||||
void* ptr;
|
||||
char buffer[sizeof(SYMBOL_INFO) + 256];
|
||||
SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer;
|
||||
struct hash_table_iter hti;
|
||||
const char* tmp;
|
||||
|
||||
TRACE("(%p %08lx %p %p)\n",
|
||||
hProcess, BaseOfDll, EnumSymbolsCallback, UserContext);
|
||||
|
||||
pcs = process_find_by_handle(hProcess);
|
||||
if (!pcs) return FALSE;
|
||||
module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
|
||||
if (!(module = module_get_debug(pcs, module))) return FALSE;
|
||||
|
||||
sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
|
||||
|
||||
hash_table_iter_init(&module->ht_types, &hti, NULL);
|
||||
while ((ptr = hash_table_iter_up(&hti)))
|
||||
{
|
||||
type = GET_ENTRY(ptr, struct symt_ht, hash_elt);
|
||||
sym_info->TypeIndex = (DWORD)type;
|
||||
sym_info->info = 0; /* FIXME */
|
||||
symt_get_info(&type->symt, TI_GET_LENGTH, &sym_info->Size);
|
||||
sym_info->ModBase = module->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->symt.tag;
|
||||
tmp = symt_get_name(&type->symt);
|
||||
sym_info->NameLen = strlen(tmp) + 1;
|
||||
strncpy(sym_info->Name, tmp, min(sym_info->NameLen, sym_info->MaxNameLen));
|
||||
sym_info->Name[sym_info->MaxNameLen - 1] = '\0';
|
||||
if (!EnumSymbolsCallback(sym_info, sym_info->Size, UserContext)) break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* symt_get_info
|
||||
*
|
||||
* Retrieves inforamtion about a symt (either symbol or type)
|
||||
*/
|
||||
BOOL symt_get_info(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 = &((struct symt_udt*)type)->vchildren; break;
|
||||
case SymTagEnum: v = &((struct symt_enum*)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] = (DWORD)*pt;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TI_GET_ADDRESS:
|
||||
switch (type->tag)
|
||||
{
|
||||
case SymTagData:
|
||||
switch (((struct symt_data*)type)->kind)
|
||||
{
|
||||
case DataIsGlobal:
|
||||
case DataIsFileStatic:
|
||||
X(DWORD) = ((struct symt_data*)type)->u.address;
|
||||
break;
|
||||
default: return FALSE;
|
||||
}
|
||||
break;
|
||||
case SymTagFunction:
|
||||
X(DWORD) = ((struct symt_function*)type)->addr;
|
||||
break;
|
||||
case SymTagPublicSymbol:
|
||||
X(DWORD) = ((struct symt_public*)type)->address;
|
||||
break;
|
||||
default:
|
||||
FIXME("Unsupported sym-tag %s for get-address\n", symt_get_tag_str(type->tag));
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
#if 0
|
||||
/* this is wrong, we should return the type of the index, not the
|
||||
* type of the array[0]
|
||||
*/
|
||||
case TI_GET_ARRAYINDEXTYPEID:
|
||||
if (type->tag != SymTagArrayType) return FALSE;
|
||||
X(DWORD) = (DWORD)((struct symt_array*)type)->basetype;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case TI_GET_BASETYPE:
|
||||
if (type->tag != SymTagBaseType) return FALSE;
|
||||
X(DWORD) = ((struct symt_basic*)type)->bt;
|
||||
break;
|
||||
|
||||
case TI_GET_BITPOSITION:
|
||||
if (type->tag != SymTagData || ((struct symt_data*)type)->location != LocIsBitField)
|
||||
return FALSE;
|
||||
X(DWORD) = ((struct symt_data*)type)->u.bitfield.position;
|
||||
break;
|
||||
|
||||
case TI_GET_CHILDRENCOUNT:
|
||||
switch (type->tag)
|
||||
{
|
||||
case SymTagUDT:
|
||||
X(DWORD) = vector_length(&((struct symt_udt*)type)->vchildren);
|
||||
break;
|
||||
case SymTagEnum:
|
||||
X(DWORD) = vector_length(&((struct symt_enum*)type)->vchildren);
|
||||
break;
|
||||
default:
|
||||
FIXME("Unsupported sym-tag %s for get-children-count\n", symt_get_tag_str(type->tag));
|
||||
/* fall through */
|
||||
case SymTagPublicSymbol:
|
||||
case SymTagPointerType:
|
||||
case SymTagBaseType:
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case TI_GET_COUNT:
|
||||
if (type->tag != SymTagArrayType) return FALSE;
|
||||
X(DWORD) = ((struct symt_array*)type)->end -
|
||||
((struct symt_array*)type)->start;
|
||||
break;
|
||||
|
||||
case TI_GET_DATAKIND:
|
||||
if (type->tag != SymTagData) return FALSE;
|
||||
X(DWORD) = ((struct symt_data*)type)->kind;
|
||||
break;
|
||||
|
||||
case TI_GET_LENGTH:
|
||||
switch (type->tag)
|
||||
{
|
||||
case SymTagBaseType:
|
||||
X(DWORD) = ((struct symt_basic*)type)->size;
|
||||
break;
|
||||
case SymTagFunction:
|
||||
X(DWORD) = ((struct symt_function*)type)->size;
|
||||
break;
|
||||
case SymTagPointerType:
|
||||
X(DWORD) = sizeof(void*);
|
||||
break;
|
||||
case SymTagUDT:
|
||||
X(DWORD) = ((struct symt_udt*)type)->size;
|
||||
break;
|
||||
case SymTagEnum:
|
||||
X(DWORD) = sizeof(int);
|
||||
break;
|
||||
case SymTagData:
|
||||
if (((struct symt_data*)type)->location == LocIsBitField)
|
||||
X(DWORD) = ((struct symt_data*)type)->u.bitfield.length;
|
||||
else
|
||||
return symt_get_info(((struct symt_data*)type)->type,
|
||||
TI_GET_LENGTH, pInfo);
|
||||
break;
|
||||
case SymTagArrayType:
|
||||
if (!symt_get_info(((struct symt_array*)type)->basetype,
|
||||
TI_GET_LENGTH, pInfo))
|
||||
return FALSE;
|
||||
X(DWORD) *= ((struct symt_array*)type)->end -
|
||||
((struct symt_array*)type)->start;
|
||||
break;
|
||||
case SymTagPublicSymbol:
|
||||
X(DWORD) = ((struct symt_public*)type)->size;
|
||||
break;
|
||||
default:
|
||||
FIXME("Unsupported sym-tag %s for get-size\n", symt_get_tag_str(type->tag));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case TI_GET_LEXICALPARENT:
|
||||
switch (type->tag)
|
||||
{
|
||||
case SymTagBlock:
|
||||
X(DWORD) = (DWORD)((struct symt_block*)type)->container;
|
||||
break;
|
||||
case SymTagData:
|
||||
X(DWORD) = (DWORD)((struct symt_data*)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_OFFSET:
|
||||
switch (type->tag)
|
||||
{
|
||||
case SymTagData:
|
||||
switch (((struct symt_data*)type)->location)
|
||||
{
|
||||
case LocIsRegRel:
|
||||
case LocIsThisRel:
|
||||
X(ULONG) = ((struct symt_data*)type)->u.offset;
|
||||
break;
|
||||
case LocIsConstant:
|
||||
X(ULONG) = 0; /* FIXME ???? */
|
||||
break;
|
||||
default:
|
||||
FIXME("Unknown location (%u) for get-offset\n",
|
||||
((struct symt_data*)type)->location);
|
||||
break;
|
||||
}
|
||||
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:
|
||||
switch (type->tag)
|
||||
{
|
||||
case SymTagArrayType:
|
||||
X(DWORD) = (DWORD)((struct symt_array*)type)->basetype;
|
||||
break;
|
||||
case SymTagPointerType:
|
||||
X(DWORD) = (DWORD)((struct symt_pointer*)type)->pointsto;
|
||||
break;
|
||||
case SymTagFunctionType:
|
||||
X(DWORD) = (DWORD)((struct symt_function_signature*)type)->rettype;
|
||||
break;
|
||||
case SymTagData:
|
||||
X(DWORD) = (DWORD)((struct symt_data*)type)->type;
|
||||
break;
|
||||
default:
|
||||
FIXME("Unsupported sym-tag %s for get-type\n", symt_get_tag_str(type->tag));
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case TI_GET_TYPEID:
|
||||
X(DWORD) = (DWORD)type;
|
||||
break;
|
||||
|
||||
case TI_GET_UDTKIND:
|
||||
if (type->tag != SymTagUDT) return FALSE;
|
||||
X(DWORD) = ((struct symt_udt*)type)->kind;
|
||||
break;
|
||||
|
||||
#undef X
|
||||
|
||||
case TI_GET_ADDRESSOFFSET:
|
||||
case TI_GET_ARRAYINDEXTYPEID:
|
||||
case TI_GET_CALLING_CONVENTION:
|
||||
case TI_GET_CLASSPARENTID:
|
||||
case TI_GET_NESTED:
|
||||
case TI_GET_SYMINDEX:
|
||||
case TI_GET_THISADJUST:
|
||||
case TI_GET_VALUE:
|
||||
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;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymGetTypeInfo (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymGetTypeInfo(HANDLE hProcess, unsigned long ModBase,
|
||||
ULONG TypeId, IMAGEHLP_SYMBOL_TYPE_INFO GetType,
|
||||
PVOID pInfo)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
#if 0
|
||||
struct module* module;
|
||||
module = module_find_by_addr(pcs, ModBase, DMT_UNKNOWN);
|
||||
if (!(module = module_get_debug(pcs, module))) return FALSE;
|
||||
#endif
|
||||
|
||||
return symt_get_info((struct symt*)TypeId, GetType, pInfo);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymGetTypeFromName (DBGHELP.@)
|
||||
*
|
||||
*/
|
||||
BOOL WINAPI SymGetTypeFromName(HANDLE hProcess, unsigned long BaseOfDll,
|
||||
LPSTR Name, PSYMBOL_INFO Symbol)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
struct module* module;
|
||||
struct symt* type;
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
|
||||
if (!module) return FALSE;
|
||||
type = symt_find_type_by_name(module, SymTagNull, Name);
|
||||
if (!type) return FALSE;
|
||||
Symbol->TypeIndex = (DWORD)type;
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -44,6 +44,7 @@ WINDOWS_INCLUDES = \
|
|||
control.h \
|
||||
cpl.h \
|
||||
custcntl.h \
|
||||
cvconst.h \
|
||||
d3d.h \
|
||||
d3d8.h \
|
||||
d3d8caps.h \
|
||||
|
|
|
@ -0,0 +1,423 @@
|
|||
/*
|
||||
* File cvconst.h - MS debug information
|
||||
*
|
||||
* Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* information in this file is highly derivated from MSDN DIA information pages */
|
||||
|
||||
/* symbols & types enumeration */
|
||||
enum SymTagEnum
|
||||
{
|
||||
SymTagNull,
|
||||
SymTagExe,
|
||||
SymTagCompiland,
|
||||
SymTagCompilandDetails,
|
||||
SymTagCompilandEnv,
|
||||
SymTagFunction,
|
||||
SymTagBlock,
|
||||
SymTagData,
|
||||
SymTagAnnotation,
|
||||
SymTagLabel,
|
||||
SymTagPublicSymbol,
|
||||
SymTagUDT,
|
||||
SymTagEnum,
|
||||
SymTagFunctionType,
|
||||
SymTagPointerType,
|
||||
SymTagArrayType,
|
||||
SymTagBaseType,
|
||||
SymTagTypedef,
|
||||
SymTagBaseClass,
|
||||
SymTagFriend,
|
||||
SymTagFunctionArgType,
|
||||
SymTagFuncDebugStart,
|
||||
SymTagFuncDebugEnd,
|
||||
SymTagUsingNamespace,
|
||||
SymTagVTableShape,
|
||||
SymTagVTable,
|
||||
SymTagCustom,
|
||||
SymTagThunk,
|
||||
SymTagCustomType,
|
||||
SymTagManagedType,
|
||||
SymTagDimension,
|
||||
SymTagMax
|
||||
};
|
||||
|
||||
enum BasicType
|
||||
{
|
||||
btNoType = 0,
|
||||
btVoid = 1,
|
||||
btChar = 2,
|
||||
btWChar = 3,
|
||||
btInt = 6,
|
||||
btUInt = 7,
|
||||
btFloat = 8,
|
||||
btBCD = 9,
|
||||
btBool = 10,
|
||||
btLong = 13,
|
||||
btULong = 14,
|
||||
btCurrency = 25,
|
||||
btDate = 26,
|
||||
btVariant = 27,
|
||||
btComplex = 28,
|
||||
btBit = 29,
|
||||
btBSTR = 30,
|
||||
btHresult = 31,
|
||||
};
|
||||
|
||||
/* kind of UDT */
|
||||
enum UdtKind
|
||||
{
|
||||
UdtStruct,
|
||||
UdtClass,
|
||||
UdtUnion
|
||||
};
|
||||
|
||||
/* where a SymTagData is */
|
||||
enum LocationType
|
||||
{
|
||||
LocIsNull,
|
||||
LocIsStatic,
|
||||
LocIsTLS,
|
||||
LocIsRegRel,
|
||||
LocIsThisRel,
|
||||
LocIsEnregistered,
|
||||
LocIsBitField,
|
||||
LocIsSlot,
|
||||
LocIsIlRel,
|
||||
LocInMetaData,
|
||||
LocIsConstant
|
||||
};
|
||||
|
||||
/* kind of SymTagData */
|
||||
enum DataKind
|
||||
{
|
||||
DataIsUnknown,
|
||||
DataIsLocal,
|
||||
DataIsStaticLocal,
|
||||
DataIsParam,
|
||||
DataIsObjectPtr,
|
||||
DataIsFileStatic,
|
||||
DataIsGlobal,
|
||||
DataIsMember,
|
||||
DataIsStaticMember,
|
||||
DataIsConstant
|
||||
};
|
||||
|
||||
/* values for registers (on different CPUs) */
|
||||
enum CV_HREG_e
|
||||
{
|
||||
/* those values are common to all supported CPUs (and CPU independant) */
|
||||
CV_ALLREG_ERR = 30000,
|
||||
CV_ALLREG_TEB = 30001,
|
||||
CV_ALLREG_TIMER = 30002,
|
||||
CV_ALLREG_EFAD1 = 30003,
|
||||
CV_ALLREG_EFAD2 = 30004,
|
||||
CV_ALLREG_EFAD3 = 30005,
|
||||
CV_ALLREG_VFRAME = 30006,
|
||||
CV_ALLREG_HANDLE = 30007,
|
||||
CV_ALLREG_PARAMS = 30008,
|
||||
CV_ALLREG_LOCALS = 30009,
|
||||
|
||||
/* Intel x86 CPU */
|
||||
CV_REG_NONE = 0,
|
||||
CV_REG_AL = 1,
|
||||
CV_REG_CL = 2,
|
||||
CV_REG_DL = 3,
|
||||
CV_REG_BL = 4,
|
||||
CV_REG_AH = 5,
|
||||
CV_REG_CH = 6,
|
||||
CV_REG_DH = 7,
|
||||
CV_REG_BH = 8,
|
||||
CV_REG_AX = 9,
|
||||
CV_REG_CX = 10,
|
||||
CV_REG_DX = 11,
|
||||
CV_REG_BX = 12,
|
||||
CV_REG_SP = 13,
|
||||
CV_REG_BP = 14,
|
||||
CV_REG_SI = 15,
|
||||
CV_REG_DI = 16,
|
||||
CV_REG_EAX = 17,
|
||||
CV_REG_ECX = 18,
|
||||
CV_REG_EDX = 19,
|
||||
CV_REG_EBX = 20,
|
||||
CV_REG_ESP = 21,
|
||||
CV_REG_EBP = 22,
|
||||
CV_REG_ESI = 23,
|
||||
CV_REG_EDI = 24,
|
||||
CV_REG_ES = 25,
|
||||
CV_REG_CS = 26,
|
||||
CV_REG_SS = 27,
|
||||
CV_REG_DS = 28,
|
||||
CV_REG_FS = 29,
|
||||
CV_REG_GS = 30,
|
||||
CV_REG_IP = 31,
|
||||
CV_REG_FLAGS = 32,
|
||||
CV_REG_EIP = 33,
|
||||
CV_REG_EFLAGS = 34,
|
||||
|
||||
/* <pcode> */
|
||||
CV_REG_TEMP = 40,
|
||||
CV_REG_TEMPH = 41,
|
||||
CV_REG_QUOTE = 42,
|
||||
CV_REG_PCDR3 = 43, /* this includes PCDR4 to PCDR7 */
|
||||
CV_REG_CR0 = 80, /* this includes CR1 to CR4 */
|
||||
CV_REG_DR0 = 90, /* this includes DR1 to DR7 */
|
||||
/* </pcode> */
|
||||
|
||||
CV_REG_GDTR = 110,
|
||||
CV_REG_GDTL = 111,
|
||||
CV_REG_IDTR = 112,
|
||||
CV_REG_IDTL = 113,
|
||||
CV_REG_LDTR = 114,
|
||||
CV_REG_TR = 115,
|
||||
|
||||
CV_REG_PSEUDO1 = 116, /* this includes Pseudo02 to Pseuso09 */
|
||||
CV_REG_ST0 = 128, /* this includes ST1 to ST7 */
|
||||
CV_REG_CTRL = 136,
|
||||
CV_REG_STAT = 137,
|
||||
CV_REG_TAG = 138,
|
||||
CV_REG_FPIP = 139,
|
||||
CV_REG_FPCS = 140,
|
||||
CV_REG_FPDO = 141,
|
||||
CV_REG_FPDS = 142,
|
||||
CV_REG_ISEM = 143,
|
||||
CV_REG_FPEIP = 144,
|
||||
CV_REG_FPEDO = 145,
|
||||
CV_REG_MM0 = 146, /* this includes MM1 to MM7 */
|
||||
CV_REG_XMM0 = 154, /* this includes XMM1 to XMM7 */
|
||||
CV_REG_XMM00 = 162,
|
||||
CV_REG_XMM0L = 194, /* this includes XMM1L to XMM7L */
|
||||
CV_REG_XMM0H = 202, /* this includes XMM1H to XMM7H */
|
||||
CV_REG_MXCSR = 211,
|
||||
CV_REG_EDXEAX = 212,
|
||||
CV_REG_EMM0L = 220,
|
||||
CV_REG_EMM0H = 228,
|
||||
CV_REG_MM00 = 236,
|
||||
CV_REG_MM01 = 237,
|
||||
CV_REG_MM10 = 238,
|
||||
CV_REG_MM11 = 239,
|
||||
CV_REG_MM20 = 240,
|
||||
CV_REG_MM21 = 241,
|
||||
CV_REG_MM30 = 242,
|
||||
CV_REG_MM31 = 243,
|
||||
CV_REG_MM40 = 244,
|
||||
CV_REG_MM41 = 245,
|
||||
CV_REG_MM50 = 246,
|
||||
CV_REG_MM51 = 247,
|
||||
CV_REG_MM60 = 248,
|
||||
CV_REG_MM61 = 249,
|
||||
CV_REG_MM70 = 250,
|
||||
CV_REG_MM71 = 251,
|
||||
|
||||
/* Motorola 68K CPU */
|
||||
CV_R68_D0 = 0, /* this includes D1 to D7 too */
|
||||
CV_R68_A0 = 8, /* this includes A1 to A7 too */
|
||||
CV_R68_CCR = 16,
|
||||
CV_R68_SR = 17,
|
||||
CV_R68_USP = 18,
|
||||
CV_R68_MSP = 19,
|
||||
CV_R68_SFC = 20,
|
||||
CV_R68_DFC = 21,
|
||||
CV_R68_CACR = 22,
|
||||
CV_R68_VBR = 23,
|
||||
CV_R68_CAAR = 24,
|
||||
CV_R68_ISP = 25,
|
||||
CV_R68_PC = 26,
|
||||
CV_R68_FPCR = 28,
|
||||
CV_R68_FPSR = 29,
|
||||
CV_R68_FPIAR = 30,
|
||||
CV_R68_FP0 = 32, /* this includes FP1 to FP7 */
|
||||
CV_R68_MMUSR030 = 41,
|
||||
CV_R68_MMUSR = 42,
|
||||
CV_R68_URP = 43,
|
||||
CV_R68_DTT0 = 44,
|
||||
CV_R68_DTT1 = 45,
|
||||
CV_R68_ITT0 = 46,
|
||||
CV_R68_ITT1 = 47,
|
||||
CV_R68_PSR = 51,
|
||||
CV_R68_PCSR = 52,
|
||||
CV_R68_VAL = 53,
|
||||
CV_R68_CRP = 54,
|
||||
CV_R68_SRP = 55,
|
||||
CV_R68_DRP = 56,
|
||||
CV_R68_TC = 57,
|
||||
CV_R68_AC = 58,
|
||||
CV_R68_SCC = 59,
|
||||
CV_R68_CAL = 60,
|
||||
CV_R68_TT0 = 61,
|
||||
CV_R68_TT1 = 62,
|
||||
CV_R68_BAD0 = 64, /* this includes BAD1 to BAD7 */
|
||||
CV_R68_BAC0 = 72, /* this includes BAC1 to BAC7 */
|
||||
|
||||
/* MIPS 4000 CPU */
|
||||
CV_M4_NOREG = CV_REG_NONE,
|
||||
CV_M4_IntZERO = 10,
|
||||
CV_M4_IntAT = 11,
|
||||
CV_M4_IntV0 = 12,
|
||||
CV_M4_IntV1 = 13,
|
||||
CV_M4_IntA0 = 14, /* this includes IntA1 to IntA3 */
|
||||
CV_M4_IntT0 = 18, /* this includes IntT1 to IntT7 */
|
||||
CV_M4_IntS0 = 26, /* this includes IntS1 to IntS7 */
|
||||
CV_M4_IntT8 = 34,
|
||||
CV_M4_IntT9 = 35,
|
||||
CV_M4_IntKT0 = 36,
|
||||
CV_M4_IntKT1 = 37,
|
||||
CV_M4_IntGP = 38,
|
||||
CV_M4_IntSP = 39,
|
||||
CV_M4_IntS8 = 40,
|
||||
CV_M4_IntRA = 41,
|
||||
CV_M4_IntLO = 42,
|
||||
CV_M4_IntHI = 43,
|
||||
CV_M4_Fir = 50,
|
||||
CV_M4_Psr = 51,
|
||||
CV_M4_FltF0 = 60, /* this includes FltF1 to Flt31 */
|
||||
CV_M4_FltFsr = 92,
|
||||
|
||||
/* Alpha AXP CPU */
|
||||
CV_ALPHA_NOREG = CV_REG_NONE,
|
||||
CV_ALPHA_FltF0 = 10, /* this includes FltF1 to FltF31 */
|
||||
CV_ALPHA_IntV0 = 42,
|
||||
CV_ALPHA_IntT0 = 43, /* this includes T1 to T7 */
|
||||
CV_ALPHA_IntS0 = 51, /* this includes S1 to S5 */
|
||||
CV_ALPHA_IntFP = 57,
|
||||
CV_ALPHA_IntA0 = 58, /* this includes A1 to A5 */
|
||||
CV_ALPHA_IntT8 = 64,
|
||||
CV_ALPHA_IntT9 = 65,
|
||||
CV_ALPHA_IntT10 = 66,
|
||||
CV_ALPHA_IntT11 = 67,
|
||||
CV_ALPHA_IntRA = 68,
|
||||
CV_ALPHA_IntT12 = 69,
|
||||
CV_ALPHA_IntAT = 70,
|
||||
CV_ALPHA_IntGP = 71,
|
||||
CV_ALPHA_IntSP = 72,
|
||||
CV_ALPHA_IntZERO = 73,
|
||||
CV_ALPHA_Fpcr = 74,
|
||||
CV_ALPHA_Fir = 75,
|
||||
CV_ALPHA_Psr = 76,
|
||||
CV_ALPHA_FltFsr = 77,
|
||||
CV_ALPHA_SoftFpcr = 78,
|
||||
|
||||
/* Motorola & IBM PowerPC CPU */
|
||||
CV_PPC_GPR0 = 1, /* this includes GPR1 to GPR31 */
|
||||
CV_PPC_CR = 33,
|
||||
CV_PPC_CR0 = 34, /* this includes CR1 to CR7 */
|
||||
CV_PPC_FPR0 = 42, /* this includes FPR1 to FPR31 */
|
||||
|
||||
CV_PPC_FPSCR = 74,
|
||||
CV_PPC_MSR = 75,
|
||||
CV_PPC_SR0 = 76, /* this includes SR1 to SR15 */
|
||||
/* some PPC registers missing */
|
||||
|
||||
/* Hitachi SH3 CPU */
|
||||
CV_SH3_NOREG = CV_REG_NONE,
|
||||
CV_SH3_IntR0 = 10, /* this include R1 to R13 */
|
||||
CV_SH3_IntFp = 24,
|
||||
CV_SH3_IntSp = 25,
|
||||
CV_SH3_Gbr = 38,
|
||||
CV_SH3_Pr = 39,
|
||||
CV_SH3_Mach = 40,
|
||||
CV_SH3_Macl = 41,
|
||||
CV_SH3_Pc = 50,
|
||||
CV_SH3_Sr = 51,
|
||||
CV_SH3_BarA = 60,
|
||||
CV_SH3_BasrA = 61,
|
||||
CV_SH3_BamrA = 62,
|
||||
CV_SH3_BbrA = 63,
|
||||
CV_SH3_BarB = 64,
|
||||
CV_SH3_BasrB = 65,
|
||||
CV_SH3_BamrB = 66,
|
||||
CV_SH3_BbrB = 67,
|
||||
CV_SH3_BdrB = 68,
|
||||
CV_SH3_BdmrB = 69,
|
||||
CV_SH3_Brcr = 70,
|
||||
CV_SH_Fpscr = 75,
|
||||
CV_SH_Fpul = 76,
|
||||
CV_SH_FpR0 = 80, /* this includes FpR1 to FpR15 */
|
||||
CV_SH_XFpR0 = 96, /* this includes XFpR1 to XXFpR15 */
|
||||
|
||||
/* ARM CPU */
|
||||
CV_ARM_NOREG = CV_REG_NONE,
|
||||
CV_ARM_R0 = 10, /* this includes R1 to R12 */
|
||||
CV_ARM_SP = 23,
|
||||
CV_ARM_LR = 24,
|
||||
CV_ARM_PC = 25,
|
||||
CV_ARM_CPSR = 26,
|
||||
|
||||
/* Intel IA64 CPU */
|
||||
CV_IA64_NOREG = CV_REG_NONE,
|
||||
CV_IA64_Br0 = 512, /* this includes Br1 to Br7 */
|
||||
CV_IA64_P0 = 704, /* this includes P1 to P63 */
|
||||
CV_IA64_Preds = 768,
|
||||
CV_IA64_IntH0 = 832, /* this includes H1 to H15 */
|
||||
CV_IA64_Ip = 1016,
|
||||
CV_IA64_Umask = 1017,
|
||||
CV_IA64_Cfm = 1018,
|
||||
CV_IA64_Psr = 1019,
|
||||
CV_IA64_Nats = 1020,
|
||||
CV_IA64_Nats2 = 1021,
|
||||
CV_IA64_Nats3 = 1022,
|
||||
CV_IA64_IntR0 = 1024, /* this includes R1 to R127 */
|
||||
CV_IA64_FltF0 = 2048, /* this includes FltF1 to FltF127 */
|
||||
/* some IA64 registers missing */
|
||||
|
||||
/* TriCore CPU */
|
||||
CV_TRI_NOREG = CV_REG_NONE,
|
||||
CV_TRI_D0 = 10, /* includes D1 to D15 */
|
||||
CV_TRI_A0 = 26, /* includes A1 to A15 */
|
||||
CV_TRI_E0 = 42,
|
||||
CV_TRI_E2 = 43,
|
||||
CV_TRI_E4 = 44,
|
||||
CV_TRI_E6 = 45,
|
||||
CV_TRI_E8 = 46,
|
||||
CV_TRI_E10 = 47,
|
||||
CV_TRI_E12 = 48,
|
||||
CV_TRI_E14 = 49,
|
||||
CV_TRI_EA0 = 50,
|
||||
CV_TRI_EA2 = 51,
|
||||
CV_TRI_EA4 = 52,
|
||||
CV_TRI_EA6 = 53,
|
||||
CV_TRI_EA8 = 54,
|
||||
CV_TRI_EA10 = 55,
|
||||
CV_TRI_EA12 = 56,
|
||||
CV_TRI_EA14 = 57,
|
||||
/* some TriCode registers missing */
|
||||
|
||||
/* AM33 (and the likes) CPU */
|
||||
CV_AM33_NOREG = CV_REG_NONE,
|
||||
CV_AM33_E0 = 10, /* this includes E1 to E7 */
|
||||
CV_AM33_A0 = 20, /* this includes A1 to A3 */
|
||||
CV_AM33_D0 = 30, /* this includes D1 to D3 */
|
||||
CV_AM33_FS0 = 40, /* this includes FS1 to FS31 */
|
||||
|
||||
/* Mitsubishi M32R CPU */
|
||||
CV_M32R_NOREG = CV_REG_NONE,
|
||||
CV_M32R_R0 = 10, /* this includes R1 to R11 */
|
||||
CV_M32R_R12 = 22,
|
||||
CV_M32R_R13 = 23,
|
||||
CV_M32R_R14 = 24,
|
||||
CV_M32R_R15 = 25,
|
||||
CV_M32R_PSW = 26,
|
||||
CV_M32R_CBR = 27,
|
||||
CV_M32R_SPI = 28,
|
||||
CV_M32R_SPU = 29,
|
||||
CV_M32R_SPO = 30,
|
||||
CV_M32R_BPC = 31,
|
||||
CV_M32R_ACHI = 32,
|
||||
CV_M32R_ACLO = 33,
|
||||
CV_M32R_PC = 34,
|
||||
} CV_HREG_e;
|
|
@ -205,6 +205,12 @@ typedef struct _IMAGEHLP_DUPLICATE_SYMBOL
|
|||
#define SYMOPT_WILD_UNDERSCORE 0x00000800
|
||||
#define SYMOPT_USE_DEFAULTS 0x00001000
|
||||
#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000
|
||||
#define SYMOPT_PUBLICS_ONLY 0x00004000
|
||||
#define SYMOPT_NO_PUBLICS 0x00008000
|
||||
#define SYMOPT_AUTO_PUBLICS 0x00010000
|
||||
#define SYMOPT_NO_IMAGE_SEARCH 0x00020000
|
||||
#define SYMOPT_SECURE 0x00040000
|
||||
#define SYMOPT_NO_PROMPTS 0x00080000
|
||||
|
||||
#define SYMOPT_DEBUG 0x80000000
|
||||
|
||||
|
@ -235,7 +241,7 @@ typedef struct _DBGHELP_MODLOAD_DATA
|
|||
} MODLOAD_DATA, *PMODLOAD_DATA;
|
||||
|
||||
/*************************
|
||||
* now DBGHELP *
|
||||
* MiniDUMP *
|
||||
*************************/
|
||||
|
||||
/* DebugHelp */
|
||||
|
@ -523,7 +529,6 @@ typedef struct _MINIDUMP_THREAD_LIST
|
|||
MINIDUMP_THREAD Threads[1]; /* FIXME: no support of 0 sized array */
|
||||
} MINIDUMP_THREAD_LIST, *PMINIDUMP_THREAD_LIST;
|
||||
|
||||
|
||||
/*************************
|
||||
* MODULE handling *
|
||||
*************************/
|
||||
|
@ -535,7 +540,7 @@ extern BOOL WINAPI EnumerateLoadedModules(HANDLE hProcess,
|
|||
typedef BOOL (CALLBACK *PSYM_ENUMMODULES_CALLBACK)(PSTR ModuleName, DWORD BaseOfDll,
|
||||
PVOID UserContext);
|
||||
extern BOOL WINAPI SymEnumerateModules(HANDLE hProcess,
|
||||
PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,
|
||||
PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,
|
||||
PVOID UserContext);
|
||||
extern BOOL WINAPI SymGetModuleInfo(HANDLE hProcess, DWORD dwAddr,
|
||||
PIMAGEHLP_MODULE ModuleInfo);
|
||||
|
@ -562,12 +567,26 @@ extern BOOL WINAPI SymUnloadModule(HANDLE hProcess, DWORD BaseOfDll);
|
|||
#define IMAGEHLP_SYMBOL_INFO_CONSTANT SYMF_CONSTANT /* 0x100 */
|
||||
#define IMAGEHLP_SYMBOL_FUNCTION SYMF_FUNCTION /* 0x800 */
|
||||
|
||||
#define SYMFLAG_VALUEPRESENT 0x00000001
|
||||
#define SYMFLAG_REGISTER 0x00000008
|
||||
#define SYMFLAG_REGREL 0x00000010
|
||||
#define SYMFLAG_FRAMEREL 0x00000020
|
||||
#define SYMFLAG_PARAMETER 0x00000040
|
||||
#define SYMFLAG_LOCAL 0x00000080
|
||||
#define SYMFLAG_CONSTANT 0x00000100
|
||||
#define SYMFLAG_EXPORT 0x00000200
|
||||
#define SYMFLAG_FORWARDER 0x00000400
|
||||
#define SYMFLAG_FUNCTION 0x00000800
|
||||
#define SYMFLAG_VIRTUAL 0x00001000
|
||||
#define SYMFLAG_THUNK 0x00002000
|
||||
#define SYMFLAG_TLSREL 0x00004000
|
||||
|
||||
typedef struct _SYMBOL_INFO
|
||||
{
|
||||
ULONG SizeOfStruct;
|
||||
ULONG TypeIndex;
|
||||
ULONG Reserved[2];
|
||||
ULONG Reserved2;
|
||||
ULONG info;
|
||||
ULONG Size;
|
||||
ULONG ModBase;
|
||||
ULONG Flags;
|
||||
|
@ -607,6 +626,9 @@ typedef enum _IMAGEHLP_SYMBOL_TYPE_INFO
|
|||
TI_GET_LEXICALPARENT,
|
||||
TI_GET_ADDRESS,
|
||||
TI_GET_THISADJUST,
|
||||
TI_GET_UDTKIND,
|
||||
TI_IS_EQUIV_TO,
|
||||
TI_GET_CALLING_CONVENTION,
|
||||
} IMAGEHLP_SYMBOL_TYPE_INFO;
|
||||
|
||||
typedef struct _TI_FINDCHILDREN_PARAMS
|
||||
|
@ -616,6 +638,24 @@ typedef struct _TI_FINDCHILDREN_PARAMS
|
|||
ULONG ChildId[1];
|
||||
} TI_FINDCHILDREN_PARAMS;
|
||||
|
||||
#define UNDNAME_COMPLETE (0x0000)
|
||||
#define UNDNAME_NO_LEADING_UNDERSCORES (0x0001)
|
||||
#define UNDNAME_NO_MS_KEYWORDS (0x0002)
|
||||
#define UNDNAME_NO_FUNCTION_RETURNS (0x0004)
|
||||
#define UNDNAME_NO_ALLOCATION_MODEL (0x0008)
|
||||
#define UNDNAME_NO_ALLOCATION_LANGUAGE (0x0010)
|
||||
#define UNDNAME_NO_MS_THISTYPE (0x0020)
|
||||
#define UNDNAME_NO_CV_THISTYPE (0x0040)
|
||||
#define UNDNAME_NO_THISTYPE (0x0060)
|
||||
#define UNDNAME_NO_ACCESS_SPECIFIERS (0x0080)
|
||||
#define UNDNAME_NO_THROW_SIGNATURES (0x0100)
|
||||
#define UNDNAME_NO_MEMBER_TYPE (0x0200)
|
||||
#define UNDNAME_NO_RETURN_UDT_MODEL (0x0400)
|
||||
#define UNDNAME_32_BIT_DECODE (0x0800)
|
||||
#define UNDNAME_NAME_ONLY (0x1000)
|
||||
#define UNDNAME_NO_ARGUMENTS (0x2000)
|
||||
#define UNDNAME_NO_SPECIAL_SYMS (0x4000)
|
||||
|
||||
BOOL WINAPI SymGetTypeInfo(HANDLE hProcess, DWORD ModBase, ULONG TypeId,
|
||||
IMAGEHLP_SYMBOL_TYPE_INFO GetType, PVOID);
|
||||
typedef BOOL (CALLBACK *PSYM_ENUMERATESYMBOLS_CALLBACK)(PSYMBOL_INFO pSymInfo,
|
||||
|
@ -623,11 +663,26 @@ typedef BOOL (CALLBACK *PSYM_ENUMERATESYMBOLS_CALLBACK)(PSYMBOL_INFO pSymInfo,
|
|||
BOOL WINAPI SymEnumTypes(HANDLE hProcess, DWORD BaseOfDll,
|
||||
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
|
||||
PVOID UserContext);
|
||||
BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD addr, DWORD* displacement,
|
||||
SYMBOL_INFO* sym_info);
|
||||
BOOL WINAPI SymFromName(HANDLE hProcess, LPSTR Name, PSYMBOL_INFO Symbol);
|
||||
BOOL WINAPI SymGetTypeFromName(HANDLE hProcess, DWORD BaseOfDll, LPSTR Name,
|
||||
PSYMBOL_INFO Symbol);
|
||||
BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG BaseOfDll, PCSTR Mask,
|
||||
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
|
||||
PVOID UserContext);
|
||||
typedef BOOL (CALLBACK *PSYM_ENUMSYMBOLS_CALLBACK)(PSTR SymbolName, DWORD SymbolAddress,
|
||||
ULONG SymbolSize, PVOID UserContext);
|
||||
BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll,
|
||||
PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback,
|
||||
PVOID UserContext);
|
||||
typedef BOOL (CALLBACK *PSYMBOL_REGISTERED_CALLBACK)(HANDLE hProcess, ULONG ActionCode,
|
||||
PVOID CallbackData, PVOID UserContext);
|
||||
BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
|
||||
PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
|
||||
PVOID UserContext);
|
||||
DWORD WINAPI UnDecorateSymbolName(LPCSTR DecoratedName, LPSTR UnDecoratedName,
|
||||
DWORD UndecoratedLength, DWORD Flags);
|
||||
|
||||
/*************************
|
||||
* Source Files *
|
||||
|
@ -638,6 +693,10 @@ typedef BOOL (CALLBACK *PSYM_ENUMSOURCFILES_CALLBACK)(PSOURCEFILE pSourceFile,
|
|||
BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG ModBase, LPSTR Mask,
|
||||
PSYM_ENUMSOURCFILES_CALLBACK cbSrcFiles,
|
||||
PVOID UserContext);
|
||||
BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr,
|
||||
PDWORD pdwDisplacement, PIMAGEHLP_LINE Line);
|
||||
BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line);
|
||||
BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line);
|
||||
|
||||
/*************************
|
||||
* File & image handling *
|
||||
|
@ -680,6 +739,116 @@ BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
|
|||
PIMAGEHLP_CONTEXT Context);
|
||||
|
||||
|
||||
/*************************
|
||||
* Stack management *
|
||||
*************************/
|
||||
|
||||
typedef struct _KDHELP
|
||||
{
|
||||
DWORD Thread;
|
||||
DWORD ThCallbackStack;
|
||||
DWORD NextCallback;
|
||||
DWORD FramePointer;
|
||||
DWORD KiCallUserMode;
|
||||
DWORD KeUserCallbackDispatcher;
|
||||
DWORD SystemRangeStart;
|
||||
} KDHELP, *PKDHELP;
|
||||
|
||||
typedef struct _STACKFRAME
|
||||
{
|
||||
ADDRESS AddrPC;
|
||||
ADDRESS AddrReturn;
|
||||
ADDRESS AddrFrame;
|
||||
ADDRESS AddrStack;
|
||||
PVOID FuncTableEntry;
|
||||
DWORD Params[4];
|
||||
BOOL Far;
|
||||
BOOL Virtual;
|
||||
DWORD Reserved[3];
|
||||
KDHELP KdHelp;
|
||||
} STACKFRAME, *LPSTACKFRAME;
|
||||
|
||||
typedef BOOL (CALLBACK *PREAD_PROCESS_MEMORY_ROUTINE)
|
||||
(HANDLE hProcess, LPCVOID lpBaseAddress, PVOID lpBuffer,
|
||||
DWORD nSize, PDWORD lpNumberOfBytesRead);
|
||||
|
||||
typedef PVOID (CALLBACK *PFUNCTION_TABLE_ACCESS_ROUTINE)
|
||||
(HANDLE hProcess, DWORD AddrBase);
|
||||
|
||||
typedef DWORD (CALLBACK *PGET_MODULE_BASE_ROUTINE)
|
||||
(HANDLE hProcess, DWORD ReturnAddress);
|
||||
|
||||
typedef DWORD (CALLBACK *PTRANSLATE_ADDRESS_ROUTINE)
|
||||
(HANDLE hProcess, HANDLE hThread, LPADDRESS lpaddr);
|
||||
|
||||
BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
|
||||
LPSTACKFRAME StackFrame, PVOID ContextRecord,
|
||||
PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
|
||||
PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
|
||||
PTRANSLATE_ADDRESS_ROUTINE TranslateAddress);
|
||||
|
||||
PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase);
|
||||
|
||||
/*************************
|
||||
* Version, global stuff *
|
||||
*************************/
|
||||
|
||||
typedef struct API_VERSION
|
||||
{
|
||||
USHORT MajorVersion;
|
||||
USHORT MinorVersion;
|
||||
USHORT Revision;
|
||||
USHORT Reserved;
|
||||
} API_VERSION, *LPAPI_VERSION;
|
||||
|
||||
LPAPI_VERSION WINAPI ImagehlpApiVersion(void);
|
||||
LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion);
|
||||
|
||||
typedef struct _IMAGE_DEBUG_INFORMATION
|
||||
{
|
||||
LIST_ENTRY List;
|
||||
DWORD ReservedSize;
|
||||
PVOID ReservedMappedBase;
|
||||
USHORT ReservedMachine;
|
||||
USHORT ReservedCharacteristics;
|
||||
DWORD ReservedCheckSum;
|
||||
DWORD ImageBase;
|
||||
DWORD SizeOfImage;
|
||||
DWORD ReservedNumberOfSections;
|
||||
PIMAGE_SECTION_HEADER ReservedSections;
|
||||
DWORD ReservedExportedNamesSize;
|
||||
PSTR ReservedExportedNames;
|
||||
DWORD ReservedNumberOfFunctionTableEntries;
|
||||
PIMAGE_FUNCTION_ENTRY ReservedFunctionTableEntries;
|
||||
DWORD ReservedLowestFunctionStartingAddress;
|
||||
DWORD ReservedHighestFunctionEndingAddress;
|
||||
DWORD ReservedNumberOfFpoTableEntries;
|
||||
PFPO_DATA ReservedFpoTableEntries;
|
||||
DWORD SizeOfCoffSymbols;
|
||||
PIMAGE_COFF_SYMBOLS_HEADER CoffSymbols;
|
||||
DWORD ReservedSizeOfCodeViewSymbols;
|
||||
PVOID ReservedCodeViewSymbols;
|
||||
PSTR ImageFilePath;
|
||||
PSTR ImageFileName;
|
||||
PSTR ReservedDebugFilePath;
|
||||
DWORD ReservedTimeDateStamp;
|
||||
BOOL ReservedRomImage;
|
||||
PIMAGE_DEBUG_DIRECTORY ReservedDebugDirectory;
|
||||
DWORD ReservedNumberOfDebugDirectories;
|
||||
DWORD ReservedOriginalFunctionTableBaseAddress;
|
||||
DWORD Reserved[ 2 ];
|
||||
} IMAGE_DEBUG_INFORMATION, *PIMAGE_DEBUG_INFORMATION;
|
||||
|
||||
|
||||
PIMAGE_DEBUG_INFORMATION WINAPI MapDebugInformation(HANDLE FileHandle, PSTR FileName,
|
||||
PSTR SymbolPath, DWORD ImageBase);
|
||||
|
||||
BOOL WINAPI UnmapDebugInformation(PIMAGE_DEBUG_INFORMATION DebugInfo);
|
||||
|
||||
DWORD WINAPI SymGetOptions(void);
|
||||
DWORD WINAPI SymSetOptions(DWORD);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
|
Loading…
Reference in New Issue