sync dbghelp.dll to wine head. should fix build

svn path=/trunk/; revision=31339
This commit is contained in:
Timo Kreuzer 2007-12-19 21:34:55 +00:00
parent fa17bda2ef
commit 929e7eeba5
25 changed files with 9130 additions and 4868 deletions

View file

@ -3,11 +3,13 @@ TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = dbghelp.dll
IMPORTLIB = libdbghelp.$(IMPLIBEXT)
IMPORTS = psapi kernel32 ntdll
C_SRCS = \
coff.c \
dbghelp.c \
dwarf.c \
elf_module.c \
image.c \
memory.c \
@ -21,9 +23,8 @@ C_SRCS = \
stack.c \
storage.c \
symbol.c \
type.c \
regex.c # ReactOS Port
type.c
@MAKE_DLL_RULES@
### Dependencies:
@DEPENDENCIES@ # everything below this line is overwritten by make depend

View file

@ -18,7 +18,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
@ -48,14 +48,12 @@
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winternl.h"
#include "wine/exception.h"
#include "wine/debug.h"
#include "excpt.h"
#include "dbghelp_private.h"
#include "mscvpdb.h"
#include "wine/mscvpdb.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_coff);
@ -82,7 +80,7 @@ struct CoffFileSet
int nfiles_alloc;
};
static const char* coff_get_name(const IMAGE_SYMBOL* coff_sym,
static const char* coff_get_name(const IMAGE_SYMBOL* coff_sym,
const char* coff_strtab)
{
static char namebuff[9];
@ -120,7 +118,8 @@ static int coff_add_file(struct CoffFileSet* coff_files, struct module* module,
file = coff_files->files + coff_files->nfiles;
file->startaddr = 0xffffffff;
file->endaddr = 0;
file->compiland = symt_new_compiland(module, filename);
file->compiland = symt_new_compiland(module, 0,
source_new(module, NULL, filename));
file->linetab_offset = -1;
file->linecnt = 0;
file->entries = NULL;
@ -137,7 +136,7 @@ static void coff_add_symbol(struct CoffFile* coff_file, struct symt* sym)
coff_file->entries = (coff_file->entries) ?
HeapReAlloc(GetProcessHeap(), 0, coff_file->entries,
coff_file->neps_alloc * sizeof(struct symt*)) :
HeapAlloc(GetProcessHeap(), 0,
HeapAlloc(GetProcessHeap(), 0,
coff_file->neps_alloc * sizeof(struct symt*));
}
coff_file->entries[coff_file->neps++] = sym;
@ -174,10 +173,8 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
coff = (const IMAGE_COFF_SYMBOLS_HEADER*)msc_dbg->root;
coff_symbols = (const IMAGE_SYMBOL*)((unsigned int)coff +
coff->LvaToFirstSymbol);
coff_linetab = (const IMAGE_LINENUMBER*)((unsigned int)coff +
coff->LvaToFirstLinenumber);
coff_symbols = (const IMAGE_SYMBOL*)((const char *)coff + coff->LvaToFirstSymbol);
coff_linetab = (const IMAGE_LINENUMBER*)((const char *)coff + coff->LvaToFirstLinenumber);
coff_strtab = (const char*)(coff_symbols + coff->NumberOfSymbols);
linetab_indx = 0;
@ -189,7 +186,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
if (coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE)
{
curr_file_idx = coff_add_file(&coff_files, msc_dbg->module,
curr_file_idx = coff_add_file(&coff_files, msc_dbg->module,
(const char*)(coff_sym + 1));
TRACE("New file %s\n", (const char*)(coff_sym + 1));
i += naux;
@ -224,12 +221,12 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
fn = source_get(msc_dbg->module,
coff_files.files[curr_file_idx].compiland->source);
TRACE("Duplicating sect from %s: %lx %x %x %d %d\n",
TRACE("Duplicating sect from %s: %x %x %x %d %d\n",
fn, aux->Section.Length,
aux->Section.NumberOfRelocations,
aux->Section.NumberOfLinenumbers,
aux->Section.Number, aux->Section.Selection);
TRACE("More sect %d %s %08lx %d %d %d\n",
TRACE("More sect %d %s %08x %d %d %d\n",
coff_sym->SectionNumber,
coff_get_name(coff_sym, coff_strtab),
coff_sym->Value, coff_sym->Type,
@ -243,7 +240,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
}
else
{
TRACE("New text sect from %s: %lx %x %x %d %d\n",
TRACE("New text sect from %s: %x %x %x %d %d\n",
source_get(msc_dbg->module, coff_files.files[curr_file_idx].compiland->source),
aux->Section.Length,
aux->Section.NumberOfRelocations,
@ -268,7 +265,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
continue;
}
if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0 &&
if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0 &&
coff_sym->SectionNumber == 1)
{
DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
@ -283,8 +280,8 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
/* FIXME: was adding symbol to this_file ??? */
coff_add_symbol(&coff_files.files[curr_file_idx],
&symt_new_function(msc_dbg->module,
coff_files.files[curr_file_idx].compiland,
&symt_new_function(msc_dbg->module,
coff_files.files[curr_file_idx].compiland,
nampnt,
msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
0 /* FIXME */,
@ -300,8 +297,8 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
nampnt = coff_get_name(coff_sym, coff_strtab);
TRACE("%d: %lx %s\n",
i, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
TRACE("%d: %s %s\n",
i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value),
nampnt);
TRACE("\tAdding global symbol %s (sect=%s)\n",
nampnt, msc_dbg->sectp[coff_sym->SectionNumber - 1].Name);
@ -321,13 +318,13 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
if (j < coff_files.nfiles)
{
coff_add_symbol(&coff_files.files[j],
&symt_new_function(msc_dbg->module, compiland, nampnt,
&symt_new_function(msc_dbg->module, compiland, nampnt,
msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
0 /* FIXME */, NULL /* FIXME */)->symt);
}
else
}
else
{
symt_new_function(msc_dbg->module, NULL, nampnt,
symt_new_function(msc_dbg->module, NULL, nampnt,
msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
0 /* FIXME */, NULL /* FIXME */);
}
@ -345,8 +342,8 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
*/
nampnt = coff_get_name(coff_sym, coff_strtab);
TRACE("%d: %lx %s\n",
i, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
TRACE("%d: %s %s\n",
i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value),
nampnt);
TRACE("\tAdding global data symbol %s\n", nampnt);
@ -373,7 +370,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
TRACE("Skipping unknown entry '%s' %d %d %d\n",
coff_get_name(coff_sym, coff_strtab),
coff_sym->StorageClass, coff_sym->SectionNumber, naux);
/*
* For now, skip past the aux entries.
*/
@ -430,7 +427,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
* first.
*/
symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1],
symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1],
coff_files.files[j].compiland->source, linepnt->Linenumber,
msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr);
}
@ -440,13 +437,16 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
for (j = 0; j < coff_files.nfiles; j++)
{
if (coff_files.files[j].entries != NULL)
{
HeapFree(GetProcessHeap(), 0, coff_files.files[j].entries);
}
HeapFree(GetProcessHeap(), 0, coff_files.files[j].entries);
}
HeapFree(GetProcessHeap(), 0, coff_files.files);
msc_dbg->module->module.SymType = SymCoff;
/* FIXME: we could have a finer grain here */
msc_dbg->module->module.LineNumbers = TRUE;
msc_dbg->module->module.GlobalSymbols = TRUE;
msc_dbg->module->module.TypeInfo = FALSE;
msc_dbg->module->module.SourceIndexed = TRUE;
msc_dbg->module->module.Publics = TRUE;
ret = TRUE;
}

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
@ -24,19 +24,25 @@
#include "winerror.h"
#include "psapi.h"
#include "wine/debug.h"
#include "wdbgexts.h"
#include "winnls.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
/* TODO
* - support for symbols' types is still partly missing
* + C++ support
* + funcargtype:s are (partly) wrong: they should be a specific struct (like
* typedef) pointing to the actual type (and not a direct access)
* + we should store the underlying type for an enum in the symt_enum struct
* + for enums, we store the names & values (associated to the enum type),
* + for enums, we store the names & values (associated to the enum type),
* but those values are not directly usable from a debugger (that's why, I
* assume, that we have also to define constants for enum values, as
* assume, that we have also to define constants for enum values, as
* Codeview does BTW.
* + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
* all the types stored/used in the modules (like char*)
* - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
* functions, and even across function blocks...). Basically, for *Next* to work
* it requires an address after the prolog of the func (the base address of the
* func doesn't work)
* - most options (dbghelp_options) are not used (loading lines...)
* - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
* we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
@ -45,18 +51,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
* - msc:
* + we should add parameters' types to the function's signature
* while processing a function's parameters
* + get rid of MSC reading FIXME:s (lots of types are not defined)
* + add support for function-less labels (as MSC seems to define them)
* + C++ management
* - stabs:
* - stabs:
* + when, in a same module, the same definition is used in several compilation
* units, we get several definitions of the same object (especially
* units, we get several definitions of the same object (especially
* struct/union). we should find a way not to duplicate them
* + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
* global variable is defined several times (at different scopes). We are
* getting several of those while looking for a unique symbol. Part of the
* getting several of those while looking for a unique symbol. Part of the
* issue is that we don't give a scope to a static variable inside a function
* + C++ management
* - implement the callback notification mechanism
*/
unsigned dbghelp_options = SYMOPT_UNDNAME;
@ -96,10 +101,43 @@ struct process* process_find_by_handle(HANDLE hProcess)
}
/******************************************************************
* SymSetSearchPath (DBGHELP.@)
* validate_addr64 (internal)
*
*/
BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PSTR searchPath)
BOOL validate_addr64(DWORD64 addr)
{
if (addr >> 32)
{
FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return TRUE;
}
/******************************************************************
* fetch_buffer
*
* Ensures process' internal buffer is large enough.
*/
void* fetch_buffer(struct process* pcs, unsigned size)
{
if (size > pcs->buffer_size)
{
if (pcs->buffer)
pcs->buffer = HeapReAlloc(GetProcessHeap(), 0, pcs->buffer, size);
else
pcs->buffer = HeapAlloc(GetProcessHeap(), 0, size);
pcs->buffer_size = (pcs->buffer) ? size : 0;
}
return pcs->buffer;
}
/******************************************************************
* SymSetSearchPathW (DBGHELP.@)
*
*/
BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath)
{
struct process* pcs = process_find_by_handle(hProcess);
@ -107,23 +145,64 @@ BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PSTR searchPath)
if (!searchPath) return FALSE;
HeapFree(GetProcessHeap(), 0, pcs->search_path);
pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(searchPath) + 1),
searchPath);
pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
(lstrlenW(searchPath) + 1) * sizeof(WCHAR)),
searchPath);
return TRUE;
}
/******************************************************************
* SymSetSearchPath (DBGHELP.@)
*
*/
BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
{
BOOL ret = FALSE;
unsigned len;
WCHAR* sp;
len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0);
if ((sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
{
MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len);
ret = SymSetSearchPathW(hProcess, sp);
HeapFree(GetProcessHeap(), 0, sp);
}
return ret;
}
/***********************************************************************
* SymGetSearchPathW (DBGHELP.@)
*/
BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, PWSTR szSearchPath,
DWORD SearchPathLength)
{
struct process* pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength);
return TRUE;
}
/***********************************************************************
* SymGetSearchPath (DBGHELP.@)
*/
BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath,
BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
DWORD SearchPathLength)
{
struct process* pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
WCHAR* buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR));
BOOL ret = FALSE;
strncpy(szSearchPath, pcs->search_path, SearchPathLength);
szSearchPath[SearchPathLength - 1] = '\0';
return TRUE;
if (buffer)
{
ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength);
if (ret)
WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength,
szSearchPath, SearchPathLength, NULL, NULL);
HeapFree(GetProcessHeap(), 0, buffer);
}
return ret;
}
/******************************************************************
@ -132,34 +211,38 @@ BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath,
* 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)
static BOOL WINAPI process_invade_cb(PCSTR name, ULONG base, ULONG size, PVOID user)
{
HMODULE hMods[256];
char img[256];
DWORD i, sz;
MODULEINFO mi;
char tmp[MAX_PATH];
HANDLE hProcess = user;
if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &sz))
return FALSE; /* FIXME should grow hMods */
if (!GetModuleFileNameExA(hProcess, (HMODULE)base,
tmp, sizeof(tmp)))
lstrcpynA(tmp, name, sizeof(tmp));
for (i = 0; i < sz / sizeof(HMODULE); i++)
{
if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
!GetModuleFileNameExA(hProcess, hMods[i], img, sizeof(img)) ||
!SymLoadModule(hProcess, 0, img, NULL, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage))
return FALSE;
}
return sz != 0;
SymLoadModule(hProcess, 0, tmp, name, base, size);
return TRUE;
}
/******************************************************************
* SymInitialize (DBGHELP.@)
* check_live_target
*
*/
static BOOL check_live_target(struct process* pcs)
{
if (!GetProcessId(pcs->handle)) return FALSE;
if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
elf_read_wine_loader_dbg_info(pcs);
return TRUE;
}
/******************************************************************
* SymInitializeW (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
* 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
@ -168,19 +251,22 @@ static BOOL process_invade(HANDLE hProcess)
* 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
* - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
* hProcess refers to a running process. We use some heuristics here, so YMMV.
* If we detect a live target, then we get the same handling as if
* fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
* 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)
BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess)
{
struct process* pcs;
TRACE("(%p %s %u)\n", hProcess, debugstr_a(UserSearchPath), fInvadeProcess);
TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess);
if (process_find_by_handle(hProcess))
FIXME("what to do ??\n");
@ -192,33 +278,36 @@ BOOL WINAPI SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProc
if (UserSearchPath)
{
pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath) + 1),
UserSearchPath);
pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
(lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)),
UserSearchPath);
}
else
{
unsigned size;
unsigned len;
static const WCHAR sym_path[] = {'_','N','T','_','S','Y','M','B','O','L','_','P','A','T','H',0};
static const WCHAR alt_sym_path[] = {'_','N','T','_','A','L','T','E','R','N','A','T','E','_','S','Y','M','B','O','L','_','P','A','T','H',0};
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);
pcs->search_path = HeapAlloc(GetProcessHeap(), 0, (len = MAX_PATH) * sizeof(WCHAR));
while ((size = GetCurrentDirectoryW(len, pcs->search_path)) >= len)
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (len *= 2) * sizeof(WCHAR));
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1) * sizeof(WCHAR));
len = GetEnvironmentVariableA("_NT_SYMBOL_PATH", NULL, 0);
len = GetEnvironmentVariableW(sym_path, NULL, 0);
if (len)
{
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
pcs->search_path[size] = ';';
GetEnvironmentVariableA("_NT_SYMBOL_PATH", pcs->search_path + size + 1, len);
GetEnvironmentVariableW(sym_path, pcs->search_path + size + 1, len);
size += 1 + len;
}
len = GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", NULL, 0);
len = GetEnvironmentVariableW(alt_sym_path, NULL, 0);
if (len)
{
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
pcs->search_path[size] = ';';
GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", pcs->search_path + size + 1, len);
GetEnvironmentVariableW(alt_sym_path, pcs->search_path + size + 1, len);
size += 1 + len;
}
}
@ -227,23 +316,47 @@ BOOL WINAPI SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProc
pcs->dbg_hdr_addr = 0;
pcs->next = process_first;
process_first = pcs;
if (fInvadeProcess)
if (check_live_target(pcs))
{
#ifndef __REACTOS__
if (!elf_read_wine_loader_dbg_info(pcs))
{
SymCleanup(hProcess);
return FALSE;
}
#endif
process_invade(hProcess);
if (fInvadeProcess)
EnumerateLoadedModules(hProcess, process_invade_cb, hProcess);
elf_synchronize_module_list(pcs);
}
DbgPrint("SymInitialize - Success\n");
else if (fInvadeProcess)
{
SymCleanup(hProcess);
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return TRUE;
}
/******************************************************************
* SymInitialize (DBGHELP.@)
*
*
*/
BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
{
WCHAR* sp = NULL;
BOOL ret;
if (UserSearchPath)
{
unsigned len;
len = MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, NULL, 0);
sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, sp, len);
}
ret = SymInitializeW(hProcess, sp, fInvadeProcess);
HeapFree(GetProcessHeap(), 0, sp);
return ret;
}
/******************************************************************
* SymCleanup (DBGHELP.@)
*
@ -275,6 +388,12 @@ BOOL WINAPI SymCleanup(HANDLE hProcess)
*/
DWORD WINAPI SymSetOptions(DWORD opts)
{
struct process* pcs;
for (pcs = process_first; pcs; pcs = pcs->next)
{
pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
}
return dbghelp_options = opts;
}
@ -287,6 +406,17 @@ DWORD WINAPI SymGetOptions(void)
return dbghelp_options;
}
/******************************************************************
* SymSetParentWindow (DBGHELP.@)
*
*/
BOOL WINAPI SymSetParentWindow(HWND hwnd)
{
/* Save hwnd so it can be used as parent window */
FIXME("(%p): stub\n", hwnd);
return TRUE;
}
/******************************************************************
* SymSetContext (DBGHELP.@)
*
@ -297,21 +427,169 @@ BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
struct process* pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset &&
pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset &&
pcs->ctx_frame.StackOffset == StackFrame->StackOffset)
{
TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
wine_dbgstr_longlong(pcs->ctx_frame.ReturnOffset),
wine_dbgstr_longlong(pcs->ctx_frame.FrameOffset),
wine_dbgstr_longlong(pcs->ctx_frame.StackOffset));
pcs->ctx_frame.InstructionOffset = StackFrame->InstructionOffset;
SetLastError(ERROR_ACCESS_DENIED); /* latest MSDN says ERROR_SUCCESS */
return FALSE;
}
pcs->ctx_frame = *StackFrame;
/* MSDN states that Context is not (no longer?) used */
return TRUE;
}
/******************************************************************
* reg_cb64to32 (internal)
*
* Registered callback for converting information from 64 bit to 32 bit
*/
static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user)
{
PSYMBOL_REGISTERED_CALLBACK cb32 = (PSYMBOL_REGISTERED_CALLBACK)(DWORD)(user >> 32);
DWORD user32 = (DWORD)user;
void* data32;
IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64;
IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
switch (action)
{
case CBA_DEBUG_INFO:
case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
case CBA_SET_OPTIONS:
case CBA_SYMBOLS_UNLOADED:
data32 = (void*)(DWORD)data;
break;
case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
case CBA_DEFERRED_SYMBOL_LOAD_START:
idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD)data;
if (!validate_addr64(idsl64->BaseOfImage))
return FALSE;
idsl.SizeOfStruct = sizeof(idsl);
idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage;
idsl.CheckSum = idsl64->CheckSum;
idsl.TimeDateStamp = idsl64->TimeDateStamp;
memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName));
idsl.Reparse = idsl64->Reparse;
data32 = &idsl;
break;
case CBA_DUPLICATE_SYMBOL:
case CBA_EVENT:
case CBA_READ_MEMORY:
default:
FIXME("No mapping for action %u\n", action);
return FALSE;
}
return cb32(hProcess, action, data32, (PVOID)user32);
}
/******************************************************************
* pcs_callback (internal)
*/
BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
{
TRACE("%p %u %p\n", pcs, action, data);
if (!pcs->reg_cb) return FALSE;
if (!pcs->reg_is_unicode)
{
IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
IMAGEHLP_DEFERRED_SYMBOL_LOADW64* idslW;
switch (action)
{
case CBA_DEBUG_INFO:
case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
case CBA_SET_OPTIONS:
case CBA_SYMBOLS_UNLOADED:
break;
case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
case CBA_DEFERRED_SYMBOL_LOAD_START:
idslW = (IMAGEHLP_DEFERRED_SYMBOL_LOADW64*)(DWORD)data;
idsl.SizeOfStruct = sizeof(idsl);
idsl.BaseOfImage = idslW->BaseOfImage;
idsl.CheckSum = idslW->CheckSum;
idsl.TimeDateStamp = idslW->TimeDateStamp;
WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1,
idsl.FileName, sizeof(idsl.FileName), NULL, NULL);
idsl.Reparse = idslW->Reparse;
data = &idsl;
break;
case CBA_DUPLICATE_SYMBOL:
case CBA_EVENT:
case CBA_READ_MEMORY:
default:
FIXME("No mapping for action %u\n", action);
return FALSE;
}
}
return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
}
/******************************************************************
* sym_register_cb
*
* Helper for registering a callback.
*/
static BOOL sym_register_cb(HANDLE hProcess,
PSYMBOL_REGISTERED_CALLBACK64 cb,
DWORD64 user, BOOL unicode)
{
struct process* pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
pcs->reg_cb = cb;
pcs->reg_is_unicode = unicode;
pcs->reg_user = user;
return TRUE;
}
/***********************************************************************
* SymRegisterCallback (DBGHELP.@)
*/
BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
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;
DWORD64 tmp = ((ULONGLONG)(DWORD)CallbackFunction << 32) | (DWORD)UserContext;
TRACE("(%p, %p, %p)\n",
hProcess, CallbackFunction, UserContext);
return sym_register_cb(hProcess, reg_cb64to32, tmp, FALSE);
}
/***********************************************************************
* SymRegisterCallback64 (DBGHELP.@)
*/
BOOL WINAPI SymRegisterCallback64(HANDLE hProcess,
PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
ULONG64 UserContext)
{
TRACE("(%p, %p, %s)\n",
hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
return sym_register_cb(hProcess, CallbackFunction, UserContext, FALSE);
}
/***********************************************************************
* SymRegisterCallbackW64 (DBGHELP.@)
*/
BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess,
PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
ULONG64 UserContext)
{
TRACE("(%p, %p, %s)\n",
hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
return sym_register_cb(hProcess, CallbackFunction, UserContext, TRUE);
}
/* This is imagehlp version not dbghelp !! */
@ -339,3 +617,20 @@ LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
return AppVersion;
}
/******************************************************************
* ExtensionApiVersion (DBGHELP.@)
*/
LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
{
static EXT_API_VERSION eav = {5, 5, 5, 0};
return &eav;
}
/******************************************************************
* WinDbgExtensionDllInit (DBGHELP.@)
*/
void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
unsigned short major, unsigned short minor)
{
}

View file

@ -3,8 +3,10 @@
<include base="dbghelp">.</include>
<include base="ReactOS">include/reactos/wine</include>
<define name="_WIN32_IE">0x600</define>
<define name="_WIN32_WINNT">0x501</define>
<define name="WINVER">0x501</define>
<define name="_WIN32_WINNT">0x502</define>
<define name="WINVER">0x502</define>
<define name="__WINESRC__" />
<define name="HAVE_REGEX_H" />
<library>wine</library>
<library>pseh</library>
<library>ntdll</library>
@ -12,6 +14,7 @@
<library>psapi</library>
<file>coff.c</file>
<file>dbghelp.c</file>
<file>dwarf.c</file>
<file>elf_module.c</file>
<file>image.c</file>
<file>memory.c</file>

View file

@ -1,13 +1,17 @@
@ stub DbgHelpCreateUserDump
@ stub DbgHelpCreateUserDumpW
@ stdcall EnumDirTree(long str str ptr ptr ptr)
@ stdcall EnumDirTreeW(long wstr wstr ptr ptr ptr)
@ stdcall EnumerateLoadedModules(long ptr ptr)
@ stub EnumerateLoadedModules64
@ stub ExtensionApiVersion
@ stdcall EnumerateLoadedModules64(long ptr ptr)
@ stdcall EnumerateLoadedModulesW64(long ptr ptr)
@ stdcall ExtensionApiVersion()
@ stdcall FindDebugInfoFile(str str ptr)
@ stdcall FindDebugInfoFileEx(str str ptr ptr ptr)
@ stub FindDebugInfoFileExW
@ stdcall FindExecutableImage(str str str)
@ stub FindExecutableImageEx
@ stdcall FindExecutableImageEx(str str ptr ptr ptr)
@ stdcall FindExecutableImageExW(wstr wstr ptr ptr ptr)
@ stub FindFileInPath
@ stub FindFileInSearchPath
@ stdcall GetTimestampForLoadedLibrary(long)
@ -20,80 +24,163 @@
@ stdcall ImagehlpApiVersionEx(ptr)
@ stdcall MakeSureDirectoryPathExists(str)
@ stdcall MapDebugInformation(long str str long)
@ stub MiniDumpReadDumpStream
@ stdcall MiniDumpReadDumpStream(ptr long ptr ptr ptr)
@ stdcall MiniDumpWriteDump(ptr long ptr long long long long)
@ stdcall SearchTreeForFile(str str str)
@ stdcall SearchTreeForFile(str str ptr)
@ stdcall SearchTreeForFileW(wstr wstr ptr)
@ stdcall StackWalk(long long long ptr ptr ptr ptr ptr ptr)
@ stub StackWalk64
@ stdcall StackWalk64(long long long ptr ptr ptr ptr ptr ptr)
@ stub SymAddSymbol
@ stub SymAddSymbolW
@ stdcall SymCleanup(long)
@ stdcall SymEnumSourceFiles(ptr long long str ptr ptr)
@ stdcall SymEnumLines(ptr double str str ptr ptr)
@ stub SymEnumLinesW
@ stdcall SymEnumSourceFiles(ptr double str ptr ptr)
@ stub SymEnumSourceFilesW
@ stub SymEnumSym
@ stdcall SymEnumSymbols(ptr long long str ptr ptr)
@ stdcall SymEnumTypes(ptr long long ptr ptr)
@ stdcall SymEnumSymbols(ptr double str ptr ptr)
@ stdcall SymEnumSymbolsW(ptr double wstr ptr ptr)
@ stub SymEnumSymbolsForAddr
@ stub SymEnumSymbolsForAddrW
@ stdcall SymEnumTypes(ptr double ptr ptr)
@ stdcall SymEnumTypesW(ptr double ptr ptr)
@ stdcall SymEnumerateModules(long ptr ptr)
@ stub SymEnumerateModules64
@ stdcall SymEnumerateModules64(long ptr ptr)
@ stdcall SymEnumerateModulesW64(long ptr ptr)
@ stdcall SymEnumerateSymbols(long long ptr ptr)
@ stub SymEnumerateSymbols64
@ stub SymEnumerateSymbolsW
@ stub SymEnumerateSymbolsW64
@ stub SymFindDebugInfoFile
@ stub SymFindDebugInfoFileW
@ stdcall SymFindFileInPath(long str str ptr long long long ptr ptr ptr)
@ stdcall SymFromAddr(ptr long long ptr ptr)
@ stdcall SymFindFileInPathW(long wstr wstr ptr long long long ptr ptr ptr)
@ stdcall SymFromAddr(ptr double ptr ptr)
@ stdcall SymFromAddrW(ptr double ptr ptr)
@ stub SymFromIndex
@ stub SymFromIndexW
@ stdcall SymFromName(long str ptr)
@ stub SymFromNameW
@ stub SymFromToken
@ stub SymFromTokenW
@ stdcall SymFunctionTableAccess(long long)
@ stub SymFunctionTableAccess64
@ stdcall SymFunctionTableAccess64(long double)
@ stub SymGetFileLineOffsets64
@ stub SymGetHomeDirectory
@ stub SymGetHomeDirectoryW
@ stdcall SymGetLineFromAddr(long long ptr ptr)
@ stub SymGetLineFromAddr64
@ stdcall SymGetLineFromAddr64(long double ptr ptr)
@ stdcall SymGetLineFromAddrW64(long double ptr ptr)
@ stub SymGetLineFromName
@ stub SymGetLineFromName64
@ stdcall SymGetLineNext(long ptr)
@ stub SymGetLineNext64
@ stdcall SymGetLineNext64(long ptr)
@ stub SymGetLineNextW64
@ stdcall SymGetLinePrev(long ptr)
@ stub SymGetLinePrev64
@ stdcall SymGetLinePrev64(long ptr)
@ stub SymGetLinePrevW64
@ stdcall SymGetModuleBase(long long)
@ stub SymGetModuleBase64
@ stdcall SymGetModuleBase64(long double)
@ stdcall SymGetModuleInfo(long long ptr)
@ stub SymGetModuleInfo64
@ stub SymGetModuleInfoW
@ stub SymGetModuleInfoW64
@ stdcall SymGetModuleInfo64(long double ptr)
@ stdcall SymGetModuleInfoW(long long ptr)
@ stdcall SymGetModuleInfoW64(long double ptr)
@ stub SymGetOmapBlockBase
@ stdcall SymGetOptions()
@ stdcall SymGetSearchPath(long str long)
@ stub SymGetScope
@ stub SymGetScopeW
@ stdcall SymGetSearchPath(long ptr long)
@ stdcall SymGetSearchPathW(long ptr long)
@ stub SymGetSourceFileFromToken
@ stub SymGetSourceFileFromTokenW
@ stdcall SymGetSourceFileToken(ptr double str ptr ptr)
@ stdcall SymGetSourceFileTokenW(ptr double wstr ptr ptr)
@ stub SymGetSourceFileW
@ stub SymGetSourceVarFromToken
@ stub SymGetSourceVarFromTokenW
@ stdcall SymGetSymFromAddr(long long ptr ptr)
@ stub SymGetSymFromAddr64
@ stdcall SymGetSymFromAddr64(long double ptr ptr)
@ stdcall SymGetSymFromName(long str ptr)
@ stub SymGetSymFromName64
@ stdcall SymGetSymNext(long ptr)
@ stub SymGetSymNext64
@ stdcall SymGetSymPrev(long ptr)
@ stub SymGetSymPrev64
@ stdcall SymGetTypeFromName(ptr long long str ptr)
@ stdcall SymGetTypeInfo(ptr long long long long ptr)
@ stub SymGetSymbolFile
@ stub SymGetSymbolFileW
@ stdcall SymGetTypeFromName(ptr double str ptr)
@ stub SymGetTypeFromNameW
@ stdcall SymGetTypeInfo(ptr double long long ptr)
@ stub SymGetTypeInfoEx
@ stdcall SymInitialize(long str long)
@ stdcall SymInitializeW(long wstr long)
@ stdcall SymLoadModule(long long str str long long)
@ stub SymLoadModule64
@ stub SymLoadModuleEx
@ stdcall SymLoadModule64(long long str str double long)
@ stdcall SymLoadModuleEx(long long str str double long ptr long)
@ stdcall SymLoadModuleExW(long long wstr wstr double long ptr long)
@ stdcall SymMatchFileName(str str ptr ptr)
@ stub SymMatchString
@ stdcall SymMatchFileNameW(wstr wstr ptr ptr)
@ stdcall SymMatchString(str str long)
@ stub SymMatchStringA
@ stub SymMatchStringW
@ stub SymNext
@ stub SymNextW
@ stub SymPrev
@ stub SymPrevW
@ stub SymRefreshModuleList
@ stdcall SymRegisterCallback(long ptr ptr)
@ stub SymRegisterCallback64
@ stub SymRegisterFunctionEntryCallback
@ stub SymRegisterFunctionEntryCallback64
@ stdcall SymRegisterCallback64(long ptr double)
@ stdcall SymRegisterCallbackW64(long ptr double)
@ stdcall SymRegisterFunctionEntryCallback(ptr ptr ptr)
@ stdcall SymRegisterFunctionEntryCallback64(ptr ptr double)
@ stdcall SymSearch(long double long long str double ptr ptr long)
@ stdcall SymSearchW(long double long long wstr double ptr ptr long)
@ stdcall SymSetContext(long ptr ptr)
@ stub SymSetHomeDirectory
@ stub SymSetHomeDirectoryW
@ stdcall SymSetOptions(long)
@ stdcall SymSetParentWindow(long)
@ stdcall SymSetSearchPath(long str)
@ stdcall SymSetSearchPathW(long wstr)
@ stub SymSetSymWithAddr64
@ stub SymSrvDeltaName
@ stub SymSrvDeltaNameW
@ stub SymSrvGetFileIndexInfo
@ stub SymSrvGetFileIndexInfoW
@ stub SymSrvGetFileIndexString
@ stub SymSrvGetFileIndexStringW
@ stub SymSrvGetFileIndexes
@ stub SymSrvGetFileIndexesW
@ stub SymSrvGetSupplement
@ stub SymSrvGetSupplementW
@ stub SymSrvIsStore
@ stub SymSrvIsStoreW
@ stub SymSrvStoreFile
@ stub SymSrvStoreFileW
@ stub SymSrvStoreSupplement
@ stub SymSrvStoreSupplementW
# @ stub SymSetSymWithAddr64 no longer present ??
@ stdcall SymUnDName(ptr str long)
@ stub SymUnDName64
@ stdcall SymUnloadModule(long long)
@ stub SymUnloadModule64
@ stdcall SymUnloadModule64(long double)
@ stdcall UnDecorateSymbolName(str str long long)
@ stub UnDecorateSymbolNameW
@ stdcall UnmapDebugInformation(ptr)
@ stub WinDbgExtensionDllInit
@ stdcall WinDbgExtensionDllInit(ptr long long)
#@ stub block
#@ stub chksym
#@ stub dbghelp
#@ stub dh
#@ stub lm
#@ stub fptr
#@ stub homedir
#@ stub itoldyouso
#@ stub lmi
#@ stub lminfo
#@ stub omap
#@ stub srcfiles
#@ stub stack_force_ebp
#@ stub stackdbg
#@ stub sym
#@ stub symsrv
#@ stub vc7fpo

