mirror of
https://github.com/reactos/reactos.git
synced 2025-03-30 17:10:22 +00:00
sync dbghelp.dll to wine head. should fix build
svn path=/trunk/; revision=31339
This commit is contained in:
parent
fa17bda2ef
commit
929e7eeba5
25 changed files with 9130 additions and 4868 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
2227
reactos/dll/win32/dbghelp/dwarf.c
Normal file
2227
reactos/dll/win32/dbghelp/dwarf.c
Normal file
File diff suppressed because it is too large
Load diff
403
reactos/dll/win32/dbghelp/dwarf.h
Normal file
403
reactos/dll/win32/dbghelp/dwarf.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
*/
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
|
|
63
reactos/dll/win32/dbghelp/wdbgexts.h
Normal file
63
reactos/dll/win32/dbghelp/wdbgexts.h
Normal 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;
|
Loading…
Reference in a new issue