First shot at implementing dbghelp.

oldstable
Eric Pouech 2004-04-05 22:21:27 +00:00 committed by Alexandre Julliard
parent 7e301d8a77
commit 800864a050
25 changed files with 10383 additions and 9 deletions

19
configure vendored

File diff suppressed because one or more lines are too long

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,3 @@
Makefile
dbghelp.dll.dbg.c
dbghelp.spec.def

View File

@ -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:

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

2917
dlls/dbghelp/msc.c 100644

File diff suppressed because it is too large Load Diff

106
dlls/dbghelp/path.c 100644
View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

1494
dlls/dbghelp/stabs.c 100644

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

674
dlls/dbghelp/type.c 100644
View File

@ -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;
}

View File

@ -44,6 +44,7 @@ WINDOWS_INCLUDES = \
control.h \
cpl.h \
custcntl.h \
cvconst.h \
d3d.h \
d3d8.h \
d3d8caps.h \

423
include/cvconst.h 100644
View File

@ -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;

View File

@ -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) */