View file

@ -4,7 +4,7 @@
* Copyright (C) 1995, Alexandre Julliard
* Copyright (C) 1996, Eric Youngdale.
* Copyright (C) 1999-2000, Ulrich Weigand.
* Copyright (C) 2004, Eric Pouech.
* Copyright (C) 2004-2007, Eric Pouech.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -18,10 +18,9 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define WIN32_NO_STATUS
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
@ -29,6 +28,8 @@
#include "dbghelp.h"
#include "objbase.h"
#include "oaidl.h"
#include "winnls.h"
#include "wine/unicode.h"
#include "cvconst.h"
@ -43,8 +44,6 @@ struct pool /* poor's man */
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
@ -54,15 +53,24 @@ struct vector
unsigned shift;
unsigned num_elts;
unsigned num_buckets;
unsigned buckets_allocated;
};
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 sparse_array
{
struct vector key2index;
struct vector elements;
};
void sparse_array_init(struct sparse_array* sa, unsigned elt_sz, unsigned bucket_sz);
void* sparse_array_find(const struct sparse_array* sa, unsigned long idx);
void* sparse_array_add(struct sparse_array* sa, unsigned long key, struct pool* pool);
unsigned sparse_array_length(const struct sparse_array* sa);
struct hash_table_elt
{
@ -72,8 +80,10 @@ struct hash_table_elt
struct hash_table
{
unsigned num_elts;
unsigned num_buckets;
struct hash_table_elt** buckets;
struct pool* pool;
};
void hash_table_init(struct pool* pool, struct hash_table* ht,
@ -103,6 +113,27 @@ extern unsigned dbghelp_options;
/* some more Wine extensions */
#define SYMOPT_WINE_WITH_ELF_MODULES 0x40000000
enum location_kind {loc_error, /* reg is the error code */
loc_absolute, /* offset is the location */
loc_register, /* reg is the location */
loc_regrel, /* [reg+offset] is the location */
loc_user, /* value is debug information dependent,
reg & offset can be used ad libidem */
};
enum location_error {loc_err_internal = -1, /* internal while computing */
loc_err_too_complex = -2, /* couldn't compute location (even at runtime) */
loc_err_out_of_scope = -3, /* variable isn't available at current address */
loc_err_cant_read = -4, /* couldn't read memory at given address */
};
struct location
{
unsigned kind : 8,
reg;
unsigned long offset;
};
struct symt
{
enum SymTagEnum tag;
@ -127,6 +158,7 @@ struct symt_block
struct symt_compiland
{
struct symt symt;
unsigned long address;
unsigned source;
struct vector vchildren; /* global variables & functions */
};
@ -140,14 +172,25 @@ struct symt_data
struct symt* type;
union /* depends on kind */
{
unsigned long address; /* DataIs{Global, FileStatic} */
/* DataIs{Global, FileStatic}:
* loc.kind is loc_absolute
* loc.offset is address
* DataIs{Local,Param}:
* with loc.kind
* loc_absolute not supported
* loc_register location is in register loc.reg
* loc_regrel location is at address loc.reg + loc.offset
* >= loc_user ask debug info provider for resolution
*/
struct location var;
/* DataIs{Member} (all values are in bits, not bytes) */
struct
{
long offset; /* DataIs{Member,Local,Param} in bits*/
unsigned long length; /* DataIs{Member} in bits */
unsigned long reg_id; /* DataIs{Local} (0 if frame relative) */
} s;
VARIANT value; /* DataIsConstant */
long offset;
unsigned long length;
} member;
/* DataIsConstant */
VARIANT value;
} u;
};
@ -167,7 +210,7 @@ struct symt_function_point
{
struct symt symt; /* either SymTagFunctionDebugStart, SymTagFunctionDebugEnd, SymTagLabel */
struct symt_function* parent;
unsigned long offset;
struct location loc;
const char* name; /* for labels */
};
@ -198,7 +241,8 @@ struct symt_array
struct symt symt;
int start;
int end;
struct symt* basetype;
struct symt* base_type;
struct symt* index_type;
};
struct symt_basic
@ -221,6 +265,14 @@ struct symt_function_signature
struct symt symt;
struct symt* rettype;
struct vector vchildren;
enum CV_call_e call_conv;
};
struct symt_function_arg_type
{
struct symt symt;
struct symt* arg_type;
struct symt* container;
};
struct symt_pointer
@ -250,22 +302,36 @@ enum module_type
DMT_UNKNOWN, /* for lookup, not actually used for a module */
DMT_ELF, /* a real ELF shared module */
DMT_PE, /* a native or builtin PE module */
DMT_PDB, /* PDB file */
};
struct process;
struct module
{
IMAGEHLP_MODULE module;
IMAGEHLP_MODULEW64 module;
/* ANSI copy of module.ModuleName for efficiency */
char module_name[MAX_PATH];
struct module* next;
enum module_type type;
enum module_type type : 16;
unsigned short is_virtual : 1;
/* specific information for debug types */
struct elf_module_info* elf_info;
struct dwarf2_module_info_s*dwarf2_info;
/* memory allocation pool */
struct pool pool;
/* symbol tables */
/* symbols & symbol tables */
int sortlist_valid;
unsigned num_sorttab; /* number of symbols with addresses */
struct symt_ht** addr_sorttab;
struct hash_table ht_symbols;
void (*loc_compute)(struct process* pcs,
const struct module* module,
const struct symt_function* func,
struct location* loc);
/* types */
struct hash_table ht_types;
@ -277,71 +343,147 @@ struct module
char* sources;
};
struct process
struct process
{
struct process* next;
HANDLE handle;
char* search_path;
WCHAR* search_path;
PSYMBOL_REGISTERED_CALLBACK64 reg_cb;
BOOL reg_is_unicode;
DWORD64 reg_user;
struct module* lmodules;
unsigned long dbg_hdr_addr;
IMAGEHLP_STACK_FRAME ctx_frame;
unsigned buffer_size;
void* buffer;
};
struct line_info
{
unsigned long is_first : 1,
is_last : 1,
is_source_file : 1,
line_number;
union
{
unsigned long pc_offset; /* if is_source_file isn't set */
unsigned source_file; /* if is_source_file is set */
} u;
};
struct module_pair
{
struct process* pcs;
struct module* requested; /* in: to module_get_debug() */
struct module* effective; /* out: module with debug info */
};
enum pdb_kind {PDB_JG, PDB_DS};
struct pdb_lookup
{
const char* filename;
DWORD age;
enum pdb_kind kind;
union
{
struct
{
DWORD timestamp;
struct PDB_JG_TOC* toc;
} jg;
struct
{
GUID guid;
struct PDB_DS_TOC* toc;
} ds;
} u;
};
/* dbghelp.c */
extern struct process* process_find_by_handle(HANDLE hProcess);
extern HANDLE hMsvcrt;
extern BOOL validate_addr64(DWORD64 addr);
extern BOOL pcs_callback(const struct process* pcs, ULONG action, void* data);
extern void* fetch_buffer(struct process* pcs, unsigned size);
/* elf_module.c */
extern BOOL elf_load_debug_info(struct module* module);
#define ELF_NO_MAP ((const void*)0xffffffff)
typedef BOOL (*elf_enum_modules_cb)(const WCHAR*, unsigned long addr, void* user);
extern BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb, void*);
extern BOOL elf_fetch_file_info(const WCHAR* name, DWORD* base, DWORD* size, DWORD* checksum);
struct elf_file_map;
extern BOOL elf_load_debug_info(struct module* module, struct elf_file_map* fmap);
extern struct module*
elf_load_module(struct process* pcs, const char* name);
elf_load_module(struct process* pcs, const WCHAR* name, unsigned long);
extern BOOL elf_read_wine_loader_dbg_info(struct process* pcs);
extern BOOL elf_synchronize_module_list(struct process* pcs);
struct elf_thunk_area;
extern int elf_is_in_thunk_area(unsigned long addr, const struct elf_thunk_area* thunks);
extern DWORD WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr);
/* module.c */
extern const WCHAR S_ElfW[];
extern const WCHAR S_WineLoaderW[];
extern const WCHAR S_WinePThreadW[];
extern const WCHAR S_WineKThreadW[];
extern const WCHAR S_SlashW[];
extern struct module*
module_find_by_addr(const struct process* pcs, unsigned long addr,
enum module_type type);
extern struct module*
module_find_by_name(const struct process* pcs,
const char* name, enum module_type type);
const WCHAR* name);
extern struct module*
module_get_debug(const struct process* pcs, struct module*);
module_find_by_nameA(const struct process* pcs,
const char* name);
extern struct module*
module_new(struct process* pcs, const char* name,
enum module_type type, unsigned long addr,
unsigned long size, unsigned long stamp,
unsigned long checksum);
module_is_already_loaded(const struct process* pcs,
const WCHAR* imgname);
extern BOOL module_get_debug(struct module_pair*);
extern struct module*
module_new(struct process* pcs, const WCHAR* name,
enum module_type type, BOOL virtual,
unsigned long addr, unsigned long size,
unsigned long stamp, unsigned long checksum);
extern struct module*
module_get_container(const struct process* pcs,
const struct module* inner);
extern struct module*
module_get_containee(const struct process* pcs,
const struct module* inner);
extern enum module_type
module_get_type_by_name(const WCHAR* name);
extern void module_reset_debug_info(struct module* module);
extern BOOL module_remove(struct process* pcs,
struct module* module);
extern void module_set_module(struct module* module, const WCHAR* name);
/* msc.c */
extern BOOL pe_load_debug_directory(const struct process* pcs,
struct module* module,
struct module* module,
const BYTE* mapping,
const IMAGE_SECTION_HEADER* sectp, DWORD nsect,
const IMAGE_DEBUG_DIRECTORY* dbg, int nDbg);
extern BOOL pdb_fetch_file_info(struct pdb_lookup* pdb_lookup);
/* pe_module.c */
extern BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth);
extern struct module*
pe_load_module(struct process* pcs, char* name,
HANDLE hFile, DWORD base, DWORD size);
pe_load_native_module(struct process* pcs, const WCHAR* 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);
pe_load_builtin_module(struct process* pcs, const WCHAR* name,
DWORD base, DWORD size);
extern BOOL pe_load_debug_info(const struct process* pcs,
struct module* module);
/* source.c */
extern unsigned source_new(struct module* module, const char* source);
extern unsigned source_new(struct module* module, const char* basedir, const char* source);
extern const char* source_get(const struct module* module, unsigned idx);
/* stabs.c */
@ -349,24 +491,35 @@ extern BOOL stabs_parse(struct module* module, unsigned long load_offset
const void* stabs, int stablen,
const char* strs, int strtablen);
/* dwarf.c */
extern BOOL dwarf2_parse(struct module* module, unsigned long load_offset,
const struct elf_thunk_area* thunks,
const unsigned char* debug, unsigned int debug_size,
const unsigned char* abbrev, unsigned int abbrev_size,
const unsigned char* str, unsigned int str_size,
const unsigned char* line, unsigned int line_size,
const unsigned char* loclist, unsigned int loclist_size);
/* symbol.c */
extern const char* symt_get_name(const struct symt* sym);
extern int symt_cmp_addr(const void* p1, const void* p2);
extern int symt_find_nearest(struct module* module, DWORD addr);
extern void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si);
extern struct symt_ht*
symt_find_nearest(struct module* module, DWORD addr);
extern struct symt_compiland*
symt_new_compiland(struct module* module,
const char* filename);
symt_new_compiland(struct module* module, unsigned long address,
unsigned src_idx);
extern struct symt_public*
symt_new_public(struct module* module,
struct symt_compiland* parent,
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,
symt_new_global_variable(struct module* module,
struct symt_compiland* parent,
const char* name, unsigned is_static,
unsigned long addr, unsigned long size,
unsigned long addr, unsigned long size,
struct symt* type);
extern struct symt_function*
symt_new_function(struct module* module,
@ -374,76 +527,83 @@ extern struct symt_function*
const char* name,
unsigned long addr, unsigned long size,
struct symt* type);
extern BOOL symt_normalize_function(struct module* module,
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,
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,
symt_add_func_local(struct module* module,
struct symt_function* func,
enum DataKind dt, const struct location* loc,
struct symt_block* block,
struct symt* type, const char* name);
extern struct symt_block*
symt_open_func_block(struct module* module,
symt_open_func_block(struct module* module,
struct symt_function* func,
struct symt_block* block,
struct symt_block* block,
unsigned pc, unsigned len);
extern struct symt_block*
symt_close_func_block(struct module* module,
symt_close_func_block(struct module* module,
struct symt_function* func,
struct symt_block* block, unsigned pc);
extern struct symt_function_point*
symt_add_function_point(struct module* module,
symt_add_function_point(struct module* module,
struct symt_function* func,
enum SymTagEnum point,
unsigned offset, const char* name);
extern BOOL symt_fill_func_line_info(struct module* module,
struct symt_function* func,
enum SymTagEnum point,
const struct location* loc,
const char* name);
extern BOOL symt_fill_func_line_info(const struct module* module,
const struct symt_function* func,
DWORD addr, IMAGEHLP_LINE* line);
extern BOOL symt_get_func_line_next(struct module* module, PIMAGEHLP_LINE line);
extern BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE line);
extern struct symt_thunk*
symt_new_thunk(struct module* module,
symt_new_thunk(struct module* module,
struct symt_compiland* parent,
const char* name, THUNK_ORDINAL ord,
unsigned long addr, unsigned long size);
extern struct symt_data*
symt_new_constant(struct module* module,
struct symt_compiland* parent,
const char* name, struct symt* type,
const VARIANT* v);
/* 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,
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,
extern BOOL symt_add_udt_element(struct module* module,
struct symt_udt* udt_type,
const char* name,
struct symt* elt_type, unsigned offset,
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,
extern BOOL symt_add_enum_element(struct module* module,
struct symt_enum* enum_type,
const char* name, int value);
extern struct symt_array*
symt_new_array(struct module* module, int min, int max,
struct symt* base);
symt_new_array(struct module* module, int min, int max,
struct symt* base, struct symt* index);
extern struct symt_function_signature*
symt_new_function_signature(struct module* module,
struct symt* ret_type);
symt_new_function_signature(struct module* module,
struct symt* ret_type,
enum CV_call_e call_conv);
extern BOOL symt_add_function_signature_parameter(struct module* module,
struct symt_function_signature* sig,
struct symt* param);
extern struct symt_pointer*
symt_new_pointer(struct module* module,
symt_new_pointer(struct module* module,
struct symt* ref_type);
extern struct symt_typedef*
symt_new_typedef(struct module* module, struct symt* ref,
symt_new_typedef(struct module* module, struct symt* ref,
const char* name);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,403 @@
/*
* dwarf2 definitions
*
* Copyright (C) 2005, Raphael Junqueira
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
typedef struct
{
unsigned char length[4];
unsigned char version[2];
unsigned char abbrev_offset[4];
unsigned char word_size[1];
} dwarf2_comp_unit_stream_t;
typedef struct
{
unsigned long length;
unsigned short version;
unsigned long abbrev_offset;
unsigned char word_size;
} dwarf2_comp_unit_t;
typedef struct
{
unsigned int length;
unsigned short version;
unsigned int prologue_length;
unsigned char min_insn_length;
unsigned char default_is_stmt;
int line_base;
unsigned char line_range;
unsigned char opcode_base;
} dwarf2_line_info_t;
typedef enum dwarf_tag_e
{
DW_TAG_padding = 0x00,
DW_TAG_array_type = 0x01,
DW_TAG_class_type = 0x02,
DW_TAG_entry_point = 0x03,
DW_TAG_enumeration_type = 0x04,
DW_TAG_formal_parameter = 0x05,
DW_TAG_imported_declaration = 0x08,
DW_TAG_label = 0x0a,
DW_TAG_lexical_block = 0x0b,
DW_TAG_member = 0x0d,
DW_TAG_pointer_type = 0x0f,
DW_TAG_reference_type = 0x10,
DW_TAG_compile_unit = 0x11,
DW_TAG_string_type = 0x12,
DW_TAG_structure_type = 0x13,
DW_TAG_subroutine_type = 0x15,
DW_TAG_typedef = 0x16,
DW_TAG_union_type = 0x17,
DW_TAG_unspecified_parameters = 0x18,
DW_TAG_variant = 0x19,
DW_TAG_common_block = 0x1a,
DW_TAG_common_inclusion = 0x1b,
DW_TAG_inheritance = 0x1c,
DW_TAG_inlined_subroutine = 0x1d,
DW_TAG_module = 0x1e,
DW_TAG_ptr_to_member_type = 0x1f,
DW_TAG_set_type = 0x20,
DW_TAG_subrange_type = 0x21,
DW_TAG_with_stmt = 0x22,
DW_TAG_access_declaration = 0x23,
DW_TAG_base_type = 0x24,
DW_TAG_catch_block = 0x25,
DW_TAG_const_type = 0x26,
DW_TAG_constant = 0x27,
DW_TAG_enumerator = 0x28,
DW_TAG_file_type = 0x29,
DW_TAG_friend = 0x2a,
DW_TAG_namelist = 0x2b,
DW_TAG_namelist_item = 0x2c,
DW_TAG_packed_type = 0x2d,
DW_TAG_subprogram = 0x2e,
DW_TAG_template_type_param = 0x2f,
DW_TAG_template_value_param = 0x30,
DW_TAG_thrown_type = 0x31,
DW_TAG_try_block = 0x32,
DW_TAG_variant_part = 0x33,
DW_TAG_variable = 0x34,
DW_TAG_volatile_type = 0x35,
/** extensions */
DW_TAG_MIPS_loop = 0x4081,
DW_TAG_format_label = 0x4101,
DW_TAG_function_template = 0x4102,
DW_TAG_class_template = 0x4103
} dwarf_tag_t;
typedef enum dwarf_attribute_e
{
DW_AT_sibling = 0x01,
DW_AT_location = 0x02,
DW_AT_name = 0x03,
DW_AT_ordering = 0x09,
DW_AT_subscr_data = 0x0a,
DW_AT_byte_size = 0x0b,
DW_AT_bit_offset = 0x0c,
DW_AT_bit_size = 0x0d,
DW_AT_element_list = 0x0f,
DW_AT_stmt_list = 0x10,
DW_AT_low_pc = 0x11,
DW_AT_high_pc = 0x12,
DW_AT_language = 0x13,
DW_AT_member = 0x14,
DW_AT_discr = 0x15,
DW_AT_discr_value = 0x16,
DW_AT_visibility = 0x17,
DW_AT_import = 0x18,
DW_AT_string_length = 0x19,
DW_AT_common_reference = 0x1a,
DW_AT_comp_dir = 0x1b,
DW_AT_const_value = 0x1c,
DW_AT_containing_type = 0x1d,
DW_AT_default_value = 0x1e,
DW_AT_inline = 0x20,
DW_AT_is_optional = 0x21,
DW_AT_lower_bound = 0x22,
DW_AT_producer = 0x25,
DW_AT_prototyped = 0x27,
DW_AT_return_addr = 0x2a,
DW_AT_start_scope = 0x2c,
DW_AT_stride_size = 0x2e,
DW_AT_upper_bound = 0x2f,
DW_AT_abstract_origin = 0x31,
DW_AT_accessibility = 0x32,
DW_AT_address_class = 0x33,
DW_AT_artificial = 0x34,
DW_AT_base_types = 0x35,
DW_AT_calling_convention = 0x36,
DW_AT_count = 0x37,
DW_AT_data_member_location = 0x38,
DW_AT_decl_column = 0x39,
DW_AT_decl_file = 0x3a,
DW_AT_decl_line = 0x3b,
DW_AT_declaration = 0x3c,
DW_AT_discr_list = 0x3d,
DW_AT_encoding = 0x3e,
DW_AT_external = 0x3f,
DW_AT_frame_base = 0x40,
DW_AT_friend = 0x41,
DW_AT_identifier_case = 0x42,
DW_AT_macro_info = 0x43,
DW_AT_namelist_items = 0x44,
DW_AT_priority = 0x45,
DW_AT_segment = 0x46,
DW_AT_specification = 0x47,
DW_AT_static_link = 0x48,
DW_AT_type = 0x49,
DW_AT_use_location = 0x4a,
DW_AT_variable_parameter = 0x4b,
DW_AT_virtuality = 0x4c,
DW_AT_vtable_elem_location = 0x4d,
DW_AT_ranges = 0x55,
/* extensions */
DW_AT_MIPS_fde = 0x2001,
DW_AT_MIPS_loop_begin = 0x2002,
DW_AT_MIPS_tail_loop_begin = 0x2003,
DW_AT_MIPS_epilog_begin = 0x2004,
DW_AT_MIPS_loop_unroll_factor = 0x2005,
DW_AT_MIPS_software_pipeline_depth = 0x2006,
DW_AT_MIPS_linkage_name = 0x2007,
DW_AT_MIPS_stride = 0x2008,
DW_AT_MIPS_abstract_name = 0x2009,
DW_AT_MIPS_clone_origin = 0x200a,
DW_AT_MIPS_has_inlines = 0x200b,
DW_AT_sf_names = 0x2101,
DW_AT_src_info = 0x2102,
DW_AT_mac_info = 0x2103,
DW_AT_src_coords = 0x2104,
DW_AT_body_begin = 0x2105,
DW_AT_body_end = 0x2106
} dwarf_attribute_t;
typedef enum dwarf_form_e
{
DW_FORM_addr = 0x01,
DW_FORM_block2 = 0x03,
DW_FORM_block4 = 0x04,
DW_FORM_data2 = 0x05,
DW_FORM_data4 = 0x06,
DW_FORM_data8 = 0x07,
DW_FORM_string = 0x08,
DW_FORM_block = 0x09,
DW_FORM_block1 = 0x0a,
DW_FORM_data1 = 0x0b,
DW_FORM_flag = 0x0c,
DW_FORM_sdata = 0x0d,
DW_FORM_strp = 0x0e,
DW_FORM_udata = 0x0f,
DW_FORM_ref_addr = 0x10,
DW_FORM_ref1 = 0x11,
DW_FORM_ref2 = 0x12,
DW_FORM_ref4 = 0x13,
DW_FORM_ref8 = 0x14,
DW_FORM_ref_udata = 0x15,
DW_FORM_indirect = 0x16
} dwarf_form_t;
/** type encoding */
typedef enum dwarf_type_e
{
DW_ATE_void = 0x0,
DW_ATE_address = 0x1,
DW_ATE_boolean = 0x2,
DW_ATE_complex_float = 0x3,
DW_ATE_float = 0x4,
DW_ATE_signed = 0x5,
DW_ATE_signed_char = 0x6,
DW_ATE_unsigned = 0x7,
DW_ATE_unsigned_char = 0x8
} dwarf_type_t;
typedef enum dwarf_operation_e
{
DW_OP_addr = 0x03,
DW_OP_deref = 0x06,
DW_OP_const1u = 0x08,
DW_OP_const1s = 0x09,
DW_OP_const2u = 0x0a,
DW_OP_const2s = 0x0b,
DW_OP_const4u = 0x0c,
DW_OP_const4s = 0x0d,
DW_OP_const8u = 0x0e,
DW_OP_const8s = 0x0f,
DW_OP_constu = 0x10,
DW_OP_consts = 0x11,
DW_OP_dup = 0x12,
DW_OP_drop = 0x13,
DW_OP_over = 0x14,
DW_OP_pick = 0x15,
DW_OP_swap = 0x16,
DW_OP_rot = 0x17,
DW_OP_xderef = 0x18,
DW_OP_abs = 0x19,
DW_OP_and = 0x1a,
DW_OP_div = 0x1b,
DW_OP_minus = 0x1c,
DW_OP_mod = 0x1d,
DW_OP_mul = 0x1e,
DW_OP_neg = 0x1f,
DW_OP_not = 0x20,
DW_OP_or = 0x21,
DW_OP_plus = 0x22,
DW_OP_plus_uconst = 0x23,
DW_OP_shl = 0x24,
DW_OP_shr = 0x25,
DW_OP_shra = 0x26,
DW_OP_xor = 0x27,
DW_OP_bra = 0x28,
DW_OP_eq = 0x29,
DW_OP_ge = 0x2a,
DW_OP_gt = 0x2b,
DW_OP_le = 0x2c,
DW_OP_lt = 0x2d,
DW_OP_ne = 0x2e,
DW_OP_skip = 0x2f,
DW_OP_lit0 = 0x30,
DW_OP_lit1 = 0x31,
DW_OP_lit2 = 0x32,
DW_OP_lit3 = 0x33,
DW_OP_lit4 = 0x34,
DW_OP_lit5 = 0x35,
DW_OP_lit6 = 0x36,
DW_OP_lit7 = 0x37,
DW_OP_lit8 = 0x38,
DW_OP_lit9 = 0x39,
DW_OP_lit10 = 0x3a,
DW_OP_lit11 = 0x3b,
DW_OP_lit12 = 0x3c,
DW_OP_lit13 = 0x3d,
DW_OP_lit14 = 0x3e,
DW_OP_lit15 = 0x3f,
DW_OP_lit16 = 0x40,
DW_OP_lit17 = 0x41,
DW_OP_lit18 = 0x42,
DW_OP_lit19 = 0x43,
DW_OP_lit20 = 0x44,
DW_OP_lit21 = 0x45,
DW_OP_lit22 = 0x46,
DW_OP_lit23 = 0x47,
DW_OP_lit24 = 0x48,
DW_OP_lit25 = 0x49,
DW_OP_lit26 = 0x4a,
DW_OP_lit27 = 0x4b,
DW_OP_lit28 = 0x4c,
DW_OP_lit29 = 0x4d,
DW_OP_lit30 = 0x4e,
DW_OP_lit31 = 0x4f,
DW_OP_reg0 = 0x50,
DW_OP_reg1 = 0x51,
DW_OP_reg2 = 0x52,
DW_OP_reg3 = 0x53,
DW_OP_reg4 = 0x54,
DW_OP_reg5 = 0x55,
DW_OP_reg6 = 0x56,
DW_OP_reg7 = 0x57,
DW_OP_reg8 = 0x58,
DW_OP_reg9 = 0x59,
DW_OP_reg10 = 0x5a,
DW_OP_reg11 = 0x5b,
DW_OP_reg12 = 0x5c,
DW_OP_reg13 = 0x5d,
DW_OP_reg14 = 0x5e,
DW_OP_reg15 = 0x5f,
DW_OP_reg16 = 0x60,
DW_OP_reg17 = 0x61,
DW_OP_reg18 = 0x62,
DW_OP_reg19 = 0x63,
DW_OP_reg20 = 0x64,
DW_OP_reg21 = 0x65,
DW_OP_reg22 = 0x66,
DW_OP_reg23 = 0x67,
DW_OP_reg24 = 0x68,
DW_OP_reg25 = 0x69,
DW_OP_reg26 = 0x6a,
DW_OP_reg27 = 0x6b,
DW_OP_reg28 = 0x6c,
DW_OP_reg29 = 0x6d,
DW_OP_reg30 = 0x6e,
DW_OP_reg31 = 0x6f,
DW_OP_breg0 = 0x70,
DW_OP_breg1 = 0x71,
DW_OP_breg2 = 0x72,
DW_OP_breg3 = 0x73,
DW_OP_breg4 = 0x74,
DW_OP_breg5 = 0x75,
DW_OP_breg6 = 0x76,
DW_OP_breg7 = 0x77,
DW_OP_breg8 = 0x78,
DW_OP_breg9 = 0x79,
DW_OP_breg10 = 0x7a,
DW_OP_breg11 = 0x7b,
DW_OP_breg12 = 0x7c,
DW_OP_breg13 = 0x7d,
DW_OP_breg14 = 0x7e,
DW_OP_breg15 = 0x7f,
DW_OP_breg16 = 0x80,
DW_OP_breg17 = 0x81,
DW_OP_breg18 = 0x82,
DW_OP_breg19 = 0x83,
DW_OP_breg20 = 0x84,
DW_OP_breg21 = 0x85,
DW_OP_breg22 = 0x86,
DW_OP_breg23 = 0x87,
DW_OP_breg24 = 0x88,
DW_OP_breg25 = 0x89,
DW_OP_breg26 = 0x8a,
DW_OP_breg27 = 0x8b,
DW_OP_breg28 = 0x8c,
DW_OP_breg29 = 0x8d,
DW_OP_breg30 = 0x8e,
DW_OP_breg31 = 0x8f,
DW_OP_regx = 0x90,
DW_OP_fbreg = 0x91,
DW_OP_bregx = 0x92,
DW_OP_piece = 0x93,
DW_OP_deref_size = 0x94,
DW_OP_xderef_size = 0x95,
DW_OP_nop = 0x96
} dwarf_operation_t;
enum dwarf_calling_convention
{
DW_CC_normal = 0x1,
DW_CC_program = 0x2,
DW_CC_nocall = 0x3
};
#define DW_CC_lo_user 0x40
#define DW_CC_hi_user 0xff
#define DW_LNS_extended_op 0x00
#define DW_LNS_copy 0x01
#define DW_LNS_advance_pc 0x02
#define DW_LNS_advance_line 0x03
#define DW_LNS_set_file 0x04
#define DW_LNS_set_column 0x05
#define DW_LNS_negate_stmt 0x06
#define DW_LNS_set_basic_block 0x07
#define DW_LNS_const_add_pc 0x08
#define DW_LNS_fixed_advance_pc 0x09
#define DW_LNE_end_sequence 0x01
#define DW_LNE_set_address 0x02
#define DW_LNE_define_file 0x03

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
@ -24,7 +24,6 @@
#include <string.h>
#include "dbghelp_private.h"
#include "winreg.h"
#include "winternl.h"
#include "wine/debug.h"
@ -42,10 +41,10 @@ DWORD WINAPI GetTimestampForLoadedLibrary(HMODULE Module)
/***********************************************************************
* MapDebugInformation (DBGHELP.@)
*/
PIMAGE_DEBUG_INFORMATION WINAPI MapDebugInformation(HANDLE FileHandle, LPSTR FileName,
LPSTR SymbolPath, DWORD ImageBase)
PIMAGE_DEBUG_INFORMATION WINAPI MapDebugInformation(HANDLE FileHandle, PCSTR FileName,
PCSTR SymbolPath, ULONG ImageBase)
{
FIXME("(%p, %s, %s, 0x%08lx): stub\n", FileHandle, FileName, SymbolPath, ImageBase);
FIXME("(%p, %s, %s, 0x%08x): stub\n", FileHandle, FileName, SymbolPath, ImageBase);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return NULL;
}

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
@ -39,12 +39,12 @@ DWORD WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr)
{
case AddrMode1616:
if (GetThreadSelectorEntry(hThread, addr->Segment, &le))
return (le.HighWord.Bits.BaseHi << 24) +
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) +
return (le.HighWord.Bits.BaseHi << 24) +
(le.HighWord.Bits.BaseMid << 16) + le.BaseLow + addr->Offset;
break;
case AddrModeReal:
@ -55,7 +55,7 @@ DWORD WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr)
FIXME("Unsupported (yet) mode (%x)\n", addr->Mode);
return 0;
}
FIXME("Failed to linearize address %04x:%08lx (mode %x)\n",
FIXME("Failed to linearize address %04x:%08x (mode %x)\n",
addr->Segment, addr->Offset, addr->Mode);
return 0;
}

View file

@ -1,7 +1,7 @@
/*
* File minidump.c - management of dumps (read & write)
*
* Copyright (C) 2004, Eric Pouech
* Copyright (C) 2004-2005, Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <time.h>
@ -23,75 +23,473 @@
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "dbghelp_private.h"
#include "winternl.h"
#include "psapi.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 ?)
struct dump_memory
{
ULONG base;
ULONG size;
ULONG rva;
};
struct dump_module
{
unsigned is_elf;
ULONG base;
ULONG size;
DWORD timestamp;
DWORD checksum;
WCHAR name[MAX_PATH];
};
struct dump_context
{
/* process & thread information */
HANDLE hProcess;
DWORD pid;
void* pcs_buffer;
SYSTEM_PROCESS_INFORMATION* spi;
/* module information */
struct dump_module* module;
unsigned num_module;
/* exception information */
/* output information */
MINIDUMP_TYPE type;
HANDLE hFile;
RVA rva;
struct dump_memory* mem;
unsigned num_mem;
/* callback information */
MINIDUMP_CALLBACK_INFORMATION* cb;
};
/******************************************************************
* fetch_process_info
*
* reads system wide process information, and make spi point to the record
* for process of id 'pid'
*/
static void DumpException(struct process* pcs, HANDLE hFile, RVA* rva)
static BOOL fetch_process_info(struct dump_context* dc)
{
ULONG buf_size = 0x1000;
NTSTATUS nts;
dc->pcs_buffer = NULL;
if (!(dc->pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size))) return FALSE;
for (;;)
{
nts = NtQuerySystemInformation(SystemProcessInformation,
dc->pcs_buffer, buf_size, NULL);
if (nts != STATUS_INFO_LENGTH_MISMATCH) break;
dc->pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, dc->pcs_buffer,
buf_size *= 2);
if (!dc->pcs_buffer) return FALSE;
}
if (nts == STATUS_SUCCESS)
{
dc->spi = dc->pcs_buffer;
for (;;)
{
if (dc->spi->dwProcessID == dc->pid) return TRUE;
if (!dc->spi->dwOffset) break;
dc->spi = (SYSTEM_PROCESS_INFORMATION*)
((char*)dc->spi + dc->spi->dwOffset);
}
}
HeapFree(GetProcessHeap(), 0, dc->pcs_buffer);
dc->pcs_buffer = NULL;
dc->spi = NULL;
return FALSE;
}
static void fetch_thread_stack(struct dump_context* dc, const void* teb_addr,
const CONTEXT* ctx, MINIDUMP_MEMORY_DESCRIPTOR* mmd)
{
NT_TIB tib;
if (ReadProcessMemory(dc->hProcess, teb_addr, &tib, sizeof(tib), NULL))
{
#ifdef __i386__
/* limiting the stack dumping to the size actually used */
if (ctx->Esp)
mmd->StartOfMemoryRange = (ctx->Esp - 4);
else
mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
#elif defined(__powerpc__)
if (ctx->Iar)
mmd->StartOfMemoryRange = ctx->Iar - 4;
else
mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
#elif defined(__x86_64__)
if (ctx->Rsp)
mmd->StartOfMemoryRange = (ctx->Rsp - 8);
else
mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
#else
#error unsupported CPU
#endif
mmd->Memory.DataSize = (ULONG_PTR)tib.StackBase - mmd->StartOfMemoryRange;
}
}
/******************************************************************
* fetch_thread_info
*
* fetches some information about thread of id 'tid'
*/
static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
const MINIDUMP_EXCEPTION_INFORMATION* except,
MINIDUMP_THREAD* mdThd, CONTEXT* ctx)
{
DWORD tid = dc->spi->ti[thd_idx].dwThreadID;
HANDLE hThread;
THREAD_BASIC_INFORMATION tbi;
memset(ctx, 0, sizeof(*ctx));
mdThd->ThreadId = dc->spi->ti[thd_idx].dwThreadID;
mdThd->SuspendCount = 0;
mdThd->Teb = 0;
mdThd->Stack.StartOfMemoryRange = 0;
mdThd->Stack.Memory.DataSize = 0;
mdThd->Stack.Memory.Rva = 0;
mdThd->ThreadContext.DataSize = 0;
mdThd->ThreadContext.Rva = 0;
mdThd->PriorityClass = dc->spi->ti[thd_idx].dwBasePriority; /* FIXME */
mdThd->Priority = dc->spi->ti[thd_idx].dwCurrentPriority;
if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL)
{
FIXME("Couldn't open thread %u (%u)\n",
dc->spi->ti[thd_idx].dwThreadID, GetLastError());
return FALSE;
}
if (NtQueryInformationThread(hThread, ThreadBasicInformation,
&tbi, sizeof(tbi), NULL) == STATUS_SUCCESS)
{
mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress;
if (tbi.ExitStatus == STILL_ACTIVE)
{
if (tid != GetCurrentThreadId() &&
(mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1)
{
mdThd->SuspendCount--;
ctx->ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(hThread, ctx))
memset(ctx, 0, sizeof(*ctx));
fetch_thread_stack(dc, tbi.TebBaseAddress, ctx, &mdThd->Stack);
ResumeThread(hThread);
}
else if (tid == GetCurrentThreadId() && except)
{
CONTEXT lctx, *pctx;
if (except->ClientPointers)
{
EXCEPTION_POINTERS ep;
ReadProcessMemory(dc->hProcess, except->ExceptionPointers,
&ep, sizeof(ep), NULL);
ReadProcessMemory(dc->hProcess, ep.ContextRecord,
&ctx, sizeof(ctx), NULL);
pctx = &lctx;
}
else pctx = except->ExceptionPointers->ContextRecord;
fetch_thread_stack(dc, tbi.TebBaseAddress, pctx, &mdThd->Stack);
}
}
}
CloseHandle(hThread);
return TRUE;
}
/******************************************************************
* add_module
*
* Add a module to a dump context
*/
static BOOL add_module(struct dump_context* dc, const WCHAR* name,
DWORD base, DWORD size, DWORD timestamp, DWORD checksum,
BOOL is_elf)
{
if (!dc->module)
dc->module = HeapAlloc(GetProcessHeap(), 0,
++dc->num_module * sizeof(*dc->module));
else
dc->module = HeapReAlloc(GetProcessHeap(), 0, dc->module,
++dc->num_module * sizeof(*dc->module));
if (!dc->module) return FALSE;
if (is_elf ||
!GetModuleFileNameExW(dc->hProcess, (HMODULE)base,
dc->module[dc->num_module - 1].name,
sizeof(dc->module[dc->num_module - 1].name) / sizeof(WCHAR)))
lstrcpynW(dc->module[dc->num_module - 1].name, name,
sizeof(dc->module[dc->num_module - 1].name) / sizeof(WCHAR));
dc->module[dc->num_module - 1].base = base;
dc->module[dc->num_module - 1].size = size;
dc->module[dc->num_module - 1].timestamp = timestamp;
dc->module[dc->num_module - 1].checksum = checksum;
dc->module[dc->num_module - 1].is_elf = is_elf;
return TRUE;
}
/******************************************************************
* fetch_pe_module_info_cb
*
* Callback for accumulating in dump_context a PE modules set
*/
static BOOL WINAPI fetch_pe_module_info_cb(PCWSTR name, DWORD64 base, ULONG size,
PVOID user)
{
struct dump_context* dc = (struct dump_context*)user;
IMAGE_NT_HEADERS nth;
if (!validate_addr64(base)) return FALSE;
if (pe_load_nt_header(dc->hProcess, base, &nth))
add_module((struct dump_context*)user, name, base, size,
nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum,
FALSE);
return TRUE;
}
/******************************************************************
* fetch_elf_module_info_cb
*
* Callback for accumulating in dump_context an ELF modules set
*/
static BOOL fetch_elf_module_info_cb(const WCHAR* name, unsigned long base,
void* user)
{
struct dump_context* dc = (struct dump_context*)user;
DWORD rbase, size, checksum;
/* FIXME: there's no relevant timestamp on ELF modules */
/* NB: if we have a non-null base from the live-target use it (whenever
* the ELF module is relocatable or not). If we have a null base (ELF
* module isn't relocatable) then grab its base address from ELF file
*/
if (!elf_fetch_file_info(name, &rbase, &size, &checksum))
size = checksum = 0;
add_module(dc, name, base ? base : rbase, size, 0 /* FIXME */, checksum, TRUE);
return TRUE;
}
static void fetch_module_info(struct dump_context* dc)
{
EnumerateLoadedModulesW64(dc->hProcess, fetch_pe_module_info_cb, dc);
/* Since we include ELF modules in a separate stream from the regular PE ones,
* we can always include those ELF modules (they don't eat lots of space)
* And it's always a good idea to have a trace of the loaded ELF modules for
* a given application in a post mortem debugging condition.
*/
elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc);
}
/******************************************************************
* add_memory_block
*
* Add a memory block to be dumped in a minidump
* If rva is non 0, it's the rva in the minidump where has to be stored
* also the rva of the memory block when written (this allows to reference
* a memory block from outside the list of memory blocks).
*/
static void add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva)
{
if (dc->mem)
dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem,
++dc->num_mem * sizeof(*dc->mem));
else
dc->mem = HeapAlloc(GetProcessHeap(), 0, ++dc->num_mem * sizeof(*dc->mem));
if (dc->mem)
{
dc->mem[dc->num_mem - 1].base = base;
dc->mem[dc->num_mem - 1].size = size;
dc->mem[dc->num_mem - 1].rva = rva;
}
else dc->num_mem = 0;
}
/******************************************************************
* writeat
*
* Writes a chunk of data at a given position in the minidump
*/
static void writeat(struct dump_context* dc, RVA rva, const void* data, unsigned size)
{
DWORD written;
SetFilePointer(dc->hFile, rva, NULL, FILE_BEGIN);
WriteFile(dc->hFile, data, size, &written, NULL);
}
/******************************************************************
* append
*
* writes a new chunk of data to the minidump, increasing the current
* rva in dc
*/
static void append(struct dump_context* dc, void* data, unsigned size)
{
writeat(dc, dc->rva, data, size);
dc->rva += size;
}
/******************************************************************
* dump_exception_info
*
* Write in File the exception information from pcs
*/
static void dump_exception_info(struct dump_context* dc,
const MINIDUMP_EXCEPTION_INFORMATION* except)
{
MINIDUMP_EXCEPTION_STREAM mdExcpt;
EXCEPTION_RECORD rec, *prec;
CONTEXT ctx, *pctx;
int i;
mdExcpt.ThreadId = DEBUG_CurrThread->tid;
mdExcpt.ThreadId = except->ThreadId;
mdExcpt.__alignment = 0;
mdExcpt.ExceptionRecord.
if (except->ClientPointers)
{
EXCEPTION_POINTERS ep;
ULONG ExceptionCode;
ULONG ExceptionFlags;
ULONGLONG ExceptionRecord;
ULONGLONG ExceptionAddress;
ULONG NumberParameters;
ULONG __unusedAlignment;
ULONGLONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
ReadProcessMemory(dc->hProcess,
except->ExceptionPointers, &ep, sizeof(ep), NULL);
ReadProcessMemory(dc->hProcess,
ep.ExceptionRecord, &rec, sizeof(rec), NULL);
ReadProcessMemory(dc->hProcess,
ep.ContextRecord, &ctx, sizeof(ctx), NULL);
prec = &rec;
pctx = &ctx;
}
else
{
prec = except->ExceptionPointers->ExceptionRecord;
pctx = except->ExceptionPointers->ContextRecord;
}
mdExcpt.ExceptionRecord.ExceptionCode = prec->ExceptionCode;
mdExcpt.ExceptionRecord.ExceptionFlags = prec->ExceptionFlags;
mdExcpt.ExceptionRecord.ExceptionRecord = (DWORD_PTR)prec->ExceptionRecord;
mdExcpt.ExceptionRecord.ExceptionAddress = (DWORD_PTR)prec->ExceptionAddress;
mdExcpt.ExceptionRecord.NumberParameters = prec->NumberParameters;
mdExcpt.ExceptionRecord.__unusedAlignment = 0;
for (i = 0; i < mdExcpt.ExceptionRecord.NumberParameters; i++)
mdExcpt.ExceptionRecord.ExceptionInformation[i] = (DWORD_PTR)prec->ExceptionInformation[i];
mdExcpt.ThreadContext.DataSize = sizeof(*pctx);
mdExcpt.ThreadContext.Rva = dc->rva + sizeof(mdExcpt);
append(dc, &mdExcpt, sizeof(mdExcpt));
append(dc, pctx, sizeof(*pctx));
}
#endif
/******************************************************************
* dump_modules
*
* Write in File the modules from pcs
*/
static void dump_modules(struct process* pcs, HANDLE hFile, RVA* rva)
static void dump_modules(struct dump_context* dc, BOOL dump_elf)
{
MINIDUMP_MODULE mdModule;
MINIDUMP_MODULE_LIST mdModuleList;
DWORD written;
struct module* module = NULL;
char tmp[1024];
MINIDUMP_STRING* ms = (MINIDUMP_STRING*)tmp;
ULONG i, nmod;
RVA rva_base;
DWORD flags_out;
for (i = nmod = 0; i < dc->num_module; i++)
{
if ((dc->module[i].is_elf && dump_elf) ||
(!dc->module[i].is_elf && !dump_elf))
nmod++;
}
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)
/* reserve space for mdModuleList
* FIXME: since we don't support 0 length arrays, we cannot use the
* size of mdModuleList
* FIXME: if we don't ask for all modules in cb, we'll get a hole in the file
*/
rva_base = dc->rva;
dc->rva += sizeof(mdModuleList.NumberOfModules) + sizeof(mdModule) * nmod;
for (i = 0; i < dc->num_module; i++)
{
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");
if ((dc->module[i].is_elf && !dump_elf) ||
(!dc->module[i].is_elf && dump_elf))
continue;
flags_out = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteCvRecord;
if (dc->type & MiniDumpWithDataSegs)
flags_out |= ModuleWriteDataSeg;
if (dc->type & MiniDumpWithProcessThreadData)
flags_out |= ModuleWriteTlsData;
if (dc->type & MiniDumpWithCodeSegs)
flags_out |= ModuleWriteCodeSegs;
ms->Length = (lstrlenW(dc->module[i].name) + 1) * sizeof(WCHAR);
if (sizeof(ULONG) + ms->Length > sizeof(tmp))
FIXME("Buffer overflow!!!\n");
lstrcpyW(ms->Buffer, dc->module[i].name);
if (dc->cb)
{
MINIDUMP_CALLBACK_INPUT cbin;
MINIDUMP_CALLBACK_OUTPUT cbout;
cbin.ProcessId = dc->pid;
cbin.ProcessHandle = dc->hProcess;
cbin.CallbackType = ModuleCallback;
cbin.u.Module.FullPath = ms->Buffer;
cbin.u.Module.BaseOfImage = dc->module[i].base;
cbin.u.Module.SizeOfImage = dc->module[i].size;
cbin.u.Module.CheckSum = dc->module[i].checksum;
cbin.u.Module.TimeDateStamp = dc->module[i].timestamp;
memset(&cbin.u.Module.VersionInfo, 0, sizeof(cbin.u.Module.VersionInfo));
cbin.u.Module.CvRecord = NULL;
cbin.u.Module.SizeOfCvRecord = 0;
cbin.u.Module.MiscRecord = NULL;
cbin.u.Module.SizeOfMiscRecord = 0;
cbout.u.ModuleWriteFlags = flags_out;
if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
continue;
flags_out &= cbout.u.ModuleWriteFlags;
}
if (flags_out & ModuleWriteModule)
{
mdModule.BaseOfImage = dc->module[i].base;
mdModule.SizeOfImage = dc->module[i].size;
mdModule.CheckSum = dc->module[i].checksum;
mdModule.TimeDateStamp = dc->module[i].timestamp;
mdModule.ModuleNameRva = dc->rva;
ms->Length -= sizeof(WCHAR);
append(dc, ms, sizeof(ULONG) + ms->Length + sizeof(WCHAR));
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; /* FIXME */
mdModule.Reserved1 = 0; /* FIXME */
writeat(dc,
rva_base + sizeof(mdModuleList.NumberOfModules) +
mdModuleList.NumberOfModules++ * sizeof(mdModule),
&mdModule, sizeof(mdModule));
}
}
writeat(dc, rva_base, &mdModuleList.NumberOfModules,
sizeof(mdModuleList.NumberOfModules));
}
/******************************************************************
@ -99,34 +497,39 @@ static void dump_modules(struct process* pcs, HANDLE hFile, RVA* rva)
*
* Dumps into File the information about the system
*/
static void dump_system_info(struct process* pcs, HANDLE hFile, RVA* rva)
static void dump_system_info(struct dump_context* dc)
{
MINIDUMP_SYSTEM_INFO mdSysInfo;
SYSTEM_INFO sysInfo;
OSVERSIONINFOA osInfo;
OSVERSIONINFOW osInfo;
DWORD written;
ULONG slen;
GetSystemInfo(&sysInfo);
GetVersionExA(&osInfo);
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
GetVersionExW(&osInfo);
mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
mdSysInfo.Reserved0 = 0;
mdSysInfo.u.s.NumberOfProcessors = sysInfo.dwNumberOfProcessors;
mdSysInfo.u.s.ProductType = VER_NT_WORKSTATION; /* FIXME */
mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
mdSysInfo.PlatformId = osInfo.dwPlatformId;
mdSysInfo.CSDVersionRva = *rva + sizeof(mdSysInfo);
mdSysInfo.Reserved1 = 0;
mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo);
mdSysInfo.u1.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;
memset(&mdSysInfo.Cpu, 0, sizeof(mdSysInfo.Cpu));
append(dc, &mdSysInfo, sizeof(mdSysInfo));
slen = lstrlenW(osInfo.szCSDVersion) * sizeof(WCHAR);
WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
WriteFile(dc->hFile, osInfo.szCSDVersion, slen, &written, NULL);
dc->rva += sizeof(ULONG) + slen;
}
/******************************************************************
@ -134,65 +537,175 @@ static void dump_system_info(struct process* pcs, HANDLE hFile, RVA* rva)
*
* Dumps into File the information about running threads
*/
static void dump_threads(struct process* pcs, HANDLE hFile, RVA* rva)
static void dump_threads(struct dump_context* dc,
const MINIDUMP_EXCEPTION_INFORMATION* except)
{
#if 0
MINIDUMP_THREAD mdThd;
MINIDUMP_THREAD_LIST mdThdList;
DWORD written;
DBG_THREAD* thd;
unsigned i;
RVA rva_base;
DWORD flags_out;
CONTEXT ctx;
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)
mdThdList.NumberOfThreads = 0;
rva_base = dc->rva;
dc->rva += sizeof(mdThdList.NumberOfThreads) +
dc->spi->dwThreadCount * sizeof(mdThd);
for (i = 0; i < dc->spi->dwThreadCount; i++)
{
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 */
fetch_thread_info(dc, i, except, &mdThd, &ctx);
WriteFile(hFile, &mdThd, sizeof(mdThd), &written, NULL);
FIXME("Stack & thread context not written\n");
flags_out = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext |
ThreadWriteInstructionWindow;
if (dc->type & MiniDumpWithProcessThreadData)
flags_out |= ThreadWriteThreadData;
if (dc->type & MiniDumpWithThreadInfo)
flags_out |= ThreadWriteThreadInfo;
if (dc->cb)
{
MINIDUMP_CALLBACK_INPUT cbin;
MINIDUMP_CALLBACK_OUTPUT cbout;
cbin.ProcessId = dc->pid;
cbin.ProcessHandle = dc->hProcess;
cbin.CallbackType = ThreadCallback;
cbin.u.Thread.ThreadId = dc->spi->ti[i].dwThreadID;
cbin.u.Thread.ThreadHandle = 0; /* FIXME */
memcpy(&cbin.u.Thread.Context, &ctx, sizeof(CONTEXT));
cbin.u.Thread.SizeOfContext = sizeof(CONTEXT);
cbin.u.Thread.StackBase = mdThd.Stack.StartOfMemoryRange;
cbin.u.Thread.StackEnd = mdThd.Stack.StartOfMemoryRange +
mdThd.Stack.Memory.DataSize;
cbout.u.ThreadWriteFlags = flags_out;
if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
continue;
flags_out &= cbout.u.ThreadWriteFlags;
}
if (flags_out & ThreadWriteThread)
{
if (ctx.ContextFlags && (flags_out & ThreadWriteContext))
{
mdThd.ThreadContext.Rva = dc->rva;
mdThd.ThreadContext.DataSize = sizeof(CONTEXT);
append(dc, &ctx, sizeof(CONTEXT));
}
if (mdThd.Stack.Memory.DataSize && (flags_out & ThreadWriteStack))
{
add_memory_block(dc, mdThd.Stack.StartOfMemoryRange,
mdThd.Stack.Memory.DataSize,
rva_base + sizeof(mdThdList.NumberOfThreads) +
mdThdList.NumberOfThreads * sizeof(mdThd) +
FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva));
}
writeat(dc,
rva_base + sizeof(mdThdList.NumberOfThreads) +
mdThdList.NumberOfThreads * sizeof(mdThd),
&mdThd, sizeof(mdThd));
mdThdList.NumberOfThreads++;
}
if (ctx.ContextFlags && (flags_out & ThreadWriteInstructionWindow))
{
/* FIXME: - Native dbghelp also dumps 0x80 bytes around EIP
* - also crop values across module boundaries,
* - and don't make it i386 dependent
*/
/* add_memory_block(dc, ctx.Eip - 0x80, ctx.Eip + 0x80, 0); */
}
}
#endif
writeat(dc, rva_base,
&mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads));
}
/******************************************************************
* dump_memory_info
*
* dumps information about the memory of the process (stack of the threads)
*/
static void dump_memory_info(struct dump_context* dc)
{
MINIDUMP_MEMORY_LIST mdMemList;
MINIDUMP_MEMORY_DESCRIPTOR mdMem;
DWORD written;
unsigned i, pos, len;
RVA rva_base;
char tmp[1024];
mdMemList.NumberOfMemoryRanges = dc->num_mem;
append(dc, &mdMemList.NumberOfMemoryRanges,
sizeof(mdMemList.NumberOfMemoryRanges));
rva_base = dc->rva;
dc->rva += mdMemList.NumberOfMemoryRanges * sizeof(mdMem);
for (i = 0; i < dc->num_mem; i++)
{
mdMem.StartOfMemoryRange = dc->mem[i].base;
mdMem.Memory.Rva = dc->rva;
mdMem.Memory.DataSize = dc->mem[i].size;
SetFilePointer(dc->hFile, dc->rva, NULL, FILE_BEGIN);
for (pos = 0; pos < dc->mem[i].size; pos += sizeof(tmp))
{
len = min(dc->mem[i].size - pos, sizeof(tmp));
if (ReadProcessMemory(dc->hProcess,
(void*)(ULONG)(dc->mem[i].base + pos),
tmp, len, NULL))
WriteFile(dc->hFile, tmp, len, &written, NULL);
}
dc->rva += mdMem.Memory.DataSize;
writeat(dc, rva_base + i * sizeof(mdMem), &mdMem, sizeof(mdMem));
if (dc->mem[i].rva)
{
writeat(dc, dc->mem[i].rva, &mdMem.Memory.Rva, sizeof(mdMem.Memory.Rva));
}
}
}
static void dump_misc_info(struct dump_context* dc)
{
MINIDUMP_MISC_INFO mmi;
mmi.SizeOfInfo = sizeof(mmi);
mmi.Flags1 = MINIDUMP_MISC1_PROCESS_ID;
mmi.ProcessId = dc->pid;
/* FIXME: create/user/kernel time */
append(dc, &mmi, sizeof(mmi));
}
/******************************************************************
* MiniDumpWriteDump (DEBUGHLP.@)
*
*
*/
BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, 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;
DWORD i, nStreams, idx_stream;
struct dump_context dc;
pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE; /* FIXME: should try to load it ??? */
dc.hProcess = hProcess;
dc.hFile = hFile;
dc.pid = pid;
dc.module = NULL;
dc.num_module = 0;
dc.cb = CallbackParam;
dc.type = DumpType;
dc.mem = NULL;
dc.num_mem = 0;
dc.rva = 0;
if (!fetch_process_info(&dc)) return FALSE;
fetch_module_info(&dc);
/* 1) init */
nStream = UserStreamParam ? UserStreamParam->UserStreamCount : 0;
addStream = 0;
if (DumpType & MiniDumpNormal)
addStream += 3; /* sure ? thread stack back trace */
nStreams = 6 + (ExceptionParam ? 1 : 0) +
(UserStreamParam ? UserStreamParam->UserStreamCount : 0);
if (DumpType & MiniDumpWithDataSegs)
FIXME("NIY MiniDumpWithDataSegs\n");
@ -206,61 +719,123 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
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.NumberOfStreams = nStreams;
mdHead.StreamDirectoryRva = sizeof(mdHead);
mdHead.u.TimeDateStamp = time(NULL);
mdHead.Flags = DumpType;
WriteFile(hFile, &mdHead, sizeof(mdHead), &written, NULL);
append(&dc, &mdHead, sizeof(mdHead));
/* 3) write stream directories */
rva += (nStream + addStream) * sizeof(mdDir);
dc.rva += nStreams * sizeof(mdDir);
idx_stream = 0;
/* 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);
mdDir.Location.Rva = dc.rva;
dump_threads(&dc, ExceptionParam);
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
&mdDir, sizeof(mdDir));
mdDir.StreamType = ModuleListStream;
mdDir.Location.Rva = dc.rva;
dump_modules(&dc, FALSE);
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
&mdDir, sizeof(mdDir));
mdDir.StreamType = 0xfff0; /* FIXME: this is part of MS reserved streams */
mdDir.Location.Rva = dc.rva;
dump_modules(&dc, TRUE);
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
&mdDir, sizeof(mdDir));
mdDir.StreamType = MemoryListStream;
mdDir.Location.Rva = dc.rva;
dump_memory_info(&dc);
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
&mdDir, sizeof(mdDir));
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);
mdDir.Location.Rva = dc.rva;
dump_system_info(&dc);
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
&mdDir, sizeof(mdDir));
/* 3.2) write user define stream */
for (i = 0; i < nStream; i++)
mdDir.StreamType = MiscInfoStream;
mdDir.Location.Rva = dc.rva;
dump_misc_info(&dc);
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
&mdDir, sizeof(mdDir));
/* 3.2) write exception information (if any) */
if (ExceptionParam)
{
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);
mdDir.StreamType = ExceptionStream;
mdDir.Location.Rva = dc.rva;
dump_exception_info(&dc, ExceptionParam);
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
&mdDir, sizeof(mdDir));
}
/* 3.3) write user defined streams (if any) */
if (UserStreamParam)
{
for (i = 0; i < UserStreamParam->UserStreamCount; i++)
{
mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
mdDir.Location.Rva = dc.rva;
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
&mdDir, sizeof(mdDir));
append(&dc, UserStreamParam->UserStreamArray[i].Buffer,
UserStreamParam->UserStreamArray[i].BufferSize);
}
}
HeapFree(GetProcessHeap(), 0, dc.pcs_buffer);
HeapFree(GetProcessHeap(), 0, dc.mem);
HeapFree(GetProcessHeap(), 0, dc.module);
return TRUE;
}
/******************************************************************
* MiniDumpReadDumpStream (DEBUGHLP.@)
*
*
*/
BOOL WINAPI MiniDumpReadDumpStream(PVOID base, ULONG str_idx,
PMINIDUMP_DIRECTORY* pdir,
PVOID* stream, ULONG* size)
{
MINIDUMP_HEADER* mdHead = (MINIDUMP_HEADER*)base;
if (mdHead->Signature == MINIDUMP_SIGNATURE)
{
MINIDUMP_DIRECTORY* dir;
int i;
dir = (MINIDUMP_DIRECTORY*)((char*)base + mdHead->StreamDirectoryRva);
for (i = 0; i < mdHead->NumberOfStreams; i++, dir++)
{
if (dir->StreamType == str_idx)
{
*pdir = dir;
*stream = (char*)base + dir->Location.Rva;
*size = dir->Location.DataSize;
return TRUE;
}
}
}
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
@ -24,25 +24,36 @@
#include <string.h>
#include "dbghelp_private.h"
#include "winnls.h"
#include "winternl.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
static __inline BOOL is_sep(char ch) {return ch == '/' || ch == '\\';}
static inline BOOL is_sep(char ch) {return ch == '/' || ch == '\\';}
static inline BOOL is_sepW(WCHAR ch) {return ch == '/' || ch == '\\';}
static __inline char* file_name(char* str)
static inline const char* file_name(const char* str)
{
char* p;
const char* p;
for (p = str + strlen(str) - 1; p >= str && !is_sep(*p); p--);
return p + 1;
}
static inline const WCHAR* file_nameW(const WCHAR* str)
{
const WCHAR* p;
for (p = str + strlenW(str) - 1; p >= str && !is_sepW(*p); p--);
return p + 1;
}
/******************************************************************
* FindDebugInfoFile (DBGHELP.@)
*
*/
HANDLE WINAPI FindDebugInfoFile(PSTR FileName, PSTR SymbolPath, PSTR DebugFilePath)
HANDLE WINAPI FindDebugInfoFile(PCSTR FileName, PCSTR SymbolPath, PSTR DebugFilePath)
{
HANDLE h;
@ -57,28 +68,48 @@ HANDLE WINAPI FindDebugInfoFile(PSTR FileName, PSTR SymbolPath, PSTR DebugFilePa
}
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}
/******************************************************************
* FindDebugInfoFileEx (DBGHELP.@)
*
*/
HANDLE WINAPI FindDebugInfoFileEx(PSTR FileName, PSTR SymbolPath,
PSTR DebugFilePath,
HANDLE WINAPI FindDebugInfoFileEx(PCSTR FileName, PCSTR SymbolPath,
PSTR DebugFilePath,
PFIND_DEBUG_FILE_CALLBACK Callback,
PVOID CallerData)
{
FIXME("(%s %s %p %p %p): stub\n",
FIXME("(%s %s %p %p %p): stub\n",
FileName, SymbolPath, DebugFilePath, Callback, CallerData);
return NULL;
}
/******************************************************************
* FindExecutableImage (DBGHELP.@)
* FindExecutableImageExW (DBGHELP.@)
*
*/
HANDLE WINAPI FindExecutableImage(PSTR FileName, PSTR SymbolPath, PSTR ImageFilePath)
HANDLE WINAPI FindExecutableImageExW(PCWSTR FileName, PCWSTR SymbolPath, PWSTR ImageFilePath,
PFIND_EXE_FILE_CALLBACKW Callback, PVOID user)
{
HANDLE h;
if (Callback) FIXME("Unsupported callback yet\n");
if (!SearchPathW(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
return NULL;
h = CreateFileW(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}
/******************************************************************
* FindExecutableImageEx (DBGHELP.@)
*
*/
HANDLE WINAPI FindExecutableImageEx(PCSTR FileName, PCSTR SymbolPath, PSTR ImageFilePath,
PFIND_EXE_FILE_CALLBACK Callback, PVOID user)
{
HANDLE h;
if (Callback) FIXME("Unsupported callback yet\n");
if (!SearchPathA(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
return NULL;
h = CreateFileA(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
@ -86,10 +117,19 @@ HANDLE WINAPI FindExecutableImage(PSTR FileName, PSTR SymbolPath, PSTR ImageFile
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}
/******************************************************************
* FindExecutableImage (DBGHELP.@)
*
*/
HANDLE WINAPI FindExecutableImage(PCSTR FileName, PCSTR SymbolPath, PSTR ImageFilePath)
{
return FindExecutableImageEx(FileName, SymbolPath, ImageFilePath, NULL, NULL);
}
/***********************************************************************
* MakeSureDirectoryPathExists (DBGHELP.@)
*/
BOOL WINAPI MakeSureDirectoryPathExists(LPCSTR DirPath)
BOOL WINAPI MakeSureDirectoryPathExists(PCSTR DirPath)
{
char path[MAX_PATH];
const char *p = DirPath;
@ -113,15 +153,43 @@ BOOL WINAPI MakeSureDirectoryPathExists(LPCSTR DirPath)
return TRUE;
}
/******************************************************************
* SymMatchFileNameW (DBGHELP.@)
*
*/
BOOL WINAPI SymMatchFileNameW(PCWSTR file, PCWSTR match,
PWSTR* filestop, PWSTR* matchstop)
{
PCWSTR fptr;
PCWSTR mptr;
TRACE("(%s %s %p %p)\n",
debugstr_w(file), debugstr_w(match), filestop, matchstop);
fptr = file + strlenW(file) - 1;
mptr = match + strlenW(match) - 1;
while (fptr >= file && mptr >= match)
{
if (toupperW(*fptr) != toupperW(*mptr) && !(is_sepW(*fptr) && is_sepW(*mptr)))
break;
fptr--; mptr--;
}
if (filestop) *filestop = (PWSTR)fptr;
if (matchstop) *matchstop = (PWSTR)mptr;
return mptr == match - 1;
}
/******************************************************************
* SymMatchFileName (DBGHELP.@)
*
*/
BOOL WINAPI SymMatchFileName(char* file, char* match,
char** filestop, char** matchstop)
BOOL WINAPI SymMatchFileName(PCSTR file, PCSTR match,
PSTR* filestop, PSTR* matchstop)
{
char* fptr;
char* mptr;
PCSTR fptr;
PCSTR mptr;
TRACE("(%s %s %p %p)\n", file, match, filestop, matchstop);
@ -134,40 +202,43 @@ BOOL WINAPI SymMatchFileName(char* file, char* match,
break;
fptr--; mptr--;
}
if (filestop) *filestop = fptr;
if (matchstop) *matchstop = mptr;
if (filestop) *filestop = (PSTR)fptr;
if (matchstop) *matchstop = (PSTR)mptr;
return mptr == match - 1;
}
static BOOL do_search(const char* file, char* buffer,
PENUMDIRTREE_CALLBACK cb, void* user)
static BOOL do_searchW(PCWSTR file, PWSTR buffer, BOOL recurse,
PENUMDIRTREE_CALLBACKW cb, PVOID user)
{
HANDLE h;
WIN32_FIND_DATAA fd;
WIN32_FIND_DATAW fd;
unsigned pos;
BOOL found = FALSE;
static const WCHAR S_AllW[] = {'*','.','*','\0'};
static const WCHAR S_DotW[] = {'.','\0'};
static const WCHAR S_DotDotW[] = {'.','\0'};
pos = strlen(buffer);
pos = strlenW(buffer);
if (buffer[pos - 1] != '\\') buffer[pos++] = '\\';
strcpy(buffer + pos, "*.*");
if ((h = FindFirstFileA(buffer, &fd)) == INVALID_HANDLE_VALUE)
strcpyW(buffer + pos, S_AllW);
if ((h = FindFirstFileW(buffer, &fd)) == INVALID_HANDLE_VALUE)
return FALSE;
/* doc doesn't specify how the tree is enumerated...
* doing a depth first based on, but may be wrong
*/
do
{
if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..")) continue;
if (!strcmpW(fd.cFileName, S_DotW) || !strcmpW(fd.cFileName, S_DotDotW)) continue;
strcpy(buffer + pos, fd.cFileName);
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
found = do_search(file, buffer, cb, user);
else if (SymMatchFileName(buffer, (char*)file, NULL, NULL))
strcpyW(buffer + pos, fd.cFileName);
if (recurse && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
found = do_searchW(file, buffer, TRUE, cb, user);
else if (SymMatchFileNameW(buffer, (WCHAR*)file, NULL, NULL))
{
if (!cb || cb(buffer, user)) found = TRUE;
}
} while (!found && FindNextFileA(h, &fd));
} while (!found && FindNextFileW(h, &fd));
if (!found) buffer[--pos] = '\0';
FindClose(h);
@ -175,14 +246,47 @@ static BOOL do_search(const char* file, char* buffer,
}
/***********************************************************************
* SearchTreeForFile (DBGHELP.@)
* SearchTreeForFileW (DBGHELP.@)
*/
BOOL WINAPI SearchTreeForFile(LPSTR root, LPSTR file, LPSTR buffer)
BOOL WINAPI SearchTreeForFileW(PCWSTR root, PCWSTR file, PWSTR buffer)
{
TRACE("(%s, %s, %p)\n",
debugstr_a(root), debugstr_a(file), buffer);
strcpy(buffer, root);
return do_search(file, buffer, NULL, NULL);
debugstr_w(root), debugstr_w(file), buffer);
strcpyW(buffer, root);
return do_searchW(file, buffer, TRUE, NULL, NULL);
}
/***********************************************************************
* SearchTreeForFile (DBGHELP.@)
*/
BOOL WINAPI SearchTreeForFile(PCSTR root, PCSTR file, PSTR buffer)
{
WCHAR rootW[MAX_PATH];
WCHAR fileW[MAX_PATH];
WCHAR bufferW[MAX_PATH];
BOOL ret;
MultiByteToWideChar(CP_ACP, 0, root, -1, rootW, MAX_PATH);
MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH);
ret = SearchTreeForFileW(rootW, fileW, bufferW);
if (ret)
WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
return ret;
}
/******************************************************************
* EnumDirTreeW (DBGHELP.@)
*
*
*/
BOOL WINAPI EnumDirTreeW(HANDLE hProcess, PCWSTR root, PCWSTR file,
PWSTR buffer, PENUMDIRTREE_CALLBACKW cb, PVOID user)
{
TRACE("(%p %s %s %p %p %p)\n",
hProcess, debugstr_w(root), debugstr_w(file), buffer, cb, user);
strcpyW(buffer, root);
return do_searchW(file, buffer, TRUE, cb, user);
}
/******************************************************************
@ -190,55 +294,193 @@ BOOL WINAPI SearchTreeForFile(LPSTR root, LPSTR file, LPSTR buffer)
*
*
*/
BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file,
LPSTR buffer, PENUMDIRTREE_CALLBACK cb, PVOID user)
struct enum_dir_treeWA
{
TRACE("(%p %s %s %p %p %p)\n", hProcess, root, file, buffer, cb, user);
PENUMDIRTREE_CALLBACK cb;
void* user;
char name[MAX_PATH];
};
strcpy(buffer, root);
return do_search(file, buffer, cb, user);
static BOOL CALLBACK enum_dir_treeWA(PCWSTR name, PVOID user)
{
struct enum_dir_treeWA* edt = user;
WideCharToMultiByte(CP_ACP, 0, name, -1, edt->name, MAX_PATH, NULL, NULL);
return edt->cb(edt->name, edt->user);
}
BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file,
PSTR buffer, PENUMDIRTREE_CALLBACK cb, PVOID user)
{
WCHAR rootW[MAX_PATH];
WCHAR fileW[MAX_PATH];
WCHAR bufferW[MAX_PATH];
struct enum_dir_treeWA edt;
BOOL ret;
edt.cb = cb;
edt.user = user;
MultiByteToWideChar(CP_ACP, 0, root, -1, rootW, MAX_PATH);
MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH);
if ((ret = EnumDirTreeW(hProcess, rootW, fileW, bufferW, enum_dir_treeWA, &edt)))
WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
return ret;
}
struct sffip
{
enum module_type kind;
/* pe: id -> DWORD:timestamp
* two -> size of image (from PE header)
* pdb: id -> PDB signature
* I think either DWORD:timestamp or GUID:guid depending on PDB version
* two -> PDB age ???
* elf: id -> DWORD:CRC 32 of ELF image (Wine only)
*/
PVOID id;
DWORD two;
DWORD three;
DWORD flags;
PFINDFILEINPATHCALLBACK cb;
PFINDFILEINPATHCALLBACKW cb;
void* user;
};
static BOOL CALLBACK sffip_cb(LPCSTR buffer, void* user)
/* checks that buffer (as found by matching the name) matches the info
* (information is based on file type)
* returns TRUE when file is found, FALSE to continue searching
* (NB this is the opposite convention of SymFindFileInPathProc)
*/
static BOOL CALLBACK sffip_cb(PCWSTR buffer, PVOID user)
{
struct sffip* s = (struct sffip*)user;
DWORD size, checksum;
/* FIXME: should check that id/two/three match the file pointed
* by buffer
*/
/* yes, EnumDirTree and SymFindFileInPath callbacks use the opposite
switch (s->kind)
{
case DMT_PE:
{
HANDLE hFile, hMap;
void* mapping;
DWORD timestamp;
timestamp = ~(DWORD_PTR)s->id;
size = ~s->two;
hFile = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) return FALSE;
if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
{
if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
{
IMAGE_NT_HEADERS* nth = RtlImageNtHeader(mapping);
timestamp = nth->FileHeader.TimeDateStamp;
size = nth->OptionalHeader.SizeOfImage;
UnmapViewOfFile(mapping);
}
CloseHandle(hMap);
}
CloseHandle(hFile);
if (timestamp != (DWORD_PTR)s->id || size != s->two)
{
WARN("Found %s, but wrong size or timestamp\n", debugstr_w(buffer));
return FALSE;
}
}
break;
case DMT_ELF:
if (elf_fetch_file_info(buffer, 0, &size, &checksum))
{
if (checksum != (DWORD_PTR)s->id)
{
WARN("Found %s, but wrong checksums: %08x %08lx\n",
debugstr_w(buffer), checksum, (DWORD_PTR)s->id);
return FALSE;
}
}
else
{
WARN("Couldn't read %s\n", debugstr_w(buffer));
return FALSE;
}
break;
case DMT_PDB:
{
struct pdb_lookup pdb_lookup;
char fn[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, buffer, -1, fn, MAX_PATH, NULL, NULL);
pdb_lookup.filename = fn;
if (!pdb_fetch_file_info(&pdb_lookup)) return FALSE;
switch (pdb_lookup.kind)
{
case PDB_JG:
if (s->flags & SSRVOPT_GUIDPTR)
{
WARN("Found %s, but wrong PDB version\n", debugstr_w(buffer));
return FALSE;
}
if (pdb_lookup.u.jg.timestamp != (DWORD_PTR)s->id)
{
WARN("Found %s, but wrong signature: %08x %08lx\n",
debugstr_w(buffer), pdb_lookup.u.jg.timestamp, (DWORD_PTR)s->id);
return FALSE;
}
break;
case PDB_DS:
if (!(s->flags & SSRVOPT_GUIDPTR))
{
WARN("Found %s, but wrong PDB version\n", debugstr_w(buffer));
return FALSE;
}
if (memcmp(&pdb_lookup.u.ds.guid, (GUID*)s->id, sizeof(GUID)))
{
WARN("Found %s, but wrong GUID: %s %s\n",
debugstr_w(buffer), debugstr_guid(&pdb_lookup.u.ds.guid),
debugstr_guid((GUID*)s->id));
return FALSE;
}
break;
}
if (pdb_lookup.age != s->two)
{
WARN("Found %s, but wrong age: %08x %08x\n",
debugstr_w(buffer), pdb_lookup.age, s->two);
return FALSE;
}
}
break;
default:
FIXME("What the heck??\n");
return FALSE;
}
/* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
* convention to stop/continue enumeration. sigh.
*/
return !(s->cb)((char*)buffer, s->user);
return !(s->cb)((WCHAR*)buffer, s->user);
}
/******************************************************************
* SymFindFileInPath (DBGHELP.@)
* SymFindFileInPathW (DBGHELP.@)
*
*/
BOOL WINAPI SymFindFileInPath(HANDLE hProcess, LPSTR searchPath, LPSTR file,
PVOID id, DWORD two, DWORD three, DWORD flags,
LPSTR buffer, PFINDFILEINPATHCALLBACK cb,
PVOID user)
BOOL WINAPI SymFindFileInPathW(HANDLE hProcess, PCWSTR searchPath, PCWSTR full_path,
PVOID id, DWORD two, DWORD three, DWORD flags,
PWSTR buffer, PFINDFILEINPATHCALLBACKW cb,
PVOID user)
{
struct sffip s;
struct process* pcs = process_find_by_handle(hProcess);
char tmp[MAX_PATH];
char* ptr;
WCHAR tmp[MAX_PATH];
WCHAR* ptr;
const WCHAR* filename;
TRACE("(%p %s %s %p %08lx %08lx %08lx %p %p %p)\n",
hProcess, searchPath, file, id, two, three, flags,
buffer, cb, user);
TRACE("(%p %s %s %p %08x %08x %08x %p %p %p)\n",
hProcess, debugstr_w(searchPath), debugstr_w(full_path),
id, two, three, flags, buffer, cb, user);
if (!pcs) return FALSE;
if (!searchPath) searchPath = pcs->search_path;
@ -250,23 +492,66 @@ BOOL WINAPI SymFindFileInPath(HANDLE hProcess, LPSTR searchPath, LPSTR file,
s.cb = cb;
s.user = user;
file = file_name(file);
filename = file_nameW(full_path);
s.kind = module_get_type_by_name(filename);
/* first check full path to file */
if (sffip_cb(full_path, &s))
{
strcpyW(buffer, full_path);
return TRUE;
}
while (searchPath)
{
ptr = strchr(searchPath, ';');
ptr = strchrW(searchPath, ';');
if (ptr)
{
memcpy(tmp, searchPath, ptr - searchPath);
memcpy(tmp, searchPath, (ptr - searchPath) * sizeof(WCHAR));
tmp[ptr - searchPath] = 0;
searchPath = ptr + 1;
}
else
{
strcpy(tmp, searchPath);
strcpyW(tmp, searchPath);
searchPath = NULL;
}
if (EnumDirTree(hProcess, tmp, file, buffer, sffip_cb, &s)) return TRUE;
if (do_searchW(filename, tmp, FALSE, sffip_cb, &s))
{
strcpyW(buffer, tmp);
return TRUE;
}
}
return FALSE;
}
/******************************************************************
* SymFindFileInPath (DBGHELP.@)
*
*/
BOOL WINAPI SymFindFileInPath(HANDLE hProcess, PCSTR searchPath, PCSTR full_path,
PVOID id, DWORD two, DWORD three, DWORD flags,
PSTR buffer, PFINDFILEINPATHCALLBACK cb,
PVOID user)
{
WCHAR searchPathW[MAX_PATH];
WCHAR full_pathW[MAX_PATH];
WCHAR bufferW[MAX_PATH];
struct enum_dir_treeWA edt;
BOOL ret;
/* a PFINDFILEINPATHCALLBACK and a PENUMDIRTREE_CALLBACK have actually the
* same signature & semantics, hence we can reuse the EnumDirTree W->A
* conversion helper
*/
edt.cb = cb;
edt.user = user;
if (searchPath)
MultiByteToWideChar(CP_ACP, 0, searchPath, -1, searchPathW, MAX_PATH);
MultiByteToWideChar(CP_ACP, 0, full_path, -1, full_pathW, MAX_PATH);
if ((ret = SymFindFileInPathW(hProcess, searchPath ? searchPathW : NULL, full_pathW,
id, two, three, flags,
bufferW, enum_dir_treeWA, &edt)))
WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
return ret;
}

View file

@ -3,7 +3,7 @@
*
* Copyright (C) 1996, Eric Youngdale.
* Copyright (C) 1999-2000, Ulrich Weigand.
* Copyright (C) 2004, Eric Pouech.
* Copyright (C) 2004-2007, Eric Pouech.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -17,7 +17,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
@ -28,7 +28,6 @@
#include <assert.h>
#include "dbghelp_private.h"
#include "winreg.h"
#include "winternl.h"
#include "wine/debug.h"
@ -37,10 +36,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
/******************************************************************
* pe_load_stabs
*
* look for stabs information in PE header (it's how the mingw compiler provides
* look for stabs information in PE header (it's how the mingw compiler provides
* its debugging information)
*/
static BOOL pe_load_stabs(const struct process* pcs, struct module* module,
static BOOL pe_load_stabs(const struct process* pcs, struct module* module,
const void* mapping, IMAGE_NT_HEADERS* nth)
{
IMAGE_SECTION_HEADER* section;
@ -52,12 +51,12 @@ static BOOL pe_load_stabs(const struct process* pcs, struct module* module,
((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
{
if (!strcasecmp(section->Name, ".stab"))
if (!strcasecmp((const char*)section->Name, ".stab"))
{
stabs = section->VirtualAddress;
stabsize = section->SizeOfRawData;
}
else if (!strncasecmp(section->Name, ".stabstr", 8))
else if (!strncasecmp((const char*)section->Name, ".stabstr", 8))
{
stabstr = section->VirtualAddress;
stabstrsize = section->SizeOfRawData;
@ -66,8 +65,8 @@ static BOOL pe_load_stabs(const struct process* pcs, struct module* module,
if (stabstrsize && stabsize)
{
ret = stabs_parse(module,
module->module.BaseOfImage - nth->OptionalHeader.ImageBase,
ret = stabs_parse(module,
module->module.BaseOfImage - nth->OptionalHeader.ImageBase,
RtlImageRvaToVa(nth, (void*)mapping, stabs, NULL),
stabsize,
RtlImageRvaToVa(nth, (void*)mapping, stabstr, NULL),
@ -76,7 +75,7 @@ static BOOL pe_load_stabs(const struct process* pcs, struct module* module,
return ret;
}
static BOOL CALLBACK dbg_match(char* file, void* user)
static BOOL CALLBACK dbg_match(const char* file, void* user)
{
/* accept first file */
return FALSE;
@ -99,12 +98,10 @@ static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module,
WINE_TRACE("Processing DBG file %s\n", dbg_name);
if (SymFindFileInPath(pcs->handle, NULL, (char*)dbg_name,
NULL, 0, 0, 0,
tmp, dbg_match, NULL) &&
if (SymFindFileInPath(pcs->handle, NULL, dbg_name, NULL, 0, 0, 0, tmp, dbg_match, NULL) &&
(hFile = CreateFileA(tmp, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE &&
((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) &&
((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) &&
((dbg_mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL))
{
hdr = (const IMAGE_SEPARATE_DEBUG_HEADER*)dbg_mapping;
@ -125,8 +122,8 @@ static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module,
const IMAGE_SECTION_HEADER *sectp =
(const IMAGE_SECTION_HEADER*)(hdr + 1);
/* and after that and the exported names comes the debug directory */
dbg = (const IMAGE_DEBUG_DIRECTORY*)
(dbg_mapping + sizeof(*hdr) +
dbg = (const IMAGE_DEBUG_DIRECTORY*)
(dbg_mapping + sizeof(*hdr) +
hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
hdr->ExportedNamesSize);
@ -141,9 +138,9 @@ static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module,
else
WINE_ERR("-Unable to peruse .DBG file %s (%s)\n", dbg_name, debugstr_a(tmp));
if (dbg_mapping) UnmapViewOfFile((void*)dbg_mapping);
if (dbg_mapping) UnmapViewOfFile(dbg_mapping);
if (hMap) CloseHandle(hMap);
if (hFile != NULL) CloseHandle(hFile);
if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
return ret;
}
@ -152,7 +149,7 @@ static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module,
*
* Process MSC debug information in PE file.
*/
static BOOL pe_load_msc_debug_info(const struct process* pcs,
static BOOL pe_load_msc_debug_info(const struct process* pcs,
struct module* module,
const void* mapping, IMAGE_NT_HEADERS* nth)
{
@ -179,11 +176,11 @@ static BOOL pe_load_msc_debug_info(const struct process* pcs,
misc->DataType != IMAGE_DEBUG_MISC_EXENAME)
{
WINE_ERR("-Debug info stripped, but no .DBG file in module %s\n",
module->module.ModuleName);
debugstr_w(module->module.ModuleName));
}
else
{
ret = pe_load_dbg_file(pcs, module, misc->Data, nth->FileHeader.TimeDateStamp);
ret = pe_load_dbg_file(pcs, module, (const char*)misc->Data, nth->FileHeader.TimeDateStamp);
}
}
else
@ -200,8 +197,8 @@ static BOOL pe_load_msc_debug_info(const struct process* pcs,
/***********************************************************************
* pe_load_export_debug_info
*/
static BOOL pe_load_export_debug_info(const struct process* pcs,
struct module* module,
static BOOL pe_load_export_debug_info(const struct process* pcs,
struct module* module,
const void* mapping, IMAGE_NT_HEADERS* nth)
{
unsigned int i;
@ -214,26 +211,26 @@ static BOOL pe_load_export_debug_info(const struct process* pcs,
#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,
symt_new_public(module, NULL, module->module.ModuleName, base, 1,
TRUE /* FIXME */, TRUE /* FIXME */);
#endif
/* Add entry point */
symt_new_public(module, NULL, "EntryPoint",
base + nth->OptionalHeader.AddressOfEntryPoint, 0,
symt_new_public(module, NULL, "EntryPoint",
base + nth->OptionalHeader.AddressOfEntryPoint, 1,
TRUE, TRUE);
#if 0
/* FIXME: we'd better store addresses linked to sections rather than
/* FIXME: we'd better store addresses linked to sections rather than
absolute values */
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++)
for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
{
symt_new_public(module, NULL, section->Name,
RtlImageRvaToVa(nth, (void*)mapping, section->VirtualAddress, NULL),
0, TRUE /* FIXME */, TRUE /* FIXME */);
symt_new_public(module, NULL, section->Name,
RtlImageRvaToVa(nth, (void*)mapping, section->VirtualAddress, NULL),
1, TRUE /* FIXME */, TRUE /* FIXME */);
}
#endif
@ -251,25 +248,28 @@ static BOOL pe_load_export_debug_info(const struct process* pcs,
ordinals = RtlImageRvaToVa(nth, (void*)mapping, exports->AddressOfNameOrdinals, NULL);
names = RtlImageRvaToVa(nth, (void*)mapping, exports->AddressOfNames, NULL);
for (i = 0; i < exports->NumberOfNames; i++)
if (functions && ordinals && names)
{
if (!names[i]) continue;
symt_new_public(module, NULL,
RtlImageRvaToVa(nth, (void*)mapping, names[i], NULL),
base + functions[ordinals[i]],
0, TRUE /* FIXME */, TRUE /* FIXME */);
}
for (i = 0; i < exports->NumberOfNames; i++)
{
if (!names[i]) continue;
symt_new_public(module, NULL,
RtlImageRvaToVa(nth, (void*)mapping, names[i], NULL),
base + functions[ordinals[i]],
1, 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), "%ld", i + exports->Base);
symt_new_public(module, NULL, buffer, base + (DWORD)functions[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), "%d", i + exports->Base);
symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 1,
TRUE /* FIXME */, TRUE /* FIXME */);
}
}
}
/* no real debug info, only entry points */
@ -290,10 +290,10 @@ BOOL pe_load_debug_info(const struct process* pcs, struct module* module)
void* mapping;
IMAGE_NT_HEADERS* nth;
hFile = CreateFileA(module->module.LoadedImageName, GENERIC_READ, FILE_SHARE_READ,
hFile = CreateFileW(module->module.LoadedImageName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) return ret;
if ((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0)
if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0)
{
if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
{
@ -304,7 +304,7 @@ BOOL pe_load_debug_info(const struct process* pcs, struct module* module)
ret = pe_load_stabs(pcs, module, mapping, nth) ||
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,
* 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
*/
}
@ -321,36 +321,35 @@ BOOL pe_load_debug_info(const struct process* pcs, struct module* module)
}
/******************************************************************
* pe_load_module
* pe_load_native_module
*
*/
struct module* pe_load_module(struct process* pcs, char* name,
HANDLE hFile, DWORD base, DWORD size)
struct module* pe_load_native_module(struct process* pcs, const WCHAR* name,
HANDLE hFile, DWORD base, DWORD size)
{
struct module* module = NULL;
BOOL opened = FALSE;
HANDLE hMap;
void* mapping;
char loaded_name[MAX_PATH];
WCHAR loaded_name[MAX_PATH];
loaded_name[0] = '\0';
if (!hFile)
{
if (!name)
{
/* FIXME SetLastError */
return NULL;
}
if ((hFile = FindExecutableImage(name, NULL, loaded_name)) == NULL)
assert(name);
if ((hFile = FindExecutableImageExW(name, pcs->search_path, loaded_name, NULL, NULL)) == NULL)
return NULL;
opened = TRUE;
}
else if (name) strcpy(loaded_name, name);
else if (name) strcpyW(loaded_name, name);
else if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
FIXME("Trouble ahead (no module name passed in deferred mode)\n");
if (!(module = module_find_by_name(pcs, loaded_name, DMT_PE)) &&
(hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
{
void* mapping;
if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
{
IMAGE_NT_HEADERS* nth = RtlImageNtHeader(mapping);
@ -360,7 +359,7 @@ struct module* pe_load_module(struct process* pcs, char* name,
if (!base) base = nth->OptionalHeader.ImageBase;
if (!size) size = nth->OptionalHeader.SizeOfImage;
module = module_new(pcs, loaded_name, DMT_PE, base, size,
module = module_new(pcs, loaded_name, DMT_PE, FALSE, base, size,
nth->FileHeader.TimeDateStamp,
nth->OptionalHeader.CheckSum);
if (module)
@ -381,43 +380,39 @@ struct module* pe_load_module(struct process* pcs, char* name,
}
/******************************************************************
* pe_load_module_from_pcs
* pe_load_nt_header
*
*/
struct module* pe_load_module_from_pcs(struct process* pcs, const char* name,
const char* mod_name, DWORD base, DWORD size)
BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth)
{
struct module* module;
const char* ptr;
IMAGE_DOS_HEADER dos;
return ReadProcessMemory(hProc, (char*)base, &dos, sizeof(dos), NULL) &&
dos.e_magic == IMAGE_DOS_SIGNATURE &&
ReadProcessMemory(hProc, (char*)(base + dos.e_lfanew),
nth, sizeof(*nth), NULL) &&
nth->Signature == IMAGE_NT_SIGNATURE;
}
/******************************************************************
* pe_load_builtin_module
*
*/
struct module* pe_load_builtin_module(struct process* pcs, const WCHAR* name,
DWORD base, DWORD size)
{
struct module* module = NULL;
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 (ReadProcessMemory(pcs->handle, (char*)base, &dos, sizeof(dos), NULL) &&
dos.e_magic == IMAGE_DOS_SIGNATURE &&
ReadProcessMemory(pcs->handle, (char*)(base + dos.e_lfanew),
&nth, sizeof(nth), NULL) &&
nth.Signature == IMAGE_NT_SIGNATURE)
if (pe_load_nt_header(pcs->handle, base, &nth))
{
if (!size) size = nth.OptionalHeader.SizeOfImage;
module = module_new(pcs, name, DMT_PE, base, size,
nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum);
module = module_new(pcs, name, DMT_PE, FALSE, base, size,
nth.FileHeader.TimeDateStamp,
nth.OptionalHeader.CheckSum);
}
}
return module;

View file

@ -1,572 +0,0 @@
/* Definitions for data structures and routines for the regular
expression library, version 0.12.
Copyright (C) 1985,89,90,91,92,93,95,96,97,98 Free Software Foundation, Inc.
This file is part of the GNU C Library. Its master source is NOT part of
the C library, however. The master source lives in /gd/gnu/lib.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef _REGEX_H
#define _REGEX_H 1
/* Allow the use in C++ code. */
#ifdef __cplusplus
extern "C" {
#endif
/* POSIX says that <sys/types.h> must be included (by the caller) before
<regex.h>. */
#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS
/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
should be there. */
# include <stddef.h>
#endif
/* The following two types have to be signed and unsigned integer type
wide enough to hold a value of a pointer. For most ANSI compilers
ptrdiff_t and size_t should be likely OK. Still size of these two
types is 2 for Microsoft C. Ugh... */
typedef long int s_reg_t;
typedef unsigned long int active_reg_t;
/* The following bits are used to determine the regexp syntax we
recognize. The set/not-set meanings are chosen so that Emacs syntax
remains the value 0. The bits are given in alphabetical order, and
the definitions shifted by one from the previous bit; thus, when we
add or remove a bit, only one other definition need change. */
typedef unsigned long int reg_syntax_t;
/* If this bit is not set, then \ inside a bracket expression is literal.
If set, then such a \ quotes the following character. */
#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
/* If this bit is not set, then + and ? are operators, and \+ and \? are
literals.
If set, then \+ and \? are operators and + and ? are literals. */
#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
/* If this bit is set, then character classes are supported. They are:
[:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
[:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
If not set, then character classes are not supported. */
#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
/* If this bit is set, then ^ and $ are always anchors (outside bracket
expressions, of course).
If this bit is not set, then it depends:
^ is an anchor if it is at the beginning of a regular
expression or after an open-group or an alternation operator;
$ is an anchor if it is at the end of a regular expression, or
before a close-group or an alternation operator.
This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
POSIX draft 11.2 says that * etc. in leading positions is undefined.
We already implemented a previous draft which made those constructs
invalid, though, so we haven't changed the code back. */
#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
/* If this bit is set, then special characters are always special
regardless of where they are in the pattern.
If this bit is not set, then special characters are special only in
some contexts; otherwise they are ordinary. Specifically,
* + ? and intervals are only special when not after the beginning,
open-group, or alternation operator. */
#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
/* If this bit is set, then *, +, ?, and { cannot be first in an re or
immediately after an alternation or begin-group operator. */
#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
/* If this bit is set, then . matches newline.
If not set, then it doesn't. */
#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
/* If this bit is set, then . doesn't match NUL.
If not set, then it does. */
#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
/* If this bit is set, nonmatching lists [^...] do not match newline.
If not set, they do. */
#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
/* If this bit is set, either \{...\} or {...} defines an
interval, depending on RE_NO_BK_BRACES.
If not set, \{, \}, {, and } are literals. */
#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
/* If this bit is set, +, ? and | aren't recognized as operators.
If not set, they are. */
#define RE_LIMITED_OPS (RE_INTERVALS << 1)
/* If this bit is set, newline is an alternation operator.
If not set, newline is literal. */
#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
/* If this bit is set, then `{...}' defines an interval, and \{ and \}
are literals.
If not set, then `\{...\}' defines an interval. */
#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
/* If this bit is set, (...) defines a group, and \( and \) are literals.
If not set, \(...\) defines a group, and ( and ) are literals. */
#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
/* If this bit is set, then \<digit> matches <digit>.
If not set, then \<digit> is a back-reference. */
#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
/* If this bit is set, then | is an alternation operator, and \| is literal.
If not set, then \| is an alternation operator, and | is literal. */
#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
/* If this bit is set, then an ending range point collating higher
than the starting range point, as in [z-a], is invalid.
If not set, then when ending range point collates higher than the
starting range point, the range is ignored. */
#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
/* If this bit is set, then an unmatched ) is ordinary.
If not set, then an unmatched ) is invalid. */
#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
/* If this bit is set, succeed as soon as we match the whole pattern,
without further backtracking. */
#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
/* If this bit is set, do not process the GNU regex operators.
If not set, then the GNU regex operators are recognized. */
#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
/* If this bit is set, turn on internal regex debugging.
If not set, and debugging was on, turn it off.
This only works if regex.c is compiled -DDEBUG.
We define this bit always, so that all that's needed to turn on
debugging is to recompile regex.c; the calling code can always have
this bit set, and it won't affect anything in the normal case. */
#define RE_DEBUG (RE_NO_GNU_OPS << 1)
/* This global variable defines the particular regexp syntax to use (for
some interfaces). When a regexp is compiled, the syntax used is
stored in the pattern buffer, so changing this does not affect
already-compiled regexps. */
extern reg_syntax_t re_syntax_options;
/* Define combinations of the above bits for the standard possibilities.
(The [[[ comments delimit what gets put into the Texinfo file, so
don't delete them!) */
/* [[[begin syntaxes]]] */
#define RE_SYNTAX_EMACS 0
#define RE_SYNTAX_AWK \
(RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
| RE_NO_BK_PARENS | RE_NO_BK_REFS \
| RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
| RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \
| RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
#define RE_SYNTAX_GNU_AWK \
((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \
& ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS))
#define RE_SYNTAX_POSIX_AWK \
(RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
| RE_INTERVALS | RE_NO_GNU_OPS)
#define RE_SYNTAX_GREP \
(RE_BK_PLUS_QM | RE_CHAR_CLASSES \
| RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
| RE_NEWLINE_ALT)
#define RE_SYNTAX_EGREP \
(RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
| RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
| RE_NEWLINE_ALT | RE_NO_BK_PARENS \
| RE_NO_BK_VBAR)
#define RE_SYNTAX_POSIX_EGREP \
(RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
/* Syntax bits common to both basic and extended POSIX regex syntax. */
#define _RE_SYNTAX_POSIX_COMMON \
(RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
| RE_INTERVALS | RE_NO_EMPTY_RANGES)
#define RE_SYNTAX_POSIX_BASIC \
(_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
isn't minimal, since other operators, such as \`, aren't disabled. */
#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
(_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
#define RE_SYNTAX_POSIX_EXTENDED \
(_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
| RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
| RE_NO_BK_PARENS | RE_NO_BK_VBAR \
| RE_UNMATCHED_RIGHT_PAREN_ORD)
/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
(_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
| RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
| RE_NO_BK_PARENS | RE_NO_BK_REFS \
| RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
/* [[[end syntaxes]]] */
/* Maximum number of duplicates an interval can allow. Some systems
(erroneously) define this in other header files, but we want our
value, so remove any previous define. */
#ifdef RE_DUP_MAX
# undef RE_DUP_MAX
#endif
/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */
#define RE_DUP_MAX (0x7fff)
/* POSIX `cflags' bits (i.e., information for `regcomp'). */
/* If this bit is set, then use extended regular expression syntax.
If not set, then use basic regular expression syntax. */
#define REG_EXTENDED 1
/* If this bit is set, then ignore case when matching.
If not set, then case is significant. */
#define REG_ICASE (REG_EXTENDED << 1)
/* If this bit is set, then anchors do not match at newline
characters in the string.
If not set, then anchors do match at newlines. */
#define REG_NEWLINE (REG_ICASE << 1)
/* If this bit is set, then report only success or fail in regexec.
If not set, then returns differ between not matching and errors. */
#define REG_NOSUB (REG_NEWLINE << 1)
/* POSIX `eflags' bits (i.e., information for regexec). */
/* If this bit is set, then the beginning-of-line operator doesn't match
the beginning of the string (presumably because it's not the
beginning of a line).
If not set, then the beginning-of-line operator does match the
beginning of the string. */
#define REG_NOTBOL 1
/* Like REG_NOTBOL, except for the end-of-line. */
#define REG_NOTEOL (1 << 1)
/* If any error codes are removed, changed, or added, update the
`re_error_msg' table in regex.c. */
typedef enum
{
#ifdef _XOPEN_SOURCE
REG_ENOSYS = -1, /* This will never happen for this implementation. */
#endif
REG_NOERROR = 0, /* Success. */
REG_NOMATCH, /* Didn't find a match (for regexec). */
/* POSIX regcomp return error codes. (In the order listed in the
standard.) */
REG_BADPAT, /* Invalid pattern. */
REG_ECOLLATE, /* Not implemented. */
REG_ECTYPE, /* Invalid character class name. */
REG_EESCAPE, /* Trailing backslash. */
REG_ESUBREG, /* Invalid back reference. */
REG_EBRACK, /* Unmatched left bracket. */
REG_EPAREN, /* Parenthesis imbalance. */
REG_EBRACE, /* Unmatched \{. */
REG_BADBR, /* Invalid contents of \{\}. */
REG_ERANGE, /* Invalid range end. */
REG_ESPACE, /* Ran out of memory. */
REG_BADRPT, /* No preceding re for repetition op. */
/* Error codes we've added. */
REG_EEND, /* Premature end. */
REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
} reg_errcode_t;
/* This data structure represents a compiled pattern. Before calling
the pattern compiler, the fields `buffer', `allocated', `fastmap',
`translate', and `no_sub' can be set. After the pattern has been
compiled, the `re_nsub' field is available. All other fields are
private to the regex routines. */
#ifndef RE_TRANSLATE_TYPE
# define RE_TRANSLATE_TYPE char *
#endif
struct re_pattern_buffer
{
/* [[[begin pattern_buffer]]] */
/* Space that holds the compiled pattern. It is declared as
`unsigned char *' because its elements are
sometimes used as array indexes. */
unsigned char *buffer;
/* Number of bytes to which `buffer' points. */
unsigned long int allocated;
/* Number of bytes actually used in `buffer'. */
unsigned long int used;
/* Syntax setting with which the pattern was compiled. */
reg_syntax_t syntax;
/* Pointer to a fastmap, if any, otherwise zero. re_search uses
the fastmap, if there is one, to skip over impossible
starting points for matches. */
char *fastmap;
/* Either a translate table to apply to all characters before
comparing them, or zero for no translation. The translation
is applied to a pattern when it is compiled and to a string
when it is matched. */
RE_TRANSLATE_TYPE translate;
/* Number of subexpressions found by the compiler. */
size_t re_nsub;
/* Zero if this pattern cannot match the empty string, one else.
Well, in truth it's used only in `re_search_2', to see
whether or not we should use the fastmap, so we don't set
this absolutely perfectly; see `re_compile_fastmap' (the
`duplicate' case). */
unsigned can_be_null : 1;
/* If REGS_UNALLOCATED, allocate space in the `regs' structure
for `max (RE_NREGS, re_nsub + 1)' groups.
If REGS_REALLOCATE, reallocate space if necessary.
If REGS_FIXED, use what's there. */
#define REGS_UNALLOCATED 0
#define REGS_REALLOCATE 1
#define REGS_FIXED 2
unsigned regs_allocated : 2;
/* Set to zero when `regex_compile' compiles a pattern; set to one
by `re_compile_fastmap' if it updates the fastmap. */
unsigned fastmap_accurate : 1;
/* If set, `re_match_2' does not return information about
subexpressions. */
unsigned no_sub : 1;
/* If set, a beginning-of-line anchor doesn't match at the
beginning of the string. */
unsigned not_bol : 1;
/* Similarly for an end-of-line anchor. */
unsigned not_eol : 1;
/* If true, an anchor at a newline matches. */
unsigned newline_anchor : 1;
/* [[[end pattern_buffer]]] */
};
typedef struct re_pattern_buffer regex_t;
/* Type for byte offsets within the string. POSIX mandates this. */
typedef int regoff_t;
/* This is the structure we store register match data in. See
regex.texinfo for a full description of what registers match. */
struct re_registers
{
unsigned num_regs;
regoff_t *start;
regoff_t *end;
};
/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
`re_match_2' returns information about at least this many registers
the first time a `regs' structure is passed. */
#ifndef RE_NREGS
# define RE_NREGS 30
#endif
/* POSIX specification for registers. Aside from the different names than
`re_registers', POSIX uses an array of structures, instead of a
structure of arrays. */
typedef struct
{
regoff_t rm_so; /* Byte offset from string's start to substring's start. */
regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
} regmatch_t;
/* Declarations for routines. */
/* To avoid duplicating every routine declaration -- once with a
prototype (if we are ANSI), and once without (if we aren't) -- we
use the following macro to declare argument types. This
unfortunately clutters up the declarations a bit, but I think it's
worth it. */
#if __STDC__
# define _RE_ARGS(args) args
#else /* not __STDC__ */
# define _RE_ARGS(args) ()
#endif /* not __STDC__ */
/* Sets the current default syntax to SYNTAX, and return the old syntax.
You can also simply assign to the `re_syntax_options' variable. */
extern reg_syntax_t __re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
/* Compile the regular expression PATTERN, with length LENGTH
and syntax given by the global `re_syntax_options', into the buffer
BUFFER. Return NULL if successful, and an error string if not. */
extern const char *__re_compile_pattern
_RE_ARGS ((const char *pattern, size_t length,
struct re_pattern_buffer *buffer));
extern const char *re_compile_pattern
_RE_ARGS ((const char *pattern, size_t length,
struct re_pattern_buffer *buffer));
/* Compile a fastmap for the compiled pattern in BUFFER; used to
accelerate searches. Return 0 if successful and -2 if was an
internal error. */
extern int __re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
/* Search in the string STRING (with length LENGTH) for the pattern
compiled into BUFFER. Start searching at position START, for RANGE
characters. Return the starting position of the match, -1 for no
match, or -2 for an internal error. Also return register
information in REGS (if REGS and BUFFER->no_sub are nonzero). */
extern int __re_search
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
int length, int start, int range, struct re_registers *regs));
extern int re_search
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
int length, int start, int range, struct re_registers *regs));
/* Like `re_search', but search in the concatenation of STRING1 and
STRING2. Also, stop searching at index START + STOP. */
extern int __re_search_2
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
int length1, const char *string2, int length2,
int start, int range, struct re_registers *regs, int stop));
extern int re_search_2
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
int length1, const char *string2, int length2,
int start, int range, struct re_registers *regs, int stop));
/* Like `re_search', but return how many characters in STRING the regexp
in BUFFER matched, starting at position START. */
extern int __re_match
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
int length, int start, struct re_registers *regs));
extern int re_match
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
int length, int start, struct re_registers *regs));
/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
extern int __re_match_2
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
int length1, const char *string2, int length2,
int start, struct re_registers *regs, int stop));
extern int re_match_2
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
int length1, const char *string2, int length2,
int start, struct re_registers *regs, int stop));
/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
ENDS. Subsequent matches using BUFFER and REGS will use this memory
for recording register information. STARTS and ENDS must be
allocated with malloc, and must each be at least `NUM_REGS * sizeof
(regoff_t)' bytes long.
If NUM_REGS == 0, then subsequent matches should allocate their own
register data.
Unless this function is called, the first search or match using
PATTERN_BUFFER will allocate its own register data, without
freeing the old data. */
extern void __re_set_registers
_RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
unsigned num_regs, regoff_t *starts, regoff_t *ends));
extern void re_set_registers
_RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
unsigned num_regs, regoff_t *starts, regoff_t *ends));
#ifdef _REGEX_RE_COMP
# ifndef _CRAY
/* 4.2 bsd compatibility. */
extern char *re_comp _RE_ARGS ((const char *));
extern int re_exec _RE_ARGS ((const char *));
# endif
#endif
/* POSIX compatibility. */
extern int __regcomp _RE_ARGS ((regex_t *__preg, const char *__pattern,
int __cflags));
extern int regcomp _RE_ARGS ((regex_t *__preg, const char *__pattern,
int __cflags));
extern int __regexec _RE_ARGS ((const regex_t *__preg,
const char *__string, size_t __nmatch,
regmatch_t __pmatch[], int __eflags));
extern int regexec _RE_ARGS ((const regex_t *__preg,
const char *__string, size_t __nmatch,
regmatch_t __pmatch[], int __eflags));
extern size_t __regerror _RE_ARGS ((int __errcode, const regex_t *__preg,
char *__errbuf, size_t __errbuf_size));
extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg,
char *__errbuf, size_t __errbuf_size));
extern void __regfree _RE_ARGS ((regex_t *__preg));
extern void regfree _RE_ARGS ((regex_t *__preg));
#ifdef __cplusplus
}
#endif /* C++ */
#endif /* regex.h */
/*
Local variables:
make-backup-files: t
version-control: t
trim-versions-without-asking: nil
End:
*/

View file

@ -15,7 +15,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
#include "config.h"
@ -26,6 +26,9 @@
#include "dbghelp_private.h"
#include "wine/debug.h"
#ifdef HAVE_REGEX_H
# include <regex.h>
#endif
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
@ -51,30 +54,45 @@ static unsigned source_find(const struct module* module, const char* name)
*
* checks if source exists. if not, add it
*/
unsigned source_new(struct module* module, const char* name)
unsigned source_new(struct module* module, const char* base, const char* name)
{
int len;
unsigned ret;
const char* full;
char* tmp = NULL;
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)
if (!base || *name == '/')
full = name;
else
{
/* 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);
unsigned bsz = strlen(base);
tmp = HeapAlloc(GetProcessHeap(), 0, bsz + 1 + strlen(name) + 1);
if (!tmp) return (unsigned)-1;
full = tmp;
strcpy(tmp, base);
if (tmp[bsz - 1] != '/') tmp[bsz++] = '/';
strcpy(&tmp[bsz], name);
}
ret = module->sources_used;
strcpy(module->sources + module->sources_used, name);
module->sources_used += len;
module->sources[module->sources_used] = '\0';
if (!module->sources || (ret = source_find(module, full)) == (unsigned)-1)
{
int len = strlen(full) + 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;
memcpy(module->sources + module->sources_used, full, len);
module->sources_used += len;
module->sources[module->sources_used] = '\0';
}
HeapFree(GetProcessHeap(), 0, tmp);
return ret;
}
@ -94,30 +112,29 @@ const char* source_get(const struct module* module, unsigned idx)
* SymEnumSourceFiles (DBGHELP.@)
*
*/
BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG64 ModBase, LPSTR Mask,
PSYM_ENUMSOURCFILES_CALLBACK cbSrcFiles,
BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG64 ModBase, PCSTR Mask,
PSYM_ENUMSOURCEFILES_CALLBACK cbSrcFiles,
PVOID UserContext)
{
struct process* pcs;
struct module* module;
struct module_pair pair;
SOURCEFILE sf;
char* ptr;
if (!cbSrcFiles) return FALSE;
pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
pair.pcs = process_find_by_handle(hProcess);
if (!pair.pcs) return FALSE;
if (ModBase)
{
module = module_find_by_addr(pcs, ModBase, DMT_UNKNOWN);
if (!(module = module_get_debug(pcs, module))) return FALSE;
pair.requested = module_find_by_addr(pair.pcs, ModBase, DMT_UNKNOWN);
if (!module_get_debug(&pair)) 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;
pair.requested = module_find_by_nameA(pair.pcs, Mask + 1);
if (!module_get_debug(&pair)) return FALSE;
}
else
{
@ -125,8 +142,8 @@ BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG64 ModBase, LPSTR Mask,
return FALSE;
}
}
if (!module->sources) return FALSE;
for (ptr = module->sources; *ptr; ptr += strlen(ptr) + 1)
if (!pair.effective->sources) return FALSE;
for (ptr = pair.effective->sources; *ptr; ptr += strlen(ptr) + 1)
{
/* FIXME: not using Mask */
sf.ModBase = ModBase;
@ -136,3 +153,93 @@ BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG64 ModBase, LPSTR Mask,
return TRUE;
}
/******************************************************************
* SymEnumLines (DBGHELP.@)
*
*/
BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user)
{
struct module_pair pair;
struct hash_table_iter hti;
struct symt_ht* sym;
regex_t re;
struct line_info* dli;
void* ptr;
SRCCODEINFO sci;
const char* file;
if (!cb) return FALSE;
if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE;
if (regcomp(&re, srcfile, REG_NOSUB))
{
FIXME("Couldn't compile %s\n", srcfile);
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pair.pcs = process_find_by_handle(hProcess);
if (!pair.pcs) return FALSE;
if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland);
pair.requested = module_find_by_addr(pair.pcs, base, DMT_UNKNOWN);
if (!module_get_debug(&pair)) return FALSE;
sci.SizeOfStruct = sizeof(sci);
sci.ModBase = base;
hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL);
while ((ptr = hash_table_iter_up(&hti)))
{
int i;
sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
if (sym->symt.tag != SymTagFunction) continue;
sci.FileName[0] = '\0';
for (i=0; i<vector_length(&((struct symt_function*)sym)->vlines); i++)
{
dli = vector_at(&((struct symt_function*)sym)->vlines, i);
if (dli->is_source_file)
{
file = source_get(pair.effective, dli->u.source_file);
if (regexec(&re, file, 0, NULL, 0) != 0) file = "";
strcpy(sci.FileName, file);
}
else if (sci.FileName[0])
{
sci.Key = dli;
sci.Obj[0] = '\0'; /* FIXME */
sci.LineNumber = dli->line_number;
sci.Address = dli->u.pc_offset;
if (!cb(&sci, user)) break;
}
}
}
return TRUE;
}
/******************************************************************
* SymGetSourceFileToken (DBGHELP.@)
*
*/
BOOL WINAPI SymGetSourceFileToken(HANDLE hProcess, ULONG64 base,
PCSTR src, PVOID* token, DWORD* size)
{
FIXME("%p %s %s %p %p: stub!\n",
hProcess, wine_dbgstr_longlong(base), debugstr_a(src), token, size);
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
/******************************************************************
* SymGetSourceFileTokenW (DBGHELP.@)
*
*/
BOOL WINAPI SymGetSourceFileTokenW(HANDLE hProcess, ULONG64 base,
PCWSTR src, PVOID* token, DWORD* size)
{
FIXME("%p %s %s %p %p: stub!\n",
hProcess, wine_dbgstr_longlong(base), debugstr_w(src), token, size);
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}

View file

@ -2,7 +2,7 @@
* File stabs.c - read stabs information from the modules
*
* Copyright (C) 1996, Eric Youngdale.
* 1999-2004, Eric Pouech
* 1999-2005, Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -16,7 +16,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
*
* Maintenance Information
@ -33,7 +33,9 @@
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
@ -52,7 +54,6 @@
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winnls.h"
#include "dbghelp_private.h"
@ -61,8 +62,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_stabs);
UINT64 _strtoui64( const char *nptr, char **endptr, int base );
#ifndef N_UNDF
#define N_UNDF 0x00
#endif
@ -73,9 +72,11 @@ UINT64 _strtoui64( const char *nptr, char **endptr, int base );
#define N_LCSYM 0x28
#define N_MAIN 0x2a
#define N_ROSYM 0x2c
#define N_BNSYM 0x2e
#define N_OPT 0x3c
#define N_RSYM 0x40
#define N_SLINE 0x44
#define N_ENSYM 0x4e
#define N_SO 0x64
#define N_LSYM 0x80
#define N_BINCL 0x82
@ -102,27 +103,36 @@ struct stab_nlist
static void stab_strcpy(char* dest, int sz, const char* source)
{
char* ptr = dest;
/*
* A strcpy routine that stops when we hit the ':' character.
* Faster than copying the whole thing, and then nuking the
* ':'.
* Takes also care of (valid) a::b constructs
*/
while (*source != '\0' && *source != ':' && sz-- > 0)
*dest++ = *source++;
*dest-- = '\0';
/* GCC seems to emit, in some cases, a .<digit>+ suffix.
while (*source != '\0')
{
if (source[0] != ':' && sz-- > 0) *ptr++ = *source++;
else if (source[1] == ':' && (sz -= 2) > 0)
{
*ptr++ = *source++;
*ptr++ = *source++;
}
else break;
}
*ptr-- = '\0';
/* GCC emits, in some cases, a .<digit>+ suffix.
* This is used for static variable inside functions, so
* that we can have several such variables with same name in
* the same compilation unit
* We simply ignore that suffix when present (we also get rid
* of it in ELF symtab parsing)
*/
if (isdigit(*dest))
if (ptr >= dest && isdigit(*ptr))
{
while (isdigit(*dest)) dest--;
if (*dest == '.') *dest = '\0';
while (ptr > dest && isdigit(*ptr)) ptr--;
if (*ptr == '.') *ptr = '\0';
}
assert(sz > 0);
}
@ -151,7 +161,7 @@ static int stabs_new_include(const char* file, unsigned long val)
{
num_alloc_include_def += 256;
if (!include_defs)
include_defs = HeapAlloc(GetProcessHeap(), 0,
include_defs = HeapAlloc(GetProcessHeap(), 0,
sizeof(include_defs[0]) * num_alloc_include_def);
else
include_defs = HeapReAlloc(GetProcessHeap(), 0, include_defs,
@ -232,10 +242,10 @@ static struct symt** stabs_find_ref(long filenr, long subnr)
if (cu_nrofentries <= subnr)
{
if (!cu_vector)
cu_vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
cu_vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(cu_vector[0]) * (subnr+1));
else
cu_vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
cu_vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
cu_vector, sizeof(cu_vector[0]) * (subnr+1));
cu_nrofentries = subnr + 1;
}
@ -251,10 +261,10 @@ static struct symt** stabs_find_ref(long filenr, long subnr)
if (idef->nrofentries <= subnr)
{
if (!idef->vector)
idef->vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
idef->vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(idef->vector[0]) * (subnr+1));
else
idef->vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
idef->vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
idef->vector, sizeof(idef->vector[0]) * (subnr+1));
idef->nrofentries = subnr + 1;
}
@ -267,20 +277,25 @@ static struct symt** stabs_find_ref(long filenr, long subnr)
static struct symt** stabs_read_type_enum(const char** x)
{
long filenr, subnr;
const char* iter;
char* end;
if (**x == '(')
iter = *x;
if (*iter == '(')
{
(*x)++; /* '(' */
filenr = strtol(*x, (char**)x, 10); /* <int> */
(*x)++; /* ',' */
subnr = strtol(*x, (char**)x, 10); /* <int> */
(*x)++; /* ')' */
++iter; /* '(' */
filenr = strtol(iter, &end, 10); /* <int> */
iter = ++end; /* ',' */
subnr = strtol(iter, &end, 10); /* <int> */
iter = ++end; /* ')' */
}
else
{
filenr = 0;
subnr = strtol(*x, (char**)x, 10); /* <int> */
filenr = 0;
subnr = strtol(iter, &end, 10); /* <int> */
iter = end;
}
*x = iter;
return stabs_find_ref(filenr, subnr);
}
@ -292,7 +307,7 @@ struct ParseTypedefData
int idx;
struct module* module;
#ifdef PTS_DEBUG
struct PTS_Error
struct PTS_Error
{
const char* ptr;
unsigned line;
@ -349,27 +364,40 @@ static int stabs_get_basic(struct ParseTypedefData* ptd, unsigned basic, struct
case 35: stabs_basic[basic] = symt_new_basic(ptd->module, btComplex, "long double complex", 24); break;
default: PTS_ABORTIF(ptd, 1);
}
}
}
*symt = &stabs_basic[basic]->symt;
return 0;
}
static int stabs_pts_read_type_def(struct ParseTypedefData* ptd,
static int stabs_pts_read_type_def(struct ParseTypedefData* ptd,
const char* typename, struct symt** dt);
static int stabs_pts_read_id(struct ParseTypedefData* ptd)
{
const char* first = ptd->ptr;
unsigned int len;
unsigned int template = 0;
char ch;
PTS_ABORTIF(ptd, (ptd->ptr = strchr(ptd->ptr, ':')) == NULL);
len = ptd->ptr - first;
PTS_ABORTIF(ptd, len >= sizeof(ptd->buf) - ptd->idx);
memcpy(ptd->buf + ptd->idx, first, len);
ptd->buf[ptd->idx + len] = '\0';
ptd->idx += len + 1;
ptd->ptr++; /* ':' */
return 0;
while ((ch = *ptd->ptr++) != '\0')
{
switch (ch)
{
case ':':
if (template == 0)
{
unsigned int len = ptd->ptr - first - 1;
PTS_ABORTIF(ptd, len >= sizeof(ptd->buf) - ptd->idx);
memcpy(ptd->buf + ptd->idx, first, len);
ptd->buf[ptd->idx + len] = '\0';
ptd->idx += len + 1;
return 0;
}
break;
case '<': template++; break;
case '>': PTS_ABORTIF(ptd, template == 0); template--; break;
}
}
return -1;
}
static int stabs_pts_read_number(struct ParseTypedefData* ptd, long* v)
@ -404,7 +432,7 @@ static int stabs_pts_read_type_reference(struct ParseTypedefData* ptd,
struct pts_range_value
{
unsigned long long val;
ULONGLONG val;
int sign;
};
@ -420,7 +448,7 @@ static int stabs_pts_read_range_value(struct ParseTypedefData* ptd, struct pts_r
{
switch (ptd->ptr[1])
{
case '0':
case '0':
PTS_ABORTIF(ptd, ptd->ptr[0] != '1');
prv->sign = -1;
prv->val = 0;
@ -437,13 +465,13 @@ static int stabs_pts_read_range_value(struct ParseTypedefData* ptd, struct pts_r
break;
case '-':
prv->sign = -1;
prv->val = _strtoui64(++ptd->ptr, &last, 10);
prv->val = strtoull(++ptd->ptr, &last, 10);
ptd->ptr = last;
break;
case '+':
default:
default:
prv->sign = 1;
prv->val = _strtoui64(ptd->ptr, &last, 10);
prv->val = strtoull(ptd->ptr, &last, 10);
ptd->ptr = last;
break;
}
@ -459,7 +487,7 @@ static int stabs_pts_read_range(struct ParseTypedefData* ptd, const char* typena
unsigned size;
enum BasicType bt;
int i;
unsigned long long v;
ULONGLONG v;
/* type ';' <int> ';' <int> ';' */
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &ref) == -1);
@ -532,7 +560,7 @@ static int stabs_pts_read_range(struct ParseTypedefData* ptd, const char* typena
return 0;
}
static __inline int stabs_pts_read_method_info(struct ParseTypedefData* ptd)
static inline int stabs_pts_read_method_info(struct ParseTypedefData* ptd)
{
struct symt* dt;
char* tmp;
@ -572,7 +600,7 @@ static __inline int stabs_pts_read_method_info(struct ParseTypedefData* ptd)
return 0;
}
static __inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd,
static inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd,
struct symt_udt* sdt)
{
long sz, ofs;
@ -603,11 +631,11 @@ static __inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd,
{
char tmp[256];
WCHAR* name;
DWORD size;
DWORD64 size;
symt_get_info(adt, TI_GET_SYMNAME, &name);
strcmp(tmp, "__inherited_class_");
WideCharToMultiByte(CP_ACP, 0, name, -1,
strcpy(tmp, "__inherited_class_");
WideCharToMultiByte(CP_ACP, 0, name, -1,
tmp + strlen(tmp), sizeof(tmp) - strlen(tmp),
NULL, NULL);
HeapFree(GetProcessHeap(), 0, name);
@ -618,11 +646,11 @@ static __inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd,
* be much of a problem
*/
symt_get_info(adt, TI_GET_LENGTH, &size);
symt_add_udt_element(ptd->module, sdt, tmp, adt, ofs, size * 8);
symt_add_udt_element(ptd->module, sdt, tmp, adt, ofs, (DWORD)size * 8);
}
PTS_ABORTIF(ptd, *ptd->ptr++ != ';');
}
}
/* if the structure has already been filled, just redo the parsing
* but don't store results into the struct
@ -630,7 +658,7 @@ static __inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd,
*/
/* Now parse the individual elements of the structure/union. */
while (*ptd->ptr != ';')
while (*ptd->ptr != ';')
{
/* agg_name : type ',' <int:offset> ',' <int:size> */
idx = ptd->idx;
@ -672,7 +700,7 @@ static __inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd,
*/
if (*ptd->ptr == ':')
{
ptd->ptr++;
ptd->ptr++;
stabs_pts_read_method_info(ptd);
ptd->idx = idx;
continue;
@ -718,7 +746,7 @@ static __inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd,
return 0;
}
static __inline int stabs_pts_read_enum(struct ParseTypedefData* ptd,
static inline int stabs_pts_read_enum(struct ParseTypedefData* ptd,
struct symt_enum* edt)
{
long value;
@ -737,26 +765,27 @@ static __inline int stabs_pts_read_enum(struct ParseTypedefData* ptd,
return 0;
}
static __inline int stabs_pts_read_array(struct ParseTypedefData* ptd,
static inline int stabs_pts_read_array(struct ParseTypedefData* ptd,
struct symt** adt)
{
long lo, hi;
struct symt* rdt;
struct symt* range_dt;
struct symt* base_dt;
/* ar<typeinfo_nodef>;<int>;<int>;<typeinfo> */
PTS_ABORTIF(ptd, *ptd->ptr++ != 'r');
/* FIXME: range type is lost, always assume int */
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &rdt) == -1);
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &range_dt) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &lo) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &hi) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &rdt) == -1);
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &base_dt) == -1);
*adt = &symt_new_array(ptd->module, lo, hi, rdt)->symt;
*adt = &symt_new_array(ptd->module, lo, hi, base_dt, range_dt)->symt;
return 0;
}
@ -781,7 +810,7 @@ static int stabs_pts_read_type_def(struct ParseTypedefData* ptd, const char* typ
PTS_ABORTIF(ptd, new_dt != btNoType);
/* first handle attribute if any */
switch (*ptd->ptr)
switch (*ptd->ptr)
{
case '@':
if (*++ptd->ptr == 's')
@ -824,7 +853,7 @@ static int stabs_pts_read_type_def(struct ParseTypedefData* ptd, const char* typ
break;
case 'f':
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &ref_dt) == -1);
new_dt = &symt_new_function_signature(ptd->module, ref_dt)->symt;
new_dt = &symt_new_function_signature(ptd->module, ref_dt, -1)->symt;
break;
case 'e':
new_dt = &symt_new_enum(ptd->module, typename)->symt;
@ -847,16 +876,28 @@ static int stabs_pts_read_type_def(struct ParseTypedefData* ptd, const char* typ
}
else
{
unsigned l1, l2;
if (udt->symt.tag != SymTagUDT)
{
ERR("Forward declaration (%p/%s) is not an aggregate (%u)\n",
udt, symt_get_name(&udt->symt), udt->symt.tag);
return -1;
}
if (strcmp(udt->hash_elt.name, typename))
/* FIXME: we currently don't correctly construct nested C++
* classes names. Therefore, we could be here with either:
* - typename and udt->hash_elt.name being the same string
* (non embedded case)
* - typename being foo::bar while udt->hash_elt.name being
* just bar
* So, we twist the comparison to test both occurrences. When
* we have proper C++ types in this file, this twist has to be
* removed
*/
l1 = strlen(udt->hash_elt.name);
l2 = strlen(typename);
if (l1 > l2 || strcmp(udt->hash_elt.name, typename + l2 - l1))
ERR("Forward declaration name mismatch %s <> %s\n",
udt->hash_elt.name, typename);
/* should check typename is the same too */
new_dt = &udt->symt;
}
PTS_ABORTIF(ptd, stabs_pts_read_aggregate(ptd, udt) == -1);
@ -894,7 +935,7 @@ static int stabs_pts_read_type_def(struct ParseTypedefData* ptd, const char* typ
{
ptd->ptr++;
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &ref_dt) == -1);
new_dt = &symt_new_function_signature(ptd->module, ref_dt)->symt;
new_dt = &symt_new_function_signature(ptd->module, ref_dt, -1)->symt;
}
else
{
@ -904,7 +945,7 @@ static int stabs_pts_read_type_def(struct ParseTypedefData* ptd, const char* typ
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &cls_dt) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ',');
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &ref_dt) == -1);
new_dt = &symt_new_function_signature(ptd->module, ref_dt)->symt;
new_dt = &symt_new_function_signature(ptd->module, ref_dt, -1)->symt;
while (*ptd->ptr == ',')
{
ptd->ptr++;
@ -916,7 +957,7 @@ static int stabs_pts_read_type_def(struct ParseTypedefData* ptd, const char* typ
{
long type, len, unk;
int basic;
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &type) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &len) == -1);
@ -955,7 +996,7 @@ static int stabs_pts_read_type_def(struct ParseTypedefData* ptd, const char* typ
new_dt = &symt_new_basic(ptd->module, btVoid, typename, 0)->symt;
PTS_ABORTIF(ptd, strcmp(typename, "void"));
}
}
}
*stabs_find_ref(filenr1, subnr1) = *ret_dt = new_dt;
@ -964,7 +1005,7 @@ static int stabs_pts_read_type_def(struct ParseTypedefData* ptd, const char* typ
return 0;
}
static int stabs_parse_typedef(struct module* module, const char* ptr,
static int stabs_parse_typedef(struct module* module, const char* ptr,
const char* typename)
{
struct ParseTypedefData ptd;
@ -973,7 +1014,7 @@ static int stabs_parse_typedef(struct module* module, const char* ptr,
/* check for already existing definition */
TRACE("%s\n", debugstr_a(ptr));
TRACE("%s => %s\n", typename, debugstr_a(ptr));
ptd.module = module;
ptd.idx = 0;
#ifdef PTS_DEBUG
@ -992,7 +1033,7 @@ static int stabs_parse_typedef(struct module* module, const char* ptr,
ret = stabs_pts_read_type_def(&ptd, typename, &dt);
}
if (ret == -1 || *ptd.ptr)
if (ret == -1 || *ptd.ptr)
{
#ifdef PTS_DEBUG
int i;
@ -1001,13 +1042,13 @@ static int stabs_parse_typedef(struct module* module, const char* ptr,
{
for (i = 0; i < ptd.err_idx; i++)
{
TRACE("[%d]: line %d => %s\n",
TRACE("[%d]: line %d => %s\n",
i, ptd.errors[i].line, debugstr_a(ptd.errors[i].ptr));
}
}
else
TRACE("[0]: => %s\n", debugstr_a(ptd.ptr));
#else
ERR("Failure on %s at %s\n", debugstr_a(ptr), debugstr_a(ptd.ptr));
#endif
@ -1052,23 +1093,66 @@ struct pending_loc_var
{
char name[256];
struct symt* type;
unsigned offset;
unsigned regno;
enum DataKind kind;
struct location loc;
};
struct pending_block
{
struct pending_loc_var* vars;
unsigned num;
unsigned allocated;
};
static inline void pending_add(struct pending_block* pending, const char* name,
enum DataKind dt, const struct location* loc)
{
if (pending->num == pending->allocated)
{
pending->allocated += 8;
if (!pending->vars)
pending->vars = HeapAlloc(GetProcessHeap(), 0,
pending->allocated * sizeof(pending->vars[0]));
else
pending->vars = HeapReAlloc(GetProcessHeap(), 0, pending->vars,
pending->allocated * sizeof(pending->vars[0]));
}
stab_strcpy(pending->vars[pending->num].name,
sizeof(pending->vars[pending->num].name), name);
pending->vars[pending->num].type = stabs_parse_type(name);
pending->vars[pending->num].kind = dt;
pending->vars[pending->num].loc = *loc;
pending->num++;
}
static void pending_flush(struct pending_block* pending, struct module* module,
struct symt_function* func, struct symt_block* block)
{
int i;
for (i = 0; i < pending->num; i++)
{
symt_add_func_local(module, func,
pending->vars[i].kind, &pending->vars[i].loc,
block, pending->vars[i].type, pending->vars[i].name);
}
pending->num = 0;
}
/******************************************************************
* stabs_finalize_function
*
* Ends function creation: mainly:
* - cleans up line number information
* - tries to set up a debug-start tag (FIXME: heuristic to be enhanced)
* - for stabs which have abolute address in them, initializes the size of the
* - for stabs which have abolute address in them, initializes the size of the
* function (assuming that current function ends where next function starts)
*/
static void stabs_finalize_function(struct module* module, struct symt_function* func,
unsigned long end)
unsigned long size)
{
IMAGEHLP_LINE il;
struct location loc;
if (!func) return;
symt_normalize_function(module, func);
@ -1078,22 +1162,23 @@ static void stabs_finalize_function(struct module* module, struct symt_function*
if (symt_fill_func_line_info(module, func, func->address, &il) &&
symt_get_func_line_next(module, &il))
{
symt_add_function_point(module, func, SymTagFuncDebugStart,
il.Address - func->address, NULL);
loc.kind = loc_absolute;
loc.offset = il.Address - func->address;
symt_add_function_point(module, func, SymTagFuncDebugStart,
&loc, NULL);
}
if (end) func->size = end - func->address;
if (size) func->size = size;
}
BOOL stabs_parse(struct module* module, unsigned long load_offset,
BOOL stabs_parse(struct module* module, unsigned long load_offset,
const void* pv_stab_ptr, int stablen,
const char* strs, int strtablen)
{
struct symt_function* curr_func = NULL;
struct symt_block* block = NULL;
struct symt_compiland* compiland = NULL;
char currpath[PATH_MAX]; /* path to current file */
char srcpath[PATH_MAX]; /* path to directory source file is in */
int i, j;
int i;
int nstab;
const char* ptr;
char* stabbuff;
@ -1105,16 +1190,16 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
unsigned incl[32];
int incl_stk = -1;
int source_idx = -1;
struct pending_loc_var* pending_vars = NULL;
unsigned num_pending_vars = 0;
unsigned num_allocated_pending_vars = 0;
struct pending_block pending;
BOOL ret = TRUE;
struct location loc;
nstab = stablen / sizeof(struct stab_nlist);
strs_end = strs + strtablen;
memset(srcpath, 0, sizeof(srcpath));
memset(stabs_basic, 0, sizeof(stabs_basic));
memset(&pending, 0, sizeof(pending));
/*
* Allocate a buffer into which we can build stab strings for cases
@ -1133,7 +1218,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
WARN("Bad stabs string %p\n", ptr);
continue;
}
if (ptr[strlen(ptr) - 1] == '\\')
if (*ptr != '\0' && (ptr[strlen(ptr) - 1] == '\\'))
{
/*
* Indicates continuation. Append this to the buffer, and go onto the
@ -1164,6 +1249,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
case N_RSYM:
case N_LSYM:
case N_ROSYM:
case N_PSYM:
if (strchr(ptr, '=') != NULL)
{
/*
@ -1185,42 +1271,6 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
}
}
#if 0
const char* defs[] = {"","","","", /* 00 */
"","","","", /* 08 */
"","","","", /* 10 */
"","","","", /* 18 */
"gsym","","fun","stsym", /* 20 */
"lcsym","main","rosym","", /* 28 */
"","","","", /* 30 */
"","","opt","", /* 38 */
"rsym","","sline","", /* 40 */
"","","","", /* 48 */
"","","","", /* 50 */
"","","","", /* 58 */
"","","so","", /* 60 */
"","","","", /* 68 */
"","","","", /* 70 */
"","","","", /* 78 */
"lsym","bincl","sol","", /* 80 */
"","","","", /* 88 */
"","","","", /* 90 */
"","","","", /* 98 */
"psym","eincl","","", /* a0 */
"","","","", /* a8 */
"","","","", /* b0 */
"","","","", /* b8 */
"lbrac","excl","","", /* c0 */
"","","","", /* c8 */
"","","","", /* d0 */
"","","","", /* d8 */
"rbrac","","","", /* e0 */
};
FIXME("Got %s<%u> %u/%lu (%s)\n",
defs[stab_ptr->n_type / 2], stab_ptr->n_type, stab_ptr->n_desc, stab_ptr->n_value, debugstr_a(ptr));
#endif
switch (stab_ptr->n_type)
{
case N_GSYM:
@ -1246,19 +1296,17 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
stabs_parse_type(ptr));
break;
case N_LBRAC:
block = symt_open_func_block(module, curr_func, block,
stab_ptr->n_value, 0);
for (j = 0; j < num_pending_vars; j++)
if (curr_func)
{
symt_add_func_local(module, curr_func, pending_vars[j].regno,
pending_vars[j].offset,
block, pending_vars[j].type, pending_vars[j].name);
block = symt_open_func_block(module, curr_func, block,
stab_ptr->n_value, 0);
pending_flush(&pending, module, curr_func, block);
}
num_pending_vars = 0;
break;
case N_RBRAC:
block = symt_close_func_block(module, curr_func, block,
stab_ptr->n_value);
if (curr_func)
block = symt_close_func_block(module, curr_func, block,
stab_ptr->n_value);
break;
case N_PSYM:
/* These are function parameters. */
@ -1266,10 +1314,14 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
{
struct symt* param_type = stabs_parse_type(ptr);
stab_strcpy(symname, sizeof(symname), ptr);
symt_add_func_local(module, curr_func, 0, stab_ptr->n_value,
NULL, param_type, symname);
symt_add_function_signature_parameter(module,
(struct symt_function_signature*)curr_func->type,
loc.kind = loc_regrel;
loc.reg = 0; /* FIXME */
loc.offset = stab_ptr->n_value;
symt_add_func_local(module, curr_func,
(long)stab_ptr->n_value >= 0 ? DataIsParam : DataIsLocal,
&loc, NULL, param_type, symname);
symt_add_function_signature_parameter(module,
(struct symt_function_signature*)curr_func->type,
param_type);
}
break;
@ -1277,28 +1329,19 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
/* These are registers (as local variables) */
if (curr_func != NULL)
{
unsigned reg;
loc.kind = loc_register;
loc.offset = 0;
if (num_pending_vars == num_allocated_pending_vars)
{
num_allocated_pending_vars += 8;
if (!pending_vars)
pending_vars = HeapAlloc(GetProcessHeap(), 0,
num_allocated_pending_vars * sizeof(pending_vars[0]));
else
pending_vars = HeapReAlloc(GetProcessHeap(), 0, pending_vars,
num_allocated_pending_vars * sizeof(pending_vars[0]));
}
switch (stab_ptr->n_value)
{
case 0: reg = CV_REG_EAX; break;
case 1: reg = CV_REG_ECX; break;
case 2: reg = CV_REG_EDX; break;
case 3: reg = CV_REG_EBX; break;
case 4: reg = CV_REG_ESP; break;
case 5: reg = CV_REG_EBP; break;
case 6: reg = CV_REG_ESI; break;
case 7: reg = CV_REG_EDI; break;
case 0: loc.reg = CV_REG_EAX; break;
case 1: loc.reg = CV_REG_ECX; break;
case 2: loc.reg = CV_REG_EDX; break;
case 3: loc.reg = CV_REG_EBX; break;
case 4: loc.reg = CV_REG_ESP; break;
case 5: loc.reg = CV_REG_EBP; break;
case 6: loc.reg = CV_REG_ESI; break;
case 7: loc.reg = CV_REG_EDI; break;
case 11:
case 12:
case 13:
@ -1307,42 +1350,33 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
case 16:
case 17:
case 18:
case 19: reg = CV_REG_ST0 + stab_ptr->n_value - 12; break;
case 19: loc.reg = CV_REG_ST0 + stab_ptr->n_value - 12; break;
default:
FIXME("Unknown register value (%lu)\n", stab_ptr->n_value);
reg = CV_REG_NONE;
loc.reg = CV_REG_NONE;
break;
}
stab_strcpy(pending_vars[num_pending_vars].name,
sizeof(pending_vars[num_pending_vars].name), ptr);
pending_vars[num_pending_vars].type = stabs_parse_type(ptr);
pending_vars[num_pending_vars].offset = 0;
pending_vars[num_pending_vars].regno = reg;
num_pending_vars++;
stab_strcpy(symname, sizeof(symname), ptr);
if (ptr[strlen(symname) + 1] == 'P')
{
struct symt* param_type = stabs_parse_type(ptr);
stab_strcpy(symname, sizeof(symname), ptr);
symt_add_func_local(module, curr_func, DataIsParam, &loc,
NULL, param_type, symname);
symt_add_function_signature_parameter(module,
(struct symt_function_signature*)curr_func->type,
param_type);
}
else
pending_add(&pending, ptr, DataIsLocal, &loc);
}
break;
case N_LSYM:
/* These are local variables */
if (curr_func != NULL)
{
if (num_pending_vars == num_allocated_pending_vars)
{
num_allocated_pending_vars += 8;
if (!pending_vars)
pending_vars = HeapAlloc(GetProcessHeap(), 0,
num_allocated_pending_vars * sizeof(pending_vars[0]));
else
pending_vars = HeapReAlloc(GetProcessHeap(), 0, pending_vars,
num_allocated_pending_vars * sizeof(pending_vars[0]));
}
stab_strcpy(pending_vars[num_pending_vars].name,
sizeof(pending_vars[num_pending_vars].name), ptr);
pending_vars[num_pending_vars].type = stabs_parse_type(ptr);
pending_vars[num_pending_vars].offset = stab_ptr->n_value;
pending_vars[num_pending_vars].regno = 0;
num_pending_vars++;
}
loc.kind = loc_regrel;
loc.reg = 0; /* FIXME */
loc.offset = stab_ptr->n_value;
if (curr_func != NULL) pending_add(&pending, ptr, DataIsLocal, &loc);
break;
case N_SLINE:
/*
@ -1352,15 +1386,11 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
if (curr_func != NULL)
{
assert(source_idx >= 0);
symt_add_func_line(module, curr_func, source_idx,
symt_add_func_line(module, curr_func, source_idx,
stab_ptr->n_desc, stab_ptr->n_value);
}
break;
case N_FUN:
/* First, clean up the previous function we were working on. */
stabs_finalize_function(module, curr_func,
stab_ptr->n_value ? load_offset + stab_ptr->n_value : 0);
/*
* For now, just declare the various functions. Later
* on, we will add the line number information and the
@ -1377,15 +1407,29 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
if (*symname)
{
struct symt_function_signature* func_type;
func_type = symt_new_function_signature(module,
stabs_parse_type(ptr));
curr_func = symt_new_function(module, compiland, symname,
if (curr_func)
{
/* First, clean up the previous function we were working on.
* Assume size of the func is the delta between current offset
* and offset of last function
*/
stabs_finalize_function(module, curr_func,
stab_ptr->n_value ?
(load_offset + stab_ptr->n_value - curr_func->address) : 0);
}
func_type = symt_new_function_signature(module,
stabs_parse_type(ptr), -1);
curr_func = symt_new_function(module, compiland, symname,
load_offset + stab_ptr->n_value, 0,
&func_type->symt);
}
else
{
/* some GCC seem to use a N_FUN "" to mark the end of a function */
/* some versions of GCC to use a N_FUN "" to mark the end of a function
* and n_value contains the size of the func
*/
stabs_finalize_function(module, curr_func, stab_ptr->n_value);
curr_func = NULL;
}
break;
@ -1398,8 +1442,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
{
/* Nuke old path. */
srcpath[0] = '\0';
stabs_finalize_function(module, curr_func,
stab_ptr->n_value ? load_offset + stab_ptr->n_value : 0);
stabs_finalize_function(module, curr_func, 0);
curr_func = NULL;
source_idx = -1;
incl_stk = -1;
@ -1411,33 +1454,27 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
int len = strlen(ptr);
if (ptr[len-1] != '/')
{
strcpy(currpath, srcpath);
strcat(currpath, ptr);
stabs_reset_includes();
compiland = symt_new_compiland(module, currpath);
source_idx = source_new(module, currpath);
source_idx = source_new(module, srcpath, ptr);
compiland = symt_new_compiland(module, 0 /* FIXME */, source_idx);
}
else
strcpy(srcpath, ptr);
}
break;
case N_SOL:
if (*ptr != '/')
{
strcpy(currpath, srcpath);
strcat(currpath, ptr);
}
else
strcpy(currpath, ptr);
source_idx = source_new(module, currpath);
source_idx = source_new(module, srcpath, ptr);
break;
case N_UNDF:
strs += strtabinc;
strtabinc = stab_ptr->n_value;
/* I'm not sure this is needed, so trace it before we obsolete it */
if (curr_func) FIXME("UNDF: curr_func %s\n", curr_func->hash_elt.name);
stabs_finalize_function(module, curr_func, 0); /* FIXME */
curr_func = NULL;
if (curr_func)
{
FIXME("UNDF: curr_func %s\n", curr_func->hash_elt.name);
stabs_finalize_function(module, curr_func, 0); /* FIXME */
curr_func = NULL;
}
break;
case N_OPT:
/* Ignore this. We don't care what it points to. */
@ -1446,7 +1483,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
stabs_add_include(stabs_new_include(ptr, stab_ptr->n_value));
assert(incl_stk < (int)(sizeof(incl) / sizeof(incl[0])) - 1);
incl[++incl_stk] = source_idx;
source_idx = source_new(module, ptr);
source_idx = source_new(module, NULL, ptr);
break;
case N_EINCL:
assert(incl_stk >= 0);
@ -1464,19 +1501,30 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
case N_MAIN:
/* Always ignore these. GCC doesn't even generate them. */
break;
case N_BNSYM:
case N_ENSYM:
/* Always ignore these, they seem to be used only on Darwin. */
break;
default:
ERR("Unknown stab type 0x%02x\n", stab_ptr->n_type);
break;
}
stabbuff[0] = '\0';
TRACE("0x%02x %lx %s\n",
TRACE("0x%02x %lx %s\n",
stab_ptr->n_type, stab_ptr->n_value, debugstr_a(strs + stab_ptr->n_un.n_strx));
}
module->module.SymType = SymDia;
module->module.CVSig = 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24);
/* FIXME: we could have a finer grain here */
module->module.LineNumbers = TRUE;
module->module.GlobalSymbols = TRUE;
module->module.TypeInfo = TRUE;
module->module.SourceIndexed = TRUE;
module->module.Publics = TRUE;
done:
HeapFree(GetProcessHeap(), 0, stabbuff);
stabs_free_includes();
if (pending_vars) HeapFree(GetProcessHeap(), 0, pending_vars);
HeapFree(GetProcessHeap(), 0, pending.vars);
return ret;
}

View file

@ -18,7 +18,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
@ -27,11 +27,12 @@
#include <string.h>
#include <assert.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "dbghelp_private.h"
#include "winreg.h"
#include "thread.h" /* FIXME: must be included before winternl.h */
#include "winternl.h"
#include "wine/winbase16.h"
#include "wine/debug.h"
#include "stackframe.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
@ -43,18 +44,36 @@ static const char* wine_dbgstr_addr(const ADDRESS* addr)
switch (addr->Mode)
{
case AddrModeFlat:
return wine_dbg_sprintf("flat<%08lx>", addr->Offset);
return wine_dbg_sprintf("flat<%08x>", addr->Offset);
case AddrMode1616:
return wine_dbg_sprintf("1616<%04x:%04lx>", addr->Segment, addr->Offset);
return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, addr->Offset);
case AddrMode1632:
return wine_dbg_sprintf("1632<%04x:%08lx>", addr->Segment, addr->Offset);
return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, addr->Offset);
case AddrModeReal:
return wine_dbg_sprintf("real<%04x:%04lx>", addr->Segment, addr->Offset);
return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, addr->Offset);
default:
return "unknown";
}
}
static BOOL CALLBACK read_mem(HANDLE hProcess, DWORD addr, void* buffer,
DWORD size, LPDWORD nread)
{
SIZE_T r;
if (!ReadProcessMemory(hProcess, (void*)addr, buffer, size, &r)) return FALSE;
if (nread) *nread = r;
return TRUE;
}
static BOOL CALLBACK read_mem64(HANDLE hProcess, DWORD64 addr, void* buffer,
DWORD size, LPDWORD nread)
{
SIZE_T r;
if (!ReadProcessMemory(hProcess, (void*)(DWORD_PTR)addr, buffer, size, &r)) return FALSE;
if (nread) *nread = r;
return TRUE;
}
/* indexes in Reserved array */
#define __CurrentMode 0
#define __CurrentSwitch 1
@ -64,15 +83,83 @@ static const char* wine_dbgstr_addr(const ADDRESS* addr)
#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)
struct stack_walk_callback
{
HANDLE hProcess;
HANDLE hThread;
BOOL is32;
union
{
struct
{
PREAD_PROCESS_MEMORY_ROUTINE f_read_mem;
PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr;
PFUNCTION_TABLE_ACCESS_ROUTINE f_tabl_acs;
PGET_MODULE_BASE_ROUTINE f_modl_bas;
} s32;
struct
{
PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem;
PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr;
PFUNCTION_TABLE_ACCESS_ROUTINE64 f_tabl_acs;
PGET_MODULE_BASE_ROUTINE64 f_modl_bas;
} s64;
} u;
};
static inline void addr_32to64(const ADDRESS* addr32, ADDRESS64* addr64)
{
addr64->Offset = (ULONG64)addr32->Offset;
addr64->Segment = addr32->Segment;
addr64->Mode = addr32->Mode;
}
static inline void addr_64to32(const ADDRESS64* addr64, ADDRESS* addr32)
{
addr32->Offset = (ULONG)addr64->Offset;
addr32->Segment = addr64->Segment;
addr32->Mode = addr64->Mode;
}
static inline BOOL sw_read_mem(struct stack_walk_callback* cb, DWORD addr, void* ptr, DWORD sz)
{
if (cb->is32)
return cb->u.s32.f_read_mem(cb->hProcess, addr, ptr, sz, NULL);
else
return cb->u.s64.f_read_mem(cb->hProcess, addr, ptr, sz, NULL);
}
static inline DWORD sw_xlat_addr(struct stack_walk_callback* cb, ADDRESS* addr)
{
if (addr->Mode == AddrModeFlat) return addr->Offset;
if (cb->is32) return cb->u.s32.f_xlat_adr(cb->hProcess, cb->hThread, addr);
if (cb->u.s64.f_xlat_adr)
{
ADDRESS64 addr64;
addr_32to64(addr, &addr64);
return cb->u.s64.f_xlat_adr(cb->hProcess, cb->hThread, &addr64);
}
return addr_to_linear(cb->hProcess, cb->hThread, addr);
}
static inline void* sw_tabl_acs(struct stack_walk_callback* cb, DWORD addr)
{
if (cb->is32)
return cb->u.s32.f_tabl_acs(cb->hProcess, addr);
else
return cb->u.s64.f_tabl_acs(cb->hProcess, addr);
}
static inline DWORD sw_modl_bas(struct stack_walk_callback* cb, DWORD addr)
{
if (cb->is32)
return cb->u.s32.f_modl_bas(cb->hProcess, addr);
else
return cb->u.s64.f_modl_bas(cb->hProcess, addr);
}
static BOOL stack_walk(struct stack_walk_callback* cb, LPSTACKFRAME frame)
{
STACK32FRAME frame32;
STACK16FRAME frame16;
@ -82,34 +169,20 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
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",
TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08x nSwitch=%08x\n",
wine_dbgstr_addr(&frame->AddrPC),
wine_dbgstr_addr(&frame->AddrFrame),
wine_dbgstr_addr(&frame->AddrReturn),
wine_dbgstr_addr(&frame->AddrStack),
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;*/
THREAD_BASIC_INFORMATION info;
if ((frame->AddrPC.Mode == AddrModeFlat) &&
(frame->AddrFrame.Mode != AddrModeFlat))
@ -119,60 +192,62 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
}
/* Init done */
curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ?
curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ?
stm_32bit : stm_16bit;
/* cur_switch holds address of curr_stack's field in TEB in debuggee
/* cur_switch holds address of WOW32Reserved 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))
if (NtQueryInformationThread(cb->hThread, ThreadBasicInformation, &info,
sizeof(info), NULL) == STATUS_SUCCESS)
{
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))
curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved);
if (!sw_read_mem(cb, curr_switch, &next_switch, sizeof(next_switch)))
{
WARN("Bad stack frame 0x%08lx\n", next_switch);
WARN("Can't read TEB:WOW32Reserved\n");
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;
if (curr_mode == stm_16bit)
{
if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32)))
{
WARN("Bad stack frame 0x%08x\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 (!sw_read_mem(cb, sw_xlat_addr(cb, &tmp), &ch, sizeof(ch)))
curr_switch = 0xFFFFFFFF;
}
else
{
tmp.Mode = AddrMode1616;
tmp.Segment = SELECTOROF(next_switch);
tmp.Offset = OFFSETOF(next_switch);
p = sw_xlat_addr(cb, &tmp);
if (!sw_read_mem(cb, p, &frame16, sizeof(frame16)))
{
WARN("Bad stack frame 0x%08x\n", p);
goto done_err;
}
curr_switch = (DWORD)frame16.frame32;
if (!sw_read_mem(cb, curr_switch, &ch, sizeof(ch)))
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;
}
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;
}
/* FIXME: this will allow to work when we're not attached to a live target,
* but the 16 <=> 32 switch facility won't be available.
*/
curr_switch = 0;
frame->AddrReturn.Mode = frame->AddrStack.Mode = (curr_mode == stm_16bit) ? AddrMode1616 : AddrModeFlat;
/* don't set up AddrStack on first call. Either the caller has set it up, or
* we will get it in the next frame
*/
memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore));
}
else
{
@ -185,19 +260,18 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
else
{
assert(curr_mode == stm_16bit);
do_switch = OFFSETOF(curr_switch) &&
do_switch = 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))
if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32)))
{
WARN("Bad stack frame 0x%08lx\n", next_switch);
WARN("Bad stack frame 0x%08x\n", next_switch);
goto done_err;
}
@ -217,37 +291,37 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
tmp.Mode = AddrMode1616;
tmp.Segment = SELECTOROF(next_switch);
tmp.Offset = OFFSETOF(next_switch);
p = f_xlat_adr(hProcess, hThread, &tmp);
p = sw_xlat_addr(cb, &tmp);
if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
if (!sw_read_mem(cb, p, &frame16, sizeof(frame16)))
{
WARN("Bad stack frame 0x%08lx\n", p);
WARN("Bad stack frame 0x%08x\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;
if (!sw_read_mem(cb, curr_switch, &ch, sizeof(ch)))
curr_switch = 0;
}
else
{
tmp.Mode = AddrMode1616;
tmp.Segment = SELECTOROF(next_switch);
tmp.Offset = OFFSETOF(next_switch);
p = f_xlat_adr(hProcess, hThread, &tmp);
p = sw_xlat_addr(cb, &tmp);
if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
if (!sw_read_mem(cb, p, &frame16, sizeof(frame16)))
{
WARN("Bad stack frame 0x%08lx\n", p);
WARN("Bad stack frame 0x%08x\n", p);
goto done_err;
}
TRACE("Got a 16 bit stack switch:"
"\n\tframe32: %08lx"
"\n\tedx:%08lx ecx:%08lx ebp:%08lx"
"\n\tedx:%08x ecx:%08x ebp:%08x"
"\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\tcall_from_ip:%08x module_cs:%04x relay=%08x"
"\n\tentry_ip:%04x entry_point:%08x"
"\n\tbp:%04x ip:%04x cs:%04x\n",
(unsigned long)frame16.frame32,
frame16.edx, frame16.ecx, frame16.ebp,
@ -256,7 +330,7 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
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;
@ -272,10 +346,9 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
frame->AddrReturn.Segment = frame16.cs;
next_switch = curr_switch;
if (!f_read_mem(hProcess, (void*)next_switch, &frame32, sizeof(frame32),
NULL))
if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32)))
{
WARN("Bad stack frame 0x%08lx\n", next_switch);
WARN("Bad stack frame 0x%08x\n", next_switch);
goto done_err;
}
curr_switch = (DWORD)frame32.frame16;
@ -283,9 +356,8 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
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;
if (!sw_read_mem(cb, sw_xlat_addr(cb, &tmp), &ch, sizeof(ch)))
curr_switch = 0;
curr_mode = stm_16bit;
}
}
@ -296,9 +368,8 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
{
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))
if (!sw_read_mem(cb, sw_xlat_addr(cb, &frame->AddrFrame),
&val, sizeof(WORD)))
goto done_err;
frame->AddrFrame.Offset = val;
}
@ -306,8 +377,8 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
{
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))
if (!sw_read_mem(cb, frame->AddrFrame.Offset,
&frame->AddrFrame.Offset, sizeof(DWORD)))
goto done_err;
}
}
@ -317,30 +388,29 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
{
int i;
p = f_xlat_adr(hProcess, hThread, &frame->AddrFrame);
if (!f_read_mem(hProcess, (void*)(p + sizeof(WORD)), &val, sizeof(WORD), NULL))
p = sw_xlat_addr(cb, &frame->AddrFrame);
if (!sw_read_mem(cb, p + sizeof(WORD), &val, sizeof(WORD)))
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))
if (!sw_read_mem(cb, p + 2 * sizeof(WORD), &val, sizeof(WORD)))
goto done_err;
if (frame->AddrFrame.Offset & 1)
frame->AddrReturn.Segment = val; /* far call assumed */
else
{
/* not explicitly marked as far call,
/* 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) &&
if (GetThreadSelectorEntry(cb->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
* a parameter, so this should work in most cases
*/
frame->AddrReturn.Segment = val;
}
@ -353,35 +423,181 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
*/
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);
sw_read_mem(cb, p + (2 + i) * sizeof(WORD), &val, sizeof(val));
frame->Params[i] = val;
}
}
else
{
if (!f_read_mem(hProcess,
(void*)(frame->AddrFrame.Offset + sizeof(DWORD)),
&frame->AddrReturn.Offset, sizeof(DWORD), NULL))
if (!sw_read_mem(cb, frame->AddrFrame.Offset + sizeof(DWORD),
&frame->AddrReturn.Offset, sizeof(DWORD)))
{
WARN("Cannot read new frame offset %08x\n", frame->AddrFrame.Offset + (int)sizeof(DWORD));
goto done_err;
f_read_mem(hProcess,
(void*)(frame->AddrFrame.Offset + 2 * sizeof(DWORD)),
frame->Params, sizeof(frame->Params), NULL);
}
sw_read_mem(cb, frame->AddrFrame.Offset + 2 * sizeof(DWORD),
frame->Params, sizeof(frame->Params));
}
frame->Far = FALSE;
frame->Virtual = FALSE;
frame->Far = TRUE;
frame->Virtual = TRUE;
p = sw_xlat_addr(cb, &frame->AddrPC);
if (p && sw_modl_bas(cb, p))
frame->FuncTableEntry = sw_tabl_acs(cb, p);
else
frame->FuncTableEntry = NULL;
TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08lx nSwitch=%08lx\n",
TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08x nSwitch=%08x FuncTable=%p\n",
wine_dbgstr_addr(&frame->AddrPC),
wine_dbgstr_addr(&frame->AddrFrame),
wine_dbgstr_addr(&frame->AddrReturn),
wine_dbgstr_addr(&frame->AddrStack),
wine_dbgstr_addr(&frame->AddrStack),
curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
curr_switch, next_switch);
curr_switch, next_switch, frame->FuncTableEntry);
return TRUE;
done_err:
curr_mode = stm_done;
return FALSE;
}
/***********************************************************************
* StackWalk (DBGHELP.@)
*/
BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
LPSTACKFRAME frame, PVOID ctx,
PREAD_PROCESS_MEMORY_ROUTINE f_read_mem,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr)
{
struct stack_walk_callback swcb;
TRACE("(%d, %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;
}
swcb.hProcess = hProcess;
swcb.hThread = hThread;
swcb.is32 = TRUE;
/* sigh... MS isn't even consistent in the func prototypes */
swcb.u.s32.f_read_mem = (f_read_mem) ? f_read_mem : read_mem;
swcb.u.s32.f_xlat_adr = (f_xlat_adr) ? f_xlat_adr : addr_to_linear;
swcb.u.s32.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess;
swcb.u.s32.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase;
return stack_walk(&swcb, frame);
}
/***********************************************************************
* StackWalk64 (DBGHELP.@)
*/
BOOL WINAPI StackWalk64(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
LPSTACKFRAME64 frame64, PVOID ctx,
PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr)
{
struct stack_walk_callback swcb;
STACKFRAME frame32;
BOOL ret;
TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p)\n",
MachineType, hProcess, hThread, frame64, ctx,
f_read_mem, FunctionTableAccessRoutine,
GetModuleBaseRoutine, f_xlat_adr);
if (MachineType != IMAGE_FILE_MACHINE_I386)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
addr_64to32(&frame64->AddrPC, &frame32.AddrPC);
addr_64to32(&frame64->AddrReturn, &frame32.AddrReturn);
addr_64to32(&frame64->AddrFrame, &frame32.AddrFrame);
addr_64to32(&frame64->AddrStack, &frame32.AddrStack);
addr_64to32(&frame64->AddrBStore, &frame32.AddrBStore);
frame32.FuncTableEntry = frame64->FuncTableEntry; /* FIXME */
frame32.Far = frame64->Far;
frame32.Virtual = frame64->Virtual;
frame32.Reserved[0] = (ULONG)frame64->Reserved[0];
frame32.Reserved[1] = (ULONG)frame64->Reserved[1];
frame32.Reserved[2] = (ULONG)frame64->Reserved[2];
/* we don't handle KdHelp */
swcb.hProcess = hProcess;
swcb.hThread = hThread;
swcb.is32 = FALSE;
/* sigh... MS isn't even consistent in the func prototypes */
swcb.u.s64.f_read_mem = (f_read_mem) ? f_read_mem : read_mem64;
swcb.u.s64.f_xlat_adr = f_xlat_adr;
swcb.u.s64.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess64;
swcb.u.s64.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase64;
ret = stack_walk(&swcb, &frame32);
addr_32to64(&frame32.AddrPC, &frame64->AddrPC);
addr_32to64(&frame32.AddrReturn, &frame64->AddrReturn);
addr_32to64(&frame32.AddrFrame, &frame64->AddrFrame);
addr_32to64(&frame32.AddrStack, &frame64->AddrStack);
addr_32to64(&frame32.AddrBStore, &frame64->AddrBStore);
frame64->FuncTableEntry = frame32.FuncTableEntry; /* FIXME */
frame64->Params[0] = frame32.Params[0];
frame64->Params[1] = frame32.Params[1];
frame64->Params[2] = frame32.Params[2];
frame64->Params[3] = frame32.Params[3];
frame64->Far = frame32.Far;
frame64->Virtual = frame32.Virtual;
frame64->Reserved[0] = frame32.Reserved[0];
frame64->Reserved[1] = frame32.Reserved[1];
frame64->Reserved[2] = frame32.Reserved[2];
/* we don't handle KdHelp */
frame64->KdHelp.Thread = 0xC000FADE;
frame64->KdHelp.ThCallbackStack = 0x10;
frame64->KdHelp.ThCallbackBStore = 0;
frame64->KdHelp.NextCallback = 0;
frame64->KdHelp.FramePointer = 0;
frame64->KdHelp.KiCallUserMode = 0xD000DAFE;
frame64->KdHelp.KeUserCallbackDispatcher = 0xE000F000;
frame64->KdHelp.SystemRangeStart = 0xC0000000;
frame64->KdHelp.Reserved[0] /* KiUserExceptionDispatcher */ = 0xE0005000;
return ret;
}
/******************************************************************
* SymRegisterFunctionEntryCallback (DBGHELP.@)
*
*
*/
BOOL WINAPI SymRegisterFunctionEntryCallback(HANDLE hProc,
PSYMBOL_FUNCENTRY_CALLBACK cb, PVOID user)
{
FIXME("(%p %p %p): stub!\n", hProc, cb, user);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/******************************************************************
* SymRegisterFunctionEntryCallback64 (DBGHELP.@)
*
*
*/
BOOL WINAPI SymRegisterFunctionEntryCallback64(HANDLE hProc,
PSYMBOL_FUNCENTRY_CALLBACK64 cb,
ULONG64 user)
{
FIXME("(%p %p %s): stub!\n", hProc, cb, wine_dbgstr_longlong(user));
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}

View file

@ -16,7 +16,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
@ -51,41 +51,46 @@ void pool_destroy(struct pool* pool)
#ifdef USE_STATS
unsigned alloc, used, num;
for (alloc = used = num = 0, arena = pool->first; arena; arena = arena->next)
alloc = used = num = 0;
arena = pool->first;
while (arena)
{
alloc += pool->arena_size;
used += arena->current - (char*)arena;
num++;
arena = arena->next;
}
if (alloc == 0) alloc = 1; /* avoid division by zero */
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)
arena = pool->first;
while (arena)
{
next = arena->next;
HeapFree(GetProcessHeap(), 0, arena);
arena = next;
}
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)
for (arena = pool->first; arena; arena = arena->next)
{
if ((char*)(*parena) + pool->arena_size - (*parena)->current >= len)
if ((char*)arena + pool->arena_size - arena->current >= len)
{
ret = (*parena)->current;
(*parena)->current += len;
ret = arena->current;
arena->current += len;
return ret;
}
}
@ -93,41 +98,13 @@ void* pool_alloc(struct pool* pool, unsigned len)
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->next = pool->first;
pool->first = arena;
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;
@ -155,6 +132,7 @@ void vector_init(struct vector* v, unsigned esz, unsigned bucket_sz)
default: assert(0);
}
v->num_buckets = 0;
v->buckets_allocated = 0;
v->num_elts = 0;
}
@ -180,49 +158,144 @@ void* vector_add(struct vector* v, struct pool* pool)
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*));
if(v->num_buckets == v->buckets_allocated)
{
/* Double the bucket cache, so it scales well with big vectors.*/
unsigned new_reserved;
void* new;
new_reserved = 2*v->buckets_allocated;
if(new_reserved == 0) new_reserved = 1;
/* Don't even try to resize memory.
Pool datastructure is very inefficient with reallocs. */
new = pool_alloc(pool, new_reserved * sizeof(void*));
memcpy(new, v->buckets, v->buckets_allocated * sizeof(void*));
v->buckets = new;
v->buckets_allocated = new_reserved;
}
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)
/* We construct the sparse array as two vectors (of equal size)
* The first vector (key2index) is the lookup table between the key and
* an index in the second vector (elements)
* When inserting an element, it's always appended in second vector (and
* never moved in memory later on), only the first vector is reordered
*/
struct key2index
{
int i;
unsigned long key;
unsigned index;
};
for (i = 0; i < v->num_buckets; i++)
void sparse_array_init(struct sparse_array* sa, unsigned elt_sz, unsigned bucket_sz)
{
vector_init(&sa->key2index, sizeof(struct key2index), bucket_sz);
vector_init(&sa->elements, elt_sz, bucket_sz);
}
/******************************************************************
* sparse_array_lookup
*
* Returns the first index which key is >= at passed key
*/
static struct key2index* sparse_array_lookup(const struct sparse_array* sa,
unsigned long key, unsigned* idx)
{
struct key2index* pk2i;
unsigned low, high;
if (!sa->elements.num_elts)
{
if (v->buckets[i] <= elt &&
(const char*)elt < (const char*)v->buckets[i] + (v->elt_size << v->shift))
*idx = 0;
return NULL;
}
high = sa->elements.num_elts;
pk2i = vector_at(&sa->key2index, high - 1);
if (pk2i->key < key)
{
*idx = high;
return NULL;
}
if (pk2i->key == key)
{
*idx = high - 1;
return pk2i;
}
low = 0;
pk2i = vector_at(&sa->key2index, low);
if (pk2i->key >= key)
{
*idx = 0;
return pk2i;
}
/* now we have: sa(lowest key) < key < sa(highest key) */
while (low < high)
{
*idx = (low + high) / 2;
pk2i = vector_at(&sa->key2index, *idx);
if (pk2i->key > key) high = *idx;
else if (pk2i->key < key) low = *idx + 1;
else return pk2i;
}
/* binary search could return exact item, we search for highest one
* below the key
*/
if (pk2i->key < key)
pk2i = vector_at(&sa->key2index, ++(*idx));
return pk2i;
}
void* sparse_array_find(const struct sparse_array* sa, unsigned long key)
{
unsigned idx;
struct key2index* pk2i;
if ((pk2i = sparse_array_lookup(sa, key, &idx)) && pk2i->key == key)
return vector_at(&sa->elements, pk2i->index);
return NULL;
}
void* sparse_array_add(struct sparse_array* sa, unsigned long key,
struct pool* pool)
{
unsigned idx, i;
struct key2index* pk2i;
struct key2index* to;
pk2i = sparse_array_lookup(sa, key, &idx);
if (pk2i && pk2i->key == key)
{
FIXME("re adding an existing key\n");
return NULL;
}
to = vector_add(&sa->key2index, pool);
if (pk2i)
{
/* we need to shift vector's content... */
/* let's do it brute force... (FIXME) */
assert(sa->key2index.num_elts >= 2);
for (i = sa->key2index.num_elts - 1; i > idx; i--)
{
return (i << v->shift) +
((const char*)elt - (const char*)v->buckets[i]) / v->elt_size;
pk2i = vector_at(&sa->key2index, i - 1);
*to = *pk2i;
to = pk2i;
}
}
assert(0);
return 0;
to->key = key;
to->index = sa->elements.num_elts;
return vector_add(&sa->elements, pool);
}
void* vector_iter_up(const struct vector* v, void* elt)
unsigned sparse_array_length(const struct sparse_array* sa)
{
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);
return sa->elements.num_elts;
}
unsigned hash_table_hash(const char* name, unsigned num_buckets)
@ -242,10 +315,10 @@ unsigned hash_table_hash(const char* name, unsigned 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_elts = 0;
ht->num_buckets = num_buckets;
memset(ht->buckets, 0, num_buckets * sizeof(struct hash_table_elt*));
ht->pool = pool;
ht->buckets = NULL;
}
void hash_table_destroy(struct hash_table* ht)
@ -253,7 +326,7 @@ 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;
unsigned min = 0xffffffff, max = 0, sq = 0;
struct hash_table_elt* elt;
double mean, variance;
@ -262,13 +335,12 @@ void hash_table_destroy(struct hash_table* ht)
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;
mean = (double)ht->num_elts / 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);
ht->num_elts, ht->num_buckets, mean, min, variance, max);
#if 1
for (i = 0; i < ht->num_buckets; i++)
{
@ -291,12 +363,20 @@ void hash_table_add(struct hash_table* ht, struct hash_table_elt* elt)
unsigned hash = hash_table_hash(elt->name, ht->num_buckets);
struct hash_table_elt** p;
if (!ht->buckets)
{
ht->buckets = pool_alloc(ht->pool, ht->num_buckets * sizeof(struct hash_table_elt*));
assert(ht->buckets);
memset(ht->buckets, 0, ht->num_buckets * sizeof(struct hash_table_elt*));
}
/* in some cases, we need to get back the symbols of same name in the order
* in which they've been inserted. So insert new elements at the end of the list.
*/
for (p = &ht->buckets[hash]; *p; p = &((*p)->next));
*p = elt;
elt->next = NULL;
ht->num_elts++;
}
void* hash_table_find(const struct hash_table* ht, const char* name)
@ -304,12 +384,14 @@ 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;
if(!ht->buckets) return NULL;
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,
void hash_table_iter_init(const struct hash_table* ht,
struct hash_table_iter* hti, const char* name)
{
hti->ht = ht;
@ -328,8 +410,10 @@ void hash_table_iter_init(const struct hash_table* ht,
void* hash_table_iter_up(struct hash_table_iter* hti)
{
if(!hti->ht->buckets) return NULL;
if (hti->element) hti->element = hti->element->next;
while (!hti->element && hti->index < hti->last)
while (!hti->element && hti->index < hti->last)
hti->element = hti->ht->buckets[++hti->index];
return hti->element;
}

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* Note: This really doesn't do much at the moment, but it forms the framework
* upon which full support for datatype handling will eventually be built.
@ -28,7 +28,6 @@
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winnls.h"
#include "wine/debug.h"
#include "dbghelp_private.h"
@ -100,8 +99,8 @@ const char* symt_get_name(const struct symt* sym)
}
}
static struct symt* symt_find_type_by_name(struct module* module,
enum SymTagEnum sym_tag,
static struct symt* symt_find_type_by_name(const struct module* module,
enum SymTagEnum sym_tag,
const char* typename)
{
void* ptr;
@ -132,7 +131,7 @@ static void symt_add_type(struct module* module, struct symt* symt)
*p = symt;
}
struct symt_basic* symt_new_basic(struct module* module, enum BasicType bt,
struct symt_basic* symt_new_basic(struct module* module, enum BasicType bt,
const char* typename, unsigned size)
{
struct symt_basic* sym;
@ -159,12 +158,13 @@ struct symt_basic* symt_new_basic(struct module* module, enum BasicType bt,
return sym;
}
struct symt_udt* symt_new_udt(struct module* module, const char* typename,
struct symt_udt* symt_new_udt(struct module* module, const char* typename,
unsigned size, enum UdtKind kind)
{
struct symt_udt* sym;
TRACE_(dbghelp_symt)("Adding udt %s:%s\n", module->module.ModuleName, typename);
TRACE_(dbghelp_symt)("Adding udt %s:%s\n",
debugstr_w(module->module.ModuleName), typename);
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagUDT;
@ -187,7 +187,7 @@ BOOL symt_set_udt_size(struct module* module, struct symt_udt* udt, unsigned siz
if (vector_length(&udt->vchildren) != 0)
{
if (udt->size != size)
FIXME_(dbghelp_symt)("Changing size for %s from %u to %u\n",
FIXME_(dbghelp_symt)("Changing size for %s from %u to %u\n",
udt->hash_elt.name, udt->size, size);
return TRUE;
}
@ -213,28 +213,30 @@ BOOL symt_add_udt_element(struct module* module, struct symt_udt* udt_type,
assert(udt_type->symt.tag == SymTagUDT);
TRACE_(dbghelp_symt)("Adding %s to UDT %s\n", name, udt_type->hash_elt.name);
p = NULL;
while ((p = vector_iter_up(&udt_type->vchildren, p)))
if (name)
{
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;
int i;
for (i=0; i<vector_length(&udt_type->vchildren); i++)
{
m = *(struct symt_data**)vector_at(&udt_type->vchildren, i);
assert(m);
assert(m->symt.tag == SymTagData);
if (strcmp(m->hash_elt.name, name) == 0)
return TRUE;
}
}
if ((m = pool_alloc(&module->pool, sizeof(*m))) == NULL) return FALSE;
memset(m, 0, sizeof(*m));
m->symt.tag = SymTagData;
m->hash_elt.name = pool_strdup(&module->pool, name);
m->hash_elt.name = name ? pool_strdup(&module->pool, name) : "";
m->hash_elt.next = NULL;
m->kind = DataIsMember;
m->container = &udt_type->symt;
m->type = elt_type;
m->u.s.offset = offset;
m->u.s.length = ((offset & 7) || (size & 7)) ? size : 0;
m->u.s.reg_id = 0;
m->kind = DataIsMember;
m->container = &udt_type->symt;
m->type = elt_type;
m->u.member.offset = offset;
m->u.member.length = ((offset & 7) || (size & 7)) ? size : 0;
p = vector_add(&udt_type->vchildren, &module->pool);
*p = &m->symt;
@ -281,24 +283,26 @@ BOOL symt_add_enum_element(struct module* module, struct symt_enum* enum_type,
return TRUE;
}
struct symt_array* symt_new_array(struct module* module, int min, int max,
struct symt* base)
struct symt_array* symt_new_array(struct module* module, int min, int max,
struct symt* base, struct symt* index)
{
struct symt_array* sym;
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagArrayType;
sym->start = min;
sym->end = max;
sym->basetype = base;
sym->symt.tag = SymTagArrayType;
sym->start = min;
sym->end = max;
sym->base_type = base;
sym->index_type = index;
symt_add_type(module, &sym->symt);
}
return sym;
}
struct symt_function_signature* symt_new_function_signature(struct module* module,
struct symt* ret_type)
struct symt_function_signature* symt_new_function_signature(struct module* module,
struct symt* ret_type,
enum CV_call_e call_conv)
{
struct symt_function_signature* sym;
@ -307,6 +311,7 @@ struct symt_function_signature* symt_new_function_signature(struct module* modul
sym->symt.tag = SymTagFunctionType;
sym->rettype = ret_type;
vector_init(&sym->vchildren, sizeof(struct symt*), 4);
sym->call_conv = call_conv;
symt_add_type(module, &sym->symt);
}
return sym;
@ -316,12 +321,18 @@ BOOL symt_add_function_signature_parameter(struct module* module,
struct symt_function_signature* sig_type,
struct symt* param)
{
struct symt** p;
struct symt** p;
struct symt_function_arg_type* arg;
assert(sig_type->symt.tag == SymTagFunctionType);
arg = pool_alloc(&module->pool, sizeof(*arg));
if (!arg) return FALSE;
arg->symt.tag = SymTagFunctionArgType;
arg->arg_type = param;
arg->container = &sig_type->symt;
p = vector_add(&sig_type->vchildren, &module->pool);
if (!p) return FALSE; /* FIXME we leak e */
*p = param;
if (!p) return FALSE; /* FIXME we leak arg */
*p = &arg->symt;
return TRUE;
}
@ -339,7 +350,7 @@ struct symt_pointer* symt_new_pointer(struct module* module, struct symt* ref_ty
return sym;
}
struct symt_typedef* symt_new_typedef(struct module* module, struct symt* ref,
struct symt_typedef* symt_new_typedef(struct module* module, struct symt* ref,
const char* name)
{
struct symt_typedef* sym;
@ -363,32 +374,33 @@ BOOL WINAPI SymEnumTypes(HANDLE hProcess, ULONG64 BaseOfDll,
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
PVOID UserContext)
{
struct process* pcs;
struct module* module;
struct module_pair pair;
char buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer;
const char* tmp;
struct symt* type;
void* pos = NULL;
DWORD64 size;
int i;
TRACE("(%p %s %p %p)\n",
hProcess, wine_dbgstr_longlong(BaseOfDll), EnumSymbolsCallback,
UserContext);
if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
if (!(module = module_get_debug(pcs, module))) return FALSE;
if (!(pair.pcs = process_find_by_handle(hProcess))) return FALSE;
pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN);
if (!module_get_debug(&pair)) return FALSE;
sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
while ((pos = vector_iter_up(&module->vtypes, pos)))
for (i=0; i<vector_length(&pair.effective->vtypes); i++)
{
type = *(struct symt**)pos;
type = *(struct symt**)vector_at(&pair.effective->vtypes, i);
sym_info->TypeIndex = (DWORD)type;
sym_info->info = 0; /* FIXME */
symt_get_info(type, TI_GET_LENGTH, &sym_info->Size);
sym_info->ModBase = module->module.BaseOfImage;
symt_get_info(type, TI_GET_LENGTH, &size);
sym_info->Size = size;
sym_info->ModBase = pair.requested->module.BaseOfImage;
sym_info->Flags = 0; /* FIXME */
sym_info->Value = 0; /* FIXME */
sym_info->Address = 0; /* FIXME */
@ -398,22 +410,55 @@ BOOL WINAPI SymEnumTypes(HANDLE hProcess, ULONG64 BaseOfDll,
tmp = symt_get_name(type);
if (tmp)
{
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';
sym_info->NameLen = min(strlen(tmp),sym_info->MaxNameLen-1);
memcpy(sym_info->Name, tmp, sym_info->NameLen);
sym_info->Name[sym_info->NameLen] = '\0';
}
else sym_info->Name[sym_info->NameLen = 0] = '\0';
else
sym_info->Name[sym_info->NameLen = 0] = '\0';
if (!EnumSymbolsCallback(sym_info, sym_info->Size, UserContext)) break;
}
return TRUE;
}
struct enum_types_AtoW
{
char buffer[sizeof(SYMBOL_INFOW) + 256 * sizeof(WCHAR)];
void* user;
PSYM_ENUMERATESYMBOLS_CALLBACKW callback;
};
BOOL CALLBACK enum_types_AtoW(PSYMBOL_INFO si, ULONG addr, PVOID _et)
{
struct enum_types_AtoW* et = _et;
SYMBOL_INFOW* siW = (SYMBOL_INFOW*)et->buffer;
copy_symbolW(siW, si);
return et->callback(siW, addr, et->user);
}
/******************************************************************
* SymEnumTypesW (DBGHELP.@)
*
*/
BOOL WINAPI SymEnumTypesW(HANDLE hProcess, ULONG64 BaseOfDll,
PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
PVOID UserContext)
{
struct enum_types_AtoW et;
et.callback = EnumSymbolsCallback;
et.user = UserContext;
return SymEnumTypes(hProcess, BaseOfDll, enum_types_AtoW, &et);
}
/******************************************************************
* symt_get_info
*
* Retrieves inforamtion about a symt (either symbol or type)
* Retrieves information about a symt (either symbol or type)
*/
BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
void* pInfo)
{
unsigned len;
@ -439,7 +484,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
case SymTagFunctionType: v = &((const struct symt_function_signature*)type)->vchildren; break;
case SymTagFunction: v = &((const struct symt_function*)type)->vchildren; break;
default:
FIXME("Unsupported sym-tag %s for find-children\n",
FIXME("Unsupported sym-tag %s for find-children\n",
symt_get_tag_str(type->tag));
return FALSE;
}
@ -459,7 +504,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
{
case DataIsGlobal:
case DataIsFileStatic:
X(ULONG64) = ((const struct symt_data*)type)->u.address;
X(ULONG64) = ((const struct symt_data*)type)->u.var.offset;
break;
default: return FALSE;
}
@ -473,14 +518,17 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:
case SymTagLabel:
X(ULONG64) = ((const struct symt_function_point*)type)->parent->address +
((const struct symt_function_point*)type)->offset;
X(ULONG64) = ((const struct symt_function_point*)type)->parent->address +
((const struct symt_function_point*)type)->loc.offset;
break;
case SymTagThunk:
X(ULONG64) = ((const struct symt_thunk*)type)->address;
break;
case SymTagCompiland:
X(ULONG64) = ((const struct symt_compiland*)type)->address;
break;
default:
FIXME("Unsupported sym-tag %s for get-address\n",
FIXME("Unsupported sym-tag %s for get-address\n",
symt_get_tag_str(type->tag));
return FALSE;
}
@ -501,11 +549,11 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
break;
case TI_GET_BITPOSITION:
if (type->tag != SymTagData ||
((const struct symt_data*)type)->kind != DataIsMember ||
((const struct symt_data*)type)->u.s.length == 0)
return FALSE;
X(DWORD) = ((const struct symt_data*)type)->u.s.offset & 7;
if (type->tag == SymTagData &&
((const struct symt_data*)type)->kind == DataIsMember &&
((const struct symt_data*)type)->u.member.length != 0)
X(DWORD) = ((const struct symt_data*)type)->u.member.offset & 7;
else return FALSE;
break;
case TI_GET_CHILDRENCOUNT:
@ -529,7 +577,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
X(DWORD) = 0;
break;
default:
FIXME("Unsupported sym-tag %s for get-children-count\n",
FIXME("Unsupported sym-tag %s for get-children-count\n",
symt_get_tag_str(type->tag));
/* fall through */
case SymTagData:
@ -540,13 +588,20 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
break;
case TI_GET_COUNT:
/* it seems that FunctionType also react to GET_COUNT (same value as
* GET_CHILDREN_COUNT ?, except for C++ methods, where it seems to
* also include 'this' (GET_CHILDREN_COUNT+1)
*/
if (type->tag != SymTagArrayType) return FALSE;
X(DWORD) = ((const struct symt_array*)type)->end -
((const struct symt_array*)type)->start + 1;
switch (type->tag)
{
case SymTagArrayType:
X(DWORD) = ((const struct symt_array*)type)->end -
((const struct symt_array*)type)->start + 1;
break;
case SymTagFunctionType:
/* this seems to be wrong for (future) C++ methods, where 'this' parameter
* should be included in this value (and not in GET_CHILDREN_COUNT)
*/
X(DWORD) = vector_length(&((const struct symt_function_signature*)type)->vchildren);
break;
default: return FALSE;
}
break;
case TI_GET_DATAKIND:
@ -558,44 +613,43 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
switch (type->tag)
{
case SymTagBaseType:
X(DWORD) = ((const struct symt_basic*)type)->size;
X(DWORD64) = ((const struct symt_basic*)type)->size;
break;
case SymTagFunction:
X(DWORD) = ((const struct symt_function*)type)->size;
X(DWORD64) = ((const struct symt_function*)type)->size;
break;
case SymTagPointerType:
X(DWORD) = sizeof(void*);
X(DWORD64) = sizeof(void*);
break;
case SymTagUDT:
X(DWORD) = ((const struct symt_udt*)type)->size;
X(DWORD64) = ((const struct symt_udt*)type)->size;
break;
case SymTagEnum:
X(DWORD) = sizeof(int); /* FIXME: should be size of base-type of enum !!! */
X(DWORD64) = sizeof(int); /* FIXME: should be size of base-type of enum !!! */
break;
case SymTagData:
if (((const struct symt_data*)type)->kind != DataIsMember ||
!((const struct symt_data*)type)->u.s.length)
!((const struct symt_data*)type)->u.member.length)
return FALSE;
X(DWORD) = ((const struct symt_data*)type)->u.s.length;
X(DWORD64) = ((const struct symt_data*)type)->u.member.length;
break;
case SymTagArrayType:
if (!symt_get_info(((const struct symt_array*)type)->basetype,
case SymTagArrayType:
if (!symt_get_info(((const struct symt_array*)type)->base_type,
TI_GET_LENGTH, pInfo))
return FALSE;
X(DWORD) *= ((const struct symt_array*)type)->end -
X(DWORD64) *= ((const struct symt_array*)type)->end -
((const struct symt_array*)type)->start + 1;
break;
case SymTagPublicSymbol:
X(DWORD) = ((const struct symt_public*)type)->size;
X(DWORD64) = ((const struct symt_public*)type)->size;
break;
case SymTagTypedef:
return symt_get_info(((const struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo);
break;
case SymTagThunk:
X(DWORD) = ((const struct symt_thunk*)type)->size;
X(DWORD64) = ((const struct symt_thunk*)type)->size;
break;
default:
FIXME("Unsupported sym-tag %s for get-length\n",
FIXME("Unsupported sym-tag %s for get-length\n",
symt_get_tag_str(type->tag));
/* fall through */
case SymTagFunctionType:
@ -618,8 +672,11 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
case SymTagThunk:
X(DWORD) = (DWORD)((const struct symt_thunk*)type)->container;
break;
case SymTagFunctionArgType:
X(DWORD) = (DWORD)((const struct symt_function_arg_type*)type)->container;
break;
default:
FIXME("Unsupported sym-tag %s for get-lexical-parent\n",
FIXME("Unsupported sym-tag %s for get-lexical-parent\n",
symt_get_tag_str(type->tag));
return FALSE;
}
@ -645,17 +702,19 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
{
case DataIsParam:
case DataIsLocal:
X(ULONG) = ((const struct symt_data*)type)->u.var.offset;
break;
case DataIsMember:
X(ULONG) = ((const struct symt_data*)type)->u.s.offset >> 3;
X(ULONG) = ((const struct symt_data*)type)->u.member.offset >> 3;
break;
default:
FIXME("Unknown kind (%u) for get-offset\n",
FIXME("Unknown kind (%u) for get-offset\n",
((const struct symt_data*)type)->kind);
return FALSE;
}
break;
default:
FIXME("Unsupported sym-tag %s for get-offset\n",
FIXME("Unsupported sym-tag %s for get-offset\n",
symt_get_tag_str(type->tag));
return FALSE;
}
@ -682,7 +741,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
{
/* hierarchical => hierarchical */
case SymTagArrayType:
X(DWORD) = (DWORD)((const struct symt_array*)type)->basetype;
X(DWORD) = (DWORD)((const struct symt_array*)type)->base_type;
break;
case SymTagPointerType:
X(DWORD) = (DWORD)((const struct symt_pointer*)type)->pointsto;
@ -695,15 +754,19 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
break;
/* lexical => hierarchical */
case SymTagData:
X(DWORD) = (DWORD)((const struct symt_data*)type)->type;
X(DWORD) = (DWORD)((const struct symt_data*)type)->type;
break;
case SymTagFunction:
X(DWORD) = (DWORD)((const struct symt_function*)type)->type;
break;
/* FIXME: should also work for enums and FunctionArgType */
/* FIXME: should also work for enums */
case SymTagFunctionArgType:
X(DWORD) = (DWORD)((const struct symt_function_arg_type*)type)->arg_type;
break;
default:
FIXME("Unsupported sym-tag %s for get-type\n",
FIXME("Unsupported sym-tag %s for get-type\n",
symt_get_tag_str(type->tag));
case SymTagPublicSymbol:
case SymTagThunk:
return FALSE;
}
@ -720,11 +783,23 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
X(VARIANT) = ((const struct symt_data*)type)->u.value;
break;
case TI_GET_CALLING_CONVENTION:
if (type->tag != SymTagFunctionType) return FALSE;
if (((const struct symt_function_signature*)type)->call_conv == -1)
{
FIXME("No support for calling convention for this signature\n");
X(DWORD) = CV_CALL_FAR_C; /* FIXME */
}
else X(DWORD) = ((const struct symt_function_signature*)type)->call_conv;
break;
case TI_GET_ARRAYINDEXTYPEID:
if (type->tag != SymTagArrayType) return FALSE;
X(DWORD) = (DWORD)((const struct symt_array*)type)->index_type;
break;
#undef X
case TI_GET_ADDRESSOFFSET:
case TI_GET_ARRAYINDEXTYPEID:
case TI_GET_CALLING_CONVENTION:
case TI_GET_CLASSPARENTID:
case TI_GET_SYMINDEX:
case TI_GET_THISADJUST:
@ -734,6 +809,9 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
case TI_IS_EQUIV_TO:
FIXME("Unsupported GetInfo request (%u)\n", req);
return FALSE;
default:
FIXME("Unknown GetInfo request (%u)\n", req);
return FALSE;
}
return TRUE;
@ -747,13 +825,13 @@ BOOL WINAPI SymGetTypeInfo(HANDLE hProcess, DWORD64 ModBase,
ULONG TypeId, IMAGEHLP_SYMBOL_TYPE_INFO GetType,
PVOID pInfo)
{
struct process* pcs = process_find_by_handle(hProcess);
struct module* module;
struct module_pair pair;
if (!pcs) return FALSE;
pair.pcs = process_find_by_handle(hProcess);
if (!pair.pcs) return FALSE;
module = module_find_by_addr(pcs, ModBase, DMT_UNKNOWN);
if (!(module = module_get_debug(pcs, module)))
pair.requested = module_find_by_addr(pair.pcs, ModBase, DMT_UNKNOWN);
if (!module_get_debug(&pair))
{
FIXME("Someone didn't properly set ModBase (%s)\n", wine_dbgstr_longlong(ModBase));
return FALSE;
@ -767,7 +845,7 @@ BOOL WINAPI SymGetTypeInfo(HANDLE hProcess, DWORD64 ModBase,
*
*/
BOOL WINAPI SymGetTypeFromName(HANDLE hProcess, ULONG64 BaseOfDll,
LPSTR Name, PSYMBOL_INFO Symbol)
PCSTR Name, PSYMBOL_INFO Symbol)
{
struct process* pcs = process_find_by_handle(hProcess);
struct module* module;

View file

@ -0,0 +1,63 @@
/*
* File wdbgexts.h: definition of windbg extensions
* (dbghelp.dll is seen as a windbg extension)
*
* Copyright (C) 2005, Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
typedef struct EXT_API_VERSION
{
USHORT MajorVersion;
USHORT MinorVersion;
USHORT Revision;
USHORT Reserved;
} EXT_API_VERSION, *LPEXT_API_VERSION;
typedef void (*PWINDBG_OUTPUT_ROUTINE)(PCSTR, ...);
typedef ULONG_PTR (WINAPI *PWINDBG_GET_EXPRESSION)(PCSTR);
typedef void (WINAPI *PWINDBG_GET_SYMBOL)(void*, char*, ULONG_PTR*);
typedef ULONG (WINAPI *PWINDBG_DISASM)(ULONG_PTR*, PCSTR, ULONG);
typedef ULONG (WINAPI *PWINDBG_CHECK_CONTROL_C)(void);
typedef ULONG (WINAPI *PWINDBG_READ_PROCESS_MEMORY_ROUTINE)(ULONG_PTR, void*, ULONG, PULONG);
typedef ULONG (WINAPI *PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE)(ULONG_PTR, const void*, ULONG, PULONG);
typedef ULONG (WINAPI *PWINDBG_GET_THREAD_CONTEXT_ROUTINE)(ULONG, PCONTEXT, ULONG);
typedef ULONG (WINAPI *PWINDBG_SET_THREAD_CONTEXT_ROUTINE)(ULONG, PCONTEXT, ULONG);
typedef ULONG (WINAPI *PWINDBG_IOCTL_ROUTINE)(USHORT, void*);
typedef struct _EXTSTACKTRACE
{
ULONG FramePointer;
ULONG ProgramCounter;
ULONG ReturnAddress;
ULONG Args[4];
} EXTSTACKTRACE, *PEXTSTACKTRACE;
typedef ULONG (WINAPI *PWINDBG_STACKTRACE_ROUTINE)(ULONG, ULONG, ULONG, PEXTSTACKTRACE, ULONG);
typedef struct _WINDBG_EXTENSION_APIS
{
ULONG nSize;
PWINDBG_OUTPUT_ROUTINE lpOutputRoutine;
PWINDBG_GET_EXPRESSION lpGetExpressionRoutine;
PWINDBG_GET_SYMBOL lpGetSymbolRoutine;
PWINDBG_DISASM lpDisasmRoutine;
PWINDBG_CHECK_CONTROL_C lpCheckControlCRoutine;
PWINDBG_READ_PROCESS_MEMORY_ROUTINE lpReadProcessMemoryRoutine;
PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE lpWriteProcessMemoryRoutine;
PWINDBG_GET_THREAD_CONTEXT_ROUTINE lpGetThreadContextRoutine;
PWINDBG_SET_THREAD_CONTEXT_ROUTINE lpSetThreadContextRoutine;
PWINDBG_IOCTL_ROUTINE lpIoctlRoutine;
PWINDBG_STACKTRACE_ROUTINE lpStackTraceRoutine;
} WINDBG_EXTENSION_APIS, *PWINDBG_EXTENSION_APIS;