mirror of
https://github.com/reactos/reactos.git
synced 2024-12-30 19:14:31 +00:00
[DBGHELP]
sync dbghelp with wine 1.1.40 svn path=/trunk/; revision=46212
This commit is contained in:
parent
48cc443d59
commit
920b13160c
27 changed files with 4128 additions and 1479 deletions
|
@ -108,12 +108,18 @@ static int coff_add_file(struct CoffFileSet* coff_files, struct module* module,
|
|||
|
||||
if (coff_files->nfiles + 1 >= coff_files->nfiles_alloc)
|
||||
{
|
||||
coff_files->nfiles_alloc += 10;
|
||||
coff_files->files = (coff_files->files) ?
|
||||
HeapReAlloc(GetProcessHeap(), 0, coff_files->files,
|
||||
coff_files->nfiles_alloc * sizeof(struct CoffFile)) :
|
||||
HeapAlloc(GetProcessHeap(), 0,
|
||||
coff_files->nfiles_alloc * sizeof(struct CoffFile));
|
||||
if (coff_files->files)
|
||||
{
|
||||
coff_files->nfiles_alloc *= 2;
|
||||
coff_files->files = HeapReAlloc(GetProcessHeap(), 0, coff_files->files,
|
||||
coff_files->nfiles_alloc * sizeof(struct CoffFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
coff_files->nfiles_alloc = 16;
|
||||
coff_files->files = HeapAlloc(GetProcessHeap(), 0,
|
||||
coff_files->nfiles_alloc * sizeof(struct CoffFile));
|
||||
}
|
||||
}
|
||||
file = coff_files->files + coff_files->nfiles;
|
||||
file->startaddr = 0xffffffff;
|
||||
|
@ -132,7 +138,7 @@ static void coff_add_symbol(struct CoffFile* coff_file, struct symt* sym)
|
|||
{
|
||||
if (coff_file->neps + 1 >= coff_file->neps_alloc)
|
||||
{
|
||||
coff_file->neps_alloc += 10;
|
||||
coff_file->neps_alloc *= 2;
|
||||
coff_file->entries = (coff_file->entries) ?
|
||||
HeapReAlloc(GetProcessHeap(), 0, coff_file->entries,
|
||||
coff_file->neps_alloc * sizeof(struct symt*)) :
|
||||
|
@ -389,6 +395,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
|
|||
{
|
||||
if (coff_files.files[j].entries != NULL)
|
||||
{
|
||||
symt_cmp_addr_module = msc_dbg->module;
|
||||
qsort(coff_files.files[j].entries, coff_files.files[j].neps,
|
||||
sizeof(struct symt*), symt_cmp_addr);
|
||||
}
|
||||
|
@ -413,7 +420,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
|
|||
for (;;)
|
||||
{
|
||||
if (l+1 >= coff_files.files[j].neps) break;
|
||||
symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
|
||||
symt_get_info(msc_dbg->module, coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
|
||||
if (((msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress) < addr))
|
||||
break;
|
||||
l++;
|
||||
|
@ -426,7 +433,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
|
|||
* start of the function, so we need to subtract that offset
|
||||
* first.
|
||||
*/
|
||||
symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
|
||||
symt_get_info(msc_dbg->module, 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],
|
||||
coff_files.files[j].compiland->source, linepnt->Linenumber,
|
||||
msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr);
|
||||
|
|
412
reactos/dll/win32/dbghelp/cpu_i386.c
Normal file
412
reactos/dll/win32/dbghelp/cpu_i386.c
Normal file
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
* File cpu_i386.c
|
||||
*
|
||||
* Copyright (C) 2009-2009, 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
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "dbghelp_private.h"
|
||||
#include "wine/winbase16.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
#define STEP_FLAG 0x00000100 /* single step flag */
|
||||
#define V86_FLAG 0x00020000
|
||||
|
||||
#define IS_VM86_MODE(ctx) (ctx->EFlags & V86_FLAG)
|
||||
|
||||
#ifdef __i386__
|
||||
static ADDRESS_MODE get_selector_type(HANDLE hThread, const CONTEXT* ctx, WORD sel)
|
||||
{
|
||||
LDT_ENTRY le;
|
||||
|
||||
if (IS_VM86_MODE(ctx)) return AddrModeReal;
|
||||
/* null or system selector */
|
||||
if (!(sel & 4) || ((sel >> 3) < 17)) return AddrModeFlat;
|
||||
if (hThread && GetThreadSelectorEntry(hThread, sel, &le))
|
||||
return le.HighWord.Bits.Default_Big ? AddrMode1632 : AddrMode1616;
|
||||
/* selector doesn't exist */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned i386_build_addr(HANDLE hThread, const CONTEXT* ctx, ADDRESS64* addr,
|
||||
unsigned seg, unsigned long offset)
|
||||
{
|
||||
addr->Mode = AddrModeFlat;
|
||||
addr->Segment = seg;
|
||||
addr->Offset = offset;
|
||||
if (seg)
|
||||
{
|
||||
switch (addr->Mode = get_selector_type(hThread, ctx, seg))
|
||||
{
|
||||
case AddrModeReal:
|
||||
case AddrMode1616:
|
||||
addr->Offset &= 0xffff;
|
||||
break;
|
||||
case AddrModeFlat:
|
||||
case AddrMode1632:
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned i386_get_addr(HANDLE hThread, const CONTEXT* ctx,
|
||||
enum cpu_addr ca, ADDRESS64* addr)
|
||||
{
|
||||
#ifdef __i386__
|
||||
switch (ca)
|
||||
{
|
||||
case cpu_addr_pc: return i386_build_addr(hThread, ctx, addr, ctx->SegCs, ctx->Eip);
|
||||
case cpu_addr_stack: return i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Esp);
|
||||
case cpu_addr_frame: return i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Ebp);
|
||||
}
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done};
|
||||
|
||||
/* indexes in Reserved array */
|
||||
#define __CurrentMode 0
|
||||
#define __CurrentSwitch 1
|
||||
#define __NextSwitch 2
|
||||
|
||||
#define curr_mode (frame->Reserved[__CurrentMode])
|
||||
#define curr_switch (frame->Reserved[__CurrentSwitch])
|
||||
#define next_switch (frame->Reserved[__NextSwitch])
|
||||
|
||||
static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame)
|
||||
{
|
||||
STACK32FRAME frame32;
|
||||
STACK16FRAME frame16;
|
||||
char ch;
|
||||
ADDRESS64 tmp;
|
||||
DWORD p;
|
||||
WORD val;
|
||||
BOOL do_switch;
|
||||
|
||||
/* sanity check */
|
||||
if (curr_mode >= stm_done) return FALSE;
|
||||
|
||||
TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%p nSwitch=%p\n",
|
||||
wine_dbgstr_addr(&frame->AddrPC),
|
||||
wine_dbgstr_addr(&frame->AddrFrame),
|
||||
wine_dbgstr_addr(&frame->AddrReturn),
|
||||
wine_dbgstr_addr(&frame->AddrStack),
|
||||
curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
|
||||
(void*)(DWORD_PTR)curr_switch, (void*)(DWORD_PTR)next_switch);
|
||||
|
||||
if (curr_mode == stm_start)
|
||||
{
|
||||
THREAD_BASIC_INFORMATION info;
|
||||
|
||||
if ((frame->AddrPC.Mode == AddrModeFlat) &&
|
||||
(frame->AddrFrame.Mode != AddrModeFlat))
|
||||
{
|
||||
WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n");
|
||||
goto done_err;
|
||||
}
|
||||
|
||||
/* Init done */
|
||||
curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ? stm_32bit : stm_16bit;
|
||||
|
||||
/* cur_switch holds address of WOW32Reserved field in TEB in debuggee
|
||||
* address space
|
||||
*/
|
||||
if (NtQueryInformationThread(csw->hThread, ThreadBasicInformation, &info,
|
||||
sizeof(info), NULL) == STATUS_SUCCESS)
|
||||
{
|
||||
curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved);
|
||||
if (!sw_read_mem(csw, curr_switch, &p, sizeof(p)))
|
||||
{
|
||||
WARN("Can't read TEB:WOW32Reserved\n");
|
||||
goto done_err;
|
||||
}
|
||||
next_switch = p;
|
||||
if (!next_switch) /* no 16-bit stack */
|
||||
{
|
||||
curr_switch = 0;
|
||||
}
|
||||
else if (curr_mode == stm_16bit)
|
||||
{
|
||||
if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32)))
|
||||
{
|
||||
WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)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(csw, sw_xlat_addr(csw, &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(csw, &tmp);
|
||||
if (!sw_read_mem(csw, p, &frame16, sizeof(frame16)))
|
||||
{
|
||||
WARN("Bad stack frame 0x%08x\n", p);
|
||||
goto done_err;
|
||||
}
|
||||
curr_switch = (DWORD_PTR)frame16.frame32;
|
||||
|
||||
if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch)))
|
||||
curr_switch = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* 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
|
||||
{
|
||||
if (frame->AddrFrame.Offset == 0) goto done_err;
|
||||
if (frame->AddrFrame.Mode == AddrModeFlat)
|
||||
{
|
||||
assert(curr_mode == stm_32bit);
|
||||
do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(curr_mode == stm_16bit);
|
||||
do_switch = curr_switch &&
|
||||
frame->AddrFrame.Segment == SELECTOROF(curr_switch) &&
|
||||
frame->AddrFrame.Offset >= OFFSETOF(curr_switch);
|
||||
}
|
||||
|
||||
if (do_switch)
|
||||
{
|
||||
if (curr_mode == stm_16bit)
|
||||
{
|
||||
if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32)))
|
||||
{
|
||||
WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch);
|
||||
goto done_err;
|
||||
}
|
||||
|
||||
frame->AddrPC.Mode = AddrModeFlat;
|
||||
frame->AddrPC.Segment = 0;
|
||||
frame->AddrPC.Offset = frame32.retaddr;
|
||||
frame->AddrFrame.Mode = AddrModeFlat;
|
||||
frame->AddrFrame.Segment = 0;
|
||||
frame->AddrFrame.Offset = frame32.ebp;
|
||||
|
||||
frame->AddrStack.Mode = AddrModeFlat;
|
||||
frame->AddrStack.Segment = 0;
|
||||
frame->AddrReturn.Mode = AddrModeFlat;
|
||||
frame->AddrReturn.Segment = 0;
|
||||
|
||||
next_switch = curr_switch;
|
||||
tmp.Mode = AddrMode1616;
|
||||
tmp.Segment = SELECTOROF(next_switch);
|
||||
tmp.Offset = OFFSETOF(next_switch);
|
||||
p = sw_xlat_addr(csw, &tmp);
|
||||
|
||||
if (!sw_read_mem(csw, p, &frame16, sizeof(frame16)))
|
||||
{
|
||||
WARN("Bad stack frame 0x%08x\n", p);
|
||||
goto done_err;
|
||||
}
|
||||
curr_switch = (DWORD_PTR)frame16.frame32;
|
||||
curr_mode = stm_32bit;
|
||||
if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch)))
|
||||
curr_switch = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp.Mode = AddrMode1616;
|
||||
tmp.Segment = SELECTOROF(next_switch);
|
||||
tmp.Offset = OFFSETOF(next_switch);
|
||||
p = sw_xlat_addr(csw, &tmp);
|
||||
|
||||
if (!sw_read_mem(csw, p, &frame16, sizeof(frame16)))
|
||||
{
|
||||
WARN("Bad stack frame 0x%08x\n", p);
|
||||
goto done_err;
|
||||
}
|
||||
|
||||
TRACE("Got a 16 bit stack switch:"
|
||||
"\n\tframe32: %08lx"
|
||||
"\n\tedx:%08x ecx:%08x ebp:%08x"
|
||||
"\n\tds:%04x es:%04x fs:%04x gs:%04x"
|
||||
"\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,
|
||||
frame16.ds, frame16.es, frame16.fs, frame16.gs,
|
||||
frame16.callfrom_ip, frame16.module_cs, frame16.relay,
|
||||
frame16.entry_ip, frame16.entry_point,
|
||||
frame16.bp, frame16.ip, frame16.cs);
|
||||
|
||||
frame->AddrPC.Mode = AddrMode1616;
|
||||
frame->AddrPC.Segment = frame16.cs;
|
||||
frame->AddrPC.Offset = frame16.ip;
|
||||
|
||||
frame->AddrFrame.Mode = AddrMode1616;
|
||||
frame->AddrFrame.Segment = SELECTOROF(next_switch);
|
||||
frame->AddrFrame.Offset = frame16.bp;
|
||||
|
||||
frame->AddrStack.Mode = AddrMode1616;
|
||||
frame->AddrStack.Segment = SELECTOROF(next_switch);
|
||||
|
||||
frame->AddrReturn.Mode = AddrMode1616;
|
||||
frame->AddrReturn.Segment = frame16.cs;
|
||||
|
||||
next_switch = curr_switch;
|
||||
if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32)))
|
||||
{
|
||||
WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)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(csw, sw_xlat_addr(csw, &tmp), &ch, sizeof(ch)))
|
||||
curr_switch = 0;
|
||||
curr_mode = stm_16bit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frame->AddrPC = frame->AddrReturn;
|
||||
if (curr_mode == stm_16bit)
|
||||
{
|
||||
frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD);
|
||||
/* "pop up" previous BP value */
|
||||
if (!sw_read_mem(csw, sw_xlat_addr(csw, &frame->AddrFrame),
|
||||
&val, sizeof(WORD)))
|
||||
goto done_err;
|
||||
frame->AddrFrame.Offset = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD);
|
||||
/* "pop up" previous EBP value */
|
||||
if (!sw_read_mem(csw, frame->AddrFrame.Offset,
|
||||
&frame->AddrFrame.Offset, sizeof(DWORD)))
|
||||
goto done_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_mode == stm_16bit)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
p = sw_xlat_addr(csw, &frame->AddrFrame);
|
||||
if (!sw_read_mem(csw, p + sizeof(WORD), &val, sizeof(WORD)))
|
||||
goto done_err;
|
||||
frame->AddrReturn.Offset = val;
|
||||
/* get potential cs if a far call was used */
|
||||
if (!sw_read_mem(csw, 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,
|
||||
* but check whether it could be anyway
|
||||
*/
|
||||
if ((val & 7) == 7 && val != frame->AddrReturn.Segment)
|
||||
{
|
||||
LDT_ENTRY le;
|
||||
|
||||
if (GetThreadSelectorEntry(csw->hThread, val, &le) &&
|
||||
(le.HighWord.Bits.Type & 0x08)) /* code segment */
|
||||
{
|
||||
/* it is very uncommon to push a code segment cs as
|
||||
* a parameter, so this should work in most cases
|
||||
*/
|
||||
frame->AddrReturn.Segment = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
frame->AddrFrame.Offset &= ~1;
|
||||
/* we "pop" parameters as 16 bit entities... of course, this won't
|
||||
* work if the parameter is in fact bigger than 16bit, but
|
||||
* there's no way to know that here
|
||||
*/
|
||||
for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
|
||||
{
|
||||
sw_read_mem(csw, p + (2 + i) * sizeof(WORD), &val, sizeof(val));
|
||||
frame->Params[i] = val;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sw_read_mem(csw, frame->AddrFrame.Offset + sizeof(DWORD),
|
||||
&frame->AddrReturn.Offset, sizeof(DWORD)))
|
||||
{
|
||||
WARN("Cannot read new frame offset %p\n",
|
||||
(void*)(DWORD_PTR)(frame->AddrFrame.Offset + (int)sizeof(DWORD)));
|
||||
goto done_err;
|
||||
}
|
||||
sw_read_mem(csw, frame->AddrFrame.Offset + 2 * sizeof(DWORD),
|
||||
frame->Params, sizeof(frame->Params));
|
||||
}
|
||||
|
||||
frame->Far = TRUE;
|
||||
frame->Virtual = TRUE;
|
||||
p = sw_xlat_addr(csw, &frame->AddrPC);
|
||||
if (p && sw_module_base(csw, p))
|
||||
frame->FuncTableEntry = sw_table_access(csw, p);
|
||||
else
|
||||
frame->FuncTableEntry = NULL;
|
||||
|
||||
TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%p nSwitch=%p FuncTable=%p\n",
|
||||
wine_dbgstr_addr(&frame->AddrPC),
|
||||
wine_dbgstr_addr(&frame->AddrFrame),
|
||||
wine_dbgstr_addr(&frame->AddrReturn),
|
||||
wine_dbgstr_addr(&frame->AddrStack),
|
||||
curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
|
||||
(void*)(DWORD_PTR)curr_switch, (void*)(DWORD_PTR)next_switch, frame->FuncTableEntry);
|
||||
|
||||
return TRUE;
|
||||
done_err:
|
||||
curr_mode = stm_done;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct cpu cpu_i386 = {
|
||||
IMAGE_FILE_MACHINE_I386,
|
||||
4,
|
||||
i386_get_addr,
|
||||
i386_stack_walk,
|
||||
};
|
62
reactos/dll/win32/dbghelp/cpu_ppc.c
Normal file
62
reactos/dll/win32/dbghelp/cpu_ppc.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* File cpu_ppc.c
|
||||
*
|
||||
* Copyright (C) 2009-2009, 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
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "dbghelp_private.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
static unsigned ppc_get_addr(HANDLE hThread, const CONTEXT* ctx,
|
||||
enum cpu_addr ca, ADDRESS64* addr)
|
||||
{
|
||||
switch (ca)
|
||||
{
|
||||
#if defined(__powerpc__)
|
||||
case cpu_addr_pc:
|
||||
addr->Mode = AddrModeFlat;
|
||||
addr->Segment = 0; /* don't need segment */
|
||||
addr->Offset = ctx->Iar;
|
||||
return TRUE;
|
||||
#endif
|
||||
default:
|
||||
case cpu_addr_stack:
|
||||
case cpu_addr_frame:
|
||||
FIXME("not done\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL ppc_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame)
|
||||
{
|
||||
FIXME("not done\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct cpu cpu_ppc = {
|
||||
IMAGE_FILE_MACHINE_POWERPC,
|
||||
4,
|
||||
ppc_get_addr,
|
||||
ppc_stack_walk,
|
||||
};
|
132
reactos/dll/win32/dbghelp/cpu_x86_64.c
Normal file
132
reactos/dll/win32/dbghelp/cpu_x86_64.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* File cpu_x86_64.c
|
||||
*
|
||||
* Copyright (C) 2009-2009, 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
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "dbghelp_private.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
static unsigned x86_64_get_addr(HANDLE hThread, const CONTEXT* ctx,
|
||||
enum cpu_addr ca, ADDRESS64* addr)
|
||||
{
|
||||
addr->Mode = AddrModeFlat;
|
||||
switch (ca)
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
case cpu_addr_pc: addr->Segment = ctx->SegCs; addr->Offset = ctx->Rip; return TRUE;
|
||||
case cpu_addr_stack: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rsp; return TRUE;
|
||||
case cpu_addr_frame: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rbp; return TRUE;
|
||||
#endif
|
||||
default: addr->Mode = -1;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
enum st_mode {stm_start, stm_64bit, stm_done};
|
||||
|
||||
/* indexes in Reserved array */
|
||||
#define __CurrentMode 0
|
||||
#define __CurrentSwitch 1
|
||||
#define __NextSwitch 2
|
||||
|
||||
#define curr_mode (frame->Reserved[__CurrentMode])
|
||||
#define curr_switch (frame->Reserved[__CurrentSwitch])
|
||||
#define next_switch (frame->Reserved[__NextSwitch])
|
||||
|
||||
static BOOL x86_64_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame)
|
||||
{
|
||||
/* sanity check */
|
||||
if (curr_mode >= stm_done) return FALSE;
|
||||
assert(!csw->is32);
|
||||
|
||||
TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s\n",
|
||||
wine_dbgstr_addr(&frame->AddrPC),
|
||||
wine_dbgstr_addr(&frame->AddrFrame),
|
||||
wine_dbgstr_addr(&frame->AddrReturn),
|
||||
wine_dbgstr_addr(&frame->AddrStack),
|
||||
curr_mode == stm_start ? "start" : "64bit");
|
||||
|
||||
if (curr_mode == stm_start)
|
||||
{
|
||||
if ((frame->AddrPC.Mode == AddrModeFlat) &&
|
||||
(frame->AddrFrame.Mode != AddrModeFlat))
|
||||
{
|
||||
WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n");
|
||||
goto done_err;
|
||||
}
|
||||
|
||||
/* Init done */
|
||||
curr_mode = stm_64bit;
|
||||
curr_switch = 0;
|
||||
frame->AddrReturn.Mode = frame->AddrStack.Mode = 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
|
||||
{
|
||||
if (frame->AddrReturn.Offset == 0) goto done_err;
|
||||
frame->AddrPC = frame->AddrReturn;
|
||||
}
|
||||
|
||||
if (!sw_read_mem(csw, frame->AddrStack.Offset,
|
||||
&frame->AddrReturn.Offset, sizeof(DWORD64)))
|
||||
{
|
||||
WARN("Cannot read new frame offset %s\n",
|
||||
wine_dbgstr_longlong(frame->AddrFrame.Offset + sizeof(DWORD64)));
|
||||
goto done_err;
|
||||
}
|
||||
/* FIXME: simplistic stuff... need to handle both dwarf & PE stack information */
|
||||
frame->AddrStack.Offset += sizeof(DWORD64);
|
||||
memset(&frame->Params, 0, sizeof(frame->Params));
|
||||
|
||||
frame->Far = TRUE;
|
||||
frame->Virtual = TRUE;
|
||||
if (frame->AddrPC.Offset && sw_module_base(csw, frame->AddrPC.Offset))
|
||||
frame->FuncTableEntry = sw_table_access(csw, frame->AddrPC.Offset);
|
||||
else
|
||||
frame->FuncTableEntry = NULL;
|
||||
|
||||
TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s FuncTable=%p\n",
|
||||
wine_dbgstr_addr(&frame->AddrPC),
|
||||
wine_dbgstr_addr(&frame->AddrFrame),
|
||||
wine_dbgstr_addr(&frame->AddrReturn),
|
||||
wine_dbgstr_addr(&frame->AddrStack),
|
||||
curr_mode == stm_start ? "start" : "64bit",
|
||||
frame->FuncTableEntry);
|
||||
|
||||
return TRUE;
|
||||
done_err:
|
||||
curr_mode = stm_done;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct cpu cpu_x86_64 = {
|
||||
IMAGE_FILE_MACHINE_AMD64,
|
||||
8,
|
||||
x86_64_get_addr,
|
||||
x86_64_stack_walk,
|
||||
};
|
149
reactos/dll/win32/dbghelp/crc32.c
Normal file
149
reactos/dll/win32/dbghelp/crc32.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* File crc32.c - calculate CRC32 checksum of a file
|
||||
*
|
||||
* Copyright (C) 1996, Eric Youngdale.
|
||||
* 1999-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
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dbghelp_private.h"
|
||||
|
||||
/* Copyright (C) 1986 Gary S. Brown. Modified by Robert Shearman. You may use
|
||||
the following calc_crc32 code or tables extracted from it, as desired without
|
||||
restriction. */
|
||||
|
||||
/**********************************************************************\
|
||||
|* Demonstration program to compute the 32-bit CRC used as the frame *|
|
||||
|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *|
|
||||
|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *|
|
||||
|* protocol). The 32-bit FCS was added via the Federal Register, *|
|
||||
|* 1 June 1982, p.23798. I presume but don't know for certain that *|
|
||||
|* this polynomial is or will be included in CCITT V.41, which *|
|
||||
|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *|
|
||||
|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *|
|
||||
|* errors by a factor of 10^-5 over 16-bit FCS. *|
|
||||
\**********************************************************************/
|
||||
|
||||
/* First, the polynomial itself and its table of feedback terms. The */
|
||||
/* polynomial is */
|
||||
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
|
||||
/* Note that we take it "backwards" and put the highest-order term in */
|
||||
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
|
||||
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
|
||||
/* the MSB being 1. */
|
||||
|
||||
/* Note that the usual hardware shift register implementation, which */
|
||||
/* is what we're using (we're merely optimizing it by doing eight-bit */
|
||||
/* chunks at a time) shifts bits into the lowest-order term. In our */
|
||||
/* implementation, that means shifting towards the right. Why do we */
|
||||
/* do it this way? Because the calculated CRC must be transmitted in */
|
||||
/* order from highest-order term to lowest-order term. UARTs transmit */
|
||||
/* characters in order from LSB to MSB. By storing the CRC this way, */
|
||||
/* we hand it to the UART in the order low-byte to high-byte; the UART */
|
||||
/* sends each low-bit to hight-bit; and the result is transmission bit */
|
||||
/* by bit from highest- to lowest-order term without requiring any bit */
|
||||
/* shuffling on our part. Reception works similarly. */
|
||||
|
||||
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
|
||||
/* */
|
||||
/* 1. The table can be generated at runtime if desired; code to do so */
|
||||
/* is shown later. It might not be obvious, but the feedback */
|
||||
/* terms simply represent the results of eight shift/xor opera- */
|
||||
/* tions for all combinations of data and CRC register values. */
|
||||
/* */
|
||||
/* 2. The CRC accumulation logic is the same for all CRC polynomials, */
|
||||
/* be they sixteen or thirty-two bits wide. You simply choose the */
|
||||
/* appropriate table. Alternatively, because the table can be */
|
||||
/* generated at runtime, you can start by generating the table for */
|
||||
/* the polynomial in question and use exactly the same "updcrc", */
|
||||
/* if your application needn't simultaneously handle two CRC */
|
||||
/* polynomials. (Note, however, that XMODEM is strange.) */
|
||||
/* */
|
||||
/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */
|
||||
/* of course, 32-bit entries work OK if the high 16 bits are zero. */
|
||||
/* */
|
||||
/* 4. The values must be right-shifted by eight bits by the "updcrc" */
|
||||
/* logic; the shift must be unsigned (bring in zeroes). On some */
|
||||
/* hardware you could probably optimize the shift in assembler by */
|
||||
/* using byte-swap instructions. */
|
||||
|
||||
|
||||
DWORD calc_crc32(int fd)
|
||||
{
|
||||
#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
|
||||
static const DWORD crc_32_tab[] =
|
||||
{ /* CRC polynomial 0xedb88320 */
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
int i, r;
|
||||
unsigned char buffer[8192];
|
||||
DWORD crc = ~0;
|
||||
|
||||
_lseek(fd, 0, SEEK_SET);
|
||||
while ((r = _read(fd, buffer, sizeof(buffer))) > 0)
|
||||
{
|
||||
for (i = 0; i < r; i++) crc = UPDC32(buffer[i], crc);
|
||||
}
|
||||
return ~crc;
|
||||
#undef UPDC32
|
||||
}
|
|
@ -106,7 +106,7 @@ struct process* process_find_by_handle(HANDLE hProcess)
|
|||
*/
|
||||
BOOL validate_addr64(DWORD64 addr)
|
||||
{
|
||||
if (addr >> 32)
|
||||
if (sizeof(void*) == sizeof(int) && (addr >> 32))
|
||||
{
|
||||
FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr));
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
@ -133,6 +133,48 @@ void* fetch_buffer(struct process* pcs, unsigned size)
|
|||
return pcs->buffer;
|
||||
}
|
||||
|
||||
const char* wine_dbgstr_addr(const ADDRESS64* addr)
|
||||
{
|
||||
if (!addr) return "(null)";
|
||||
switch (addr->Mode)
|
||||
{
|
||||
case AddrModeFlat:
|
||||
return wine_dbg_sprintf("flat<%s>", wine_dbgstr_longlong(addr->Offset));
|
||||
case AddrMode1616:
|
||||
return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, (DWORD)addr->Offset);
|
||||
case AddrMode1632:
|
||||
return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, (DWORD)addr->Offset);
|
||||
case AddrModeReal:
|
||||
return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, (DWORD)addr->Offset);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
extern struct cpu cpu_i386, cpu_x86_64;
|
||||
|
||||
static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, NULL};
|
||||
struct cpu* dbghelp_current_cpu =
|
||||
#if defined(__i386__)
|
||||
&cpu_i386
|
||||
#elif defined(__x86_64__)
|
||||
&cpu_x86_64
|
||||
#else
|
||||
#error define support for your CPU
|
||||
#endif
|
||||
;
|
||||
|
||||
struct cpu* cpu_find(DWORD machine)
|
||||
{
|
||||
struct cpu** cpu;
|
||||
|
||||
for (cpu = dbghelp_cpus ; *cpu; cpu++)
|
||||
{
|
||||
if (cpu[0]->machine == machine) return cpu[0];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymSetSearchPathW (DBGHELP.@)
|
||||
*
|
||||
|
@ -211,16 +253,16 @@ BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
|
|||
* SymInitialize helper: loads in dbghelp all known (and loaded modules)
|
||||
* this assumes that hProcess is a handle on a valid process
|
||||
*/
|
||||
static BOOL WINAPI process_invade_cb(PCSTR name, ULONG base, ULONG size, PVOID user)
|
||||
static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user)
|
||||
{
|
||||
char tmp[MAX_PATH];
|
||||
WCHAR tmp[MAX_PATH];
|
||||
HANDLE hProcess = user;
|
||||
|
||||
if (!GetModuleFileNameExA(hProcess, (HMODULE)base,
|
||||
tmp, sizeof(tmp)))
|
||||
lstrcpynA(tmp, name, sizeof(tmp));
|
||||
if (!GetModuleFileNameExW(hProcess, (HMODULE)(DWORD_PTR)base,
|
||||
tmp, sizeof(tmp) / sizeof(WCHAR)))
|
||||
lstrcpynW(tmp, name, sizeof(tmp) / sizeof(WCHAR));
|
||||
|
||||
SymLoadModule(hProcess, 0, tmp, name, base, size);
|
||||
SymLoadModuleExW(hProcess, 0, tmp, name, base, size, NULL, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -232,7 +274,8 @@ 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);
|
||||
if (!elf_read_wine_loader_dbg_info(pcs))
|
||||
macho_read_wine_loader_dbg_info(pcs);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -325,8 +368,9 @@ BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeP
|
|||
if (check_live_target(pcs))
|
||||
{
|
||||
if (fInvadeProcess)
|
||||
EnumerateLoadedModules(hProcess, process_invade_cb, hProcess);
|
||||
EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess);
|
||||
elf_synchronize_module_list(pcs);
|
||||
macho_synchronize_module_list(pcs);
|
||||
}
|
||||
else if (fInvadeProcess)
|
||||
{
|
||||
|
@ -459,25 +503,25 @@ BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
|
|||
*/
|
||||
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;
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
void* data32;
|
||||
IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64;
|
||||
IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
switch (action)
|
||||
{
|
||||
case CBA_DEBUG_INFO:
|
||||
case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
|
||||
case CBA_SET_OPTIONS:
|
||||
case CBA_SYMBOLS_UNLOADED:
|
||||
data32 = (void*)(DWORD)data;
|
||||
data32 = (void*)(DWORD_PTR)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;
|
||||
idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data;
|
||||
if (!validate_addr64(idsl64->BaseOfImage))
|
||||
return FALSE;
|
||||
idsl.SizeOfStruct = sizeof(idsl);
|
||||
|
@ -495,7 +539,7 @@ static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, U
|
|||
FIXME("No mapping for action %u\n", action);
|
||||
return FALSE;
|
||||
}
|
||||
return cb32(hProcess, action, data32, (PVOID)user32);
|
||||
return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
@ -522,7 +566,7 @@ BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
|
|||
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;
|
||||
idslW = data;
|
||||
idsl.SizeOfStruct = sizeof(idsl);
|
||||
idsl.BaseOfImage = idslW->BaseOfImage;
|
||||
idsl.CheckSum = idslW->CheckSum;
|
||||
|
@ -548,14 +592,16 @@ BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
|
|||
*
|
||||
* Helper for registering a callback.
|
||||
*/
|
||||
static BOOL sym_register_cb(HANDLE hProcess,
|
||||
static BOOL sym_register_cb(HANDLE hProcess,
|
||||
PSYMBOL_REGISTERED_CALLBACK64 cb,
|
||||
PSYMBOL_REGISTERED_CALLBACK cb32,
|
||||
DWORD64 user, BOOL unicode)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
pcs->reg_cb = cb;
|
||||
pcs->reg_cb32 = cb32;
|
||||
pcs->reg_is_unicode = unicode;
|
||||
pcs->reg_user = user;
|
||||
|
||||
|
@ -569,10 +615,9 @@ BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
|
|||
PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
|
||||
PVOID UserContext)
|
||||
{
|
||||
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);
|
||||
return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -584,7 +629,7 @@ BOOL WINAPI SymRegisterCallback64(HANDLE hProcess,
|
|||
{
|
||||
TRACE("(%p, %p, %s)\n",
|
||||
hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
|
||||
return sym_register_cb(hProcess, CallbackFunction, UserContext, FALSE);
|
||||
return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -596,7 +641,7 @@ BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess,
|
|||
{
|
||||
TRACE("(%p, %p, %s)\n",
|
||||
hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
|
||||
return sym_register_cb(hProcess, CallbackFunction, UserContext, TRUE);
|
||||
return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE);
|
||||
}
|
||||
|
||||
/* This is imagehlp version not dbghelp !! */
|
||||
|
|
|
@ -9,10 +9,15 @@
|
|||
<define name="_WINE" />
|
||||
<define name="HAVE_REGEX_H" />
|
||||
<file>coff.c</file>
|
||||
<file>cpu_i386.c</file>
|
||||
<file>cpu_ppc.c</file>
|
||||
<file>cpu_x86_64.c</file>
|
||||
<file>crc32.c</file>
|
||||
<file>dbghelp.c</file>
|
||||
<file>dwarf.c</file>
|
||||
<file>elf_module.c</file>
|
||||
<file>image.c</file>
|
||||
<file>macho_module.c</file>
|
||||
<file>memory.c</file>
|
||||
<file>minidump.c</file>
|
||||
<file>module.c</file>
|
||||
|
@ -27,6 +32,7 @@
|
|||
<file>storage.c</file>
|
||||
<file>symbol.c</file>
|
||||
<file>type.c</file>
|
||||
<file>version.rc</file>
|
||||
<library>wine</library>
|
||||
<library>psapi</library>
|
||||
<library>version</library>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "objbase.h"
|
||||
#include "oaidl.h"
|
||||
#include "winnls.h"
|
||||
#include "wine/list.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
#include "cvconst.h"
|
||||
|
@ -37,13 +38,14 @@
|
|||
|
||||
struct pool /* poor's man */
|
||||
{
|
||||
struct pool_arena* first;
|
||||
unsigned arena_size;
|
||||
struct list arena_list;
|
||||
struct list arena_full;
|
||||
size_t arena_size;
|
||||
};
|
||||
|
||||
void pool_init(struct pool* a, unsigned arena_size);
|
||||
void pool_init(struct pool* a, size_t arena_size);
|
||||
void pool_destroy(struct pool* a);
|
||||
void* pool_alloc(struct pool* a, unsigned len);
|
||||
void* pool_alloc(struct pool* a, size_t len);
|
||||
char* pool_strdup(struct pool* a, const char* str);
|
||||
|
||||
struct vector
|
||||
|
@ -96,7 +98,6 @@ void hash_table_init(struct pool* pool, struct hash_table* ht,
|
|||
unsigned num_buckets);
|
||||
void hash_table_destroy(struct hash_table* ht);
|
||||
void hash_table_add(struct hash_table* ht, struct hash_table_elt* elt);
|
||||
unsigned hash_table_hash(const char* name, unsigned num_buckets);
|
||||
|
||||
struct hash_table_iter
|
||||
{
|
||||
|
@ -116,7 +117,7 @@ void* hash_table_iter_up(struct hash_table_iter* hti);
|
|||
|
||||
extern unsigned dbghelp_options;
|
||||
/* some more Wine extensions */
|
||||
#define SYMOPT_WINE_WITH_ELF_MODULES 0x40000000
|
||||
#define SYMOPT_WINE_WITH_NATIVE_MODULES 0x40000000
|
||||
|
||||
enum location_kind {loc_error, /* reg is the error code */
|
||||
loc_absolute, /* offset is the location */
|
||||
|
@ -226,8 +227,6 @@ struct symt_public
|
|||
struct symt* container; /* compiland */
|
||||
unsigned long address;
|
||||
unsigned long size;
|
||||
unsigned in_code : 1,
|
||||
is_function : 1;
|
||||
};
|
||||
|
||||
struct symt_thunk
|
||||
|
@ -245,7 +244,7 @@ struct symt_array
|
|||
{
|
||||
struct symt symt;
|
||||
int start;
|
||||
int end;
|
||||
int end; /* end index if > 0, or -array_len (in bytes) if < 0 */
|
||||
struct symt* base_type;
|
||||
struct symt* index_type;
|
||||
};
|
||||
|
@ -308,6 +307,7 @@ 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_MACHO, /* a real Mach-O shared module */
|
||||
DMT_PDB, /* .PDB file */
|
||||
DMT_DBG, /* .DBG file */
|
||||
};
|
||||
|
@ -327,12 +327,17 @@ struct module
|
|||
struct elf_module_info* elf_info;
|
||||
struct dwarf2_module_info_s*dwarf2_info;
|
||||
|
||||
struct macho_module_info* macho_info;
|
||||
|
||||
/* memory allocation pool */
|
||||
struct pool pool;
|
||||
|
||||
/* symbols & symbol tables */
|
||||
struct vector vsymt;
|
||||
int sortlist_valid;
|
||||
unsigned num_sorttab; /* number of symbols with addresses */
|
||||
unsigned num_symbols;
|
||||
unsigned sorttab_size;
|
||||
struct symt_ht** addr_sorttab;
|
||||
struct hash_table ht_symbols;
|
||||
void (*loc_compute)(struct process* pcs,
|
||||
|
@ -355,8 +360,9 @@ struct process
|
|||
struct process* next;
|
||||
HANDLE handle;
|
||||
WCHAR* search_path;
|
||||
|
||||
|
||||
PSYMBOL_REGISTERED_CALLBACK64 reg_cb;
|
||||
PSYMBOL_REGISTERED_CALLBACK reg_cb32;
|
||||
BOOL reg_is_unicode;
|
||||
DWORD64 reg_user;
|
||||
|
||||
|
@ -411,17 +417,62 @@ struct pdb_lookup
|
|||
} u;
|
||||
};
|
||||
|
||||
struct cpu_stack_walk
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
enum cpu_addr {cpu_addr_pc, cpu_addr_stack, cpu_addr_frame};
|
||||
struct cpu
|
||||
{
|
||||
DWORD machine;
|
||||
DWORD word_size;
|
||||
/* address manipulation */
|
||||
unsigned (*get_addr)(HANDLE hThread, const CONTEXT* ctx,
|
||||
enum cpu_addr, ADDRESS64* addr);
|
||||
|
||||
/* stack manipulation */
|
||||
BOOL (*stack_walk)(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame);
|
||||
};
|
||||
|
||||
extern struct cpu* dbghelp_current_cpu;
|
||||
|
||||
/* 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);
|
||||
extern const char* wine_dbgstr_addr(const ADDRESS64* addr);
|
||||
extern struct cpu* cpu_find(DWORD);
|
||||
|
||||
/* crc32.c */
|
||||
extern DWORD calc_crc32(int fd);
|
||||
|
||||
typedef BOOL (*enum_modules_cb)(const WCHAR*, unsigned long addr, void* user);
|
||||
|
||||
/* elf_module.c */
|
||||
#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*);
|
||||
#define ELF_NO_MAP ((const void*)-1)
|
||||
extern BOOL elf_enum_modules(HANDLE hProc, 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);
|
||||
|
@ -431,21 +482,27 @@ 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);
|
||||
|
||||
/* macho_module.c */
|
||||
#define MACHO_NO_MAP ((const void*)-1)
|
||||
extern BOOL macho_enum_modules(HANDLE hProc, enum_modules_cb, void*);
|
||||
extern BOOL macho_fetch_file_info(const WCHAR* name, DWORD* base, DWORD* size, DWORD* checksum);
|
||||
struct macho_file_map;
|
||||
extern BOOL macho_load_debug_info(struct module* module, struct macho_file_map* fmap);
|
||||
extern struct module*
|
||||
macho_load_module(struct process* pcs, const WCHAR* name, unsigned long);
|
||||
extern BOOL macho_read_wine_loader_dbg_info(struct process* pcs);
|
||||
extern BOOL macho_synchronize_module_list(struct process* pcs);
|
||||
|
||||
/* 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_WineW[];
|
||||
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 WCHAR* name);
|
||||
extern struct module*
|
||||
module_find_by_nameA(const struct process* pcs,
|
||||
const char* name);
|
||||
|
@ -456,11 +513,8 @@ 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,
|
||||
DWORD64 addr, DWORD64 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);
|
||||
|
@ -485,13 +539,13 @@ extern BOOL path_find_symbol_file(const struct process* pcs, PCSTR full_
|
|||
BOOL* is_unmatched);
|
||||
|
||||
/* pe_module.c */
|
||||
extern BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth);
|
||||
extern BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth);
|
||||
extern struct module*
|
||||
pe_load_native_module(struct process* pcs, const WCHAR* name,
|
||||
HANDLE hFile, DWORD base, DWORD size);
|
||||
extern struct module*
|
||||
pe_load_builtin_module(struct process* pcs, const WCHAR* name,
|
||||
DWORD base, DWORD size);
|
||||
DWORD64 base, DWORD64 size);
|
||||
extern BOOL pe_load_debug_info(const struct process* pcs,
|
||||
struct module* module);
|
||||
/* source.c */
|
||||
|
@ -499,9 +553,14 @@ extern unsigned source_new(struct module* module, const char* basedir, const
|
|||
extern const char* source_get(const struct module* module, unsigned idx);
|
||||
|
||||
/* stabs.c */
|
||||
typedef void (*stabs_def_cb)(struct module* module, unsigned long load_offset,
|
||||
const char* name, unsigned long offset,
|
||||
BOOL is_public, BOOL is_global, unsigned char other,
|
||||
struct symt_compiland* compiland, void* user);
|
||||
extern BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
||||
const void* stabs, int stablen,
|
||||
const char* strs, int strtablen);
|
||||
const char* strs, int strtablen,
|
||||
stabs_def_cb callback, void* user);
|
||||
|
||||
/* dwarf.c */
|
||||
extern BOOL dwarf2_parse(struct module* module, unsigned long load_offset,
|
||||
|
@ -512,12 +571,19 @@ extern BOOL dwarf2_parse(struct module* module, unsigned long load_offse
|
|||
const unsigned char* line, unsigned int line_size,
|
||||
const unsigned char* loclist, unsigned int loclist_size);
|
||||
|
||||
/* stack.c */
|
||||
extern BOOL sw_read_mem(struct cpu_stack_walk* csw, DWORD64 addr, void* ptr, DWORD sz);
|
||||
extern DWORD64 sw_xlat_addr(struct cpu_stack_walk* csw, ADDRESS64* addr);
|
||||
extern void* sw_table_access(struct cpu_stack_walk* csw, DWORD64 addr);
|
||||
extern DWORD64 sw_module_base(struct cpu_stack_walk* csw, DWORD64 addr);
|
||||
|
||||
/* symbol.c */
|
||||
extern const char* symt_get_name(const struct symt* sym);
|
||||
extern struct module* symt_cmp_addr_module;
|
||||
extern int symt_cmp_addr(const void* p1, const void* p2);
|
||||
extern void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si);
|
||||
extern struct symt_ht*
|
||||
symt_find_nearest(struct module* module, DWORD addr);
|
||||
symt_find_nearest(struct module* module, DWORD_PTR addr);
|
||||
extern struct symt_compiland*
|
||||
symt_new_compiland(struct module* module, unsigned long address,
|
||||
unsigned src_idx);
|
||||
|
@ -525,8 +591,7 @@ extern struct symt_public*
|
|||
symt_new_public(struct module* module,
|
||||
struct symt_compiland* parent,
|
||||
const char* typename,
|
||||
unsigned long address, unsigned size,
|
||||
BOOL in_code, BOOL is_func);
|
||||
unsigned long address, unsigned size);
|
||||
extern struct symt_data*
|
||||
symt_new_global_variable(struct module* module,
|
||||
struct symt_compiland* parent,
|
||||
|
@ -540,7 +605,7 @@ extern struct symt_function*
|
|||
unsigned long addr, unsigned long size,
|
||||
struct symt* type);
|
||||
extern BOOL symt_normalize_function(struct module* module,
|
||||
struct symt_function* func);
|
||||
const struct symt_function* func);
|
||||
extern void symt_add_func_line(struct module* module,
|
||||
struct symt_function* func,
|
||||
unsigned source_idx, int line_num,
|
||||
|
@ -558,7 +623,7 @@ extern struct symt_block*
|
|||
unsigned pc, unsigned len);
|
||||
extern struct symt_block*
|
||||
symt_close_func_block(struct module* module,
|
||||
struct symt_function* func,
|
||||
const struct symt_function* func,
|
||||
struct symt_block* block, unsigned pc);
|
||||
extern struct symt_hierarchy_point*
|
||||
symt_add_function_point(struct module* module,
|
||||
|
@ -568,8 +633,8 @@ extern struct symt_hierarchy_point*
|
|||
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(const struct module* module, PIMAGEHLP_LINE line);
|
||||
DWORD64 addr, IMAGEHLP_LINE64* line);
|
||||
extern BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE64 line);
|
||||
extern struct symt_thunk*
|
||||
symt_new_thunk(struct module* module,
|
||||
struct symt_compiland* parent,
|
||||
|
@ -584,10 +649,12 @@ extern struct symt_hierarchy_point*
|
|||
symt_new_label(struct module* module,
|
||||
struct symt_compiland* compiland,
|
||||
const char* name, unsigned long address);
|
||||
extern struct symt* symt_index2ptr(struct module* module, DWORD id);
|
||||
extern DWORD symt_ptr2index(struct module* module, const struct symt* sym);
|
||||
|
||||
/* type.c */
|
||||
extern void symt_init_basic(struct module* module);
|
||||
extern BOOL symt_get_info(const struct symt* type,
|
||||
extern BOOL symt_get_info(struct module* module, const struct symt* type,
|
||||
IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo);
|
||||
extern struct symt_basic*
|
||||
symt_new_basic(struct module* module, enum BasicType,
|
||||
|
|
|
@ -72,7 +72,7 @@ static void dump(const void* ptr, unsigned len)
|
|||
int i, j;
|
||||
BYTE msg[128];
|
||||
static const char hexof[] = "0123456789abcdef";
|
||||
const BYTE* x = (const BYTE*)ptr;
|
||||
const BYTE* x = ptr;
|
||||
|
||||
for (i = 0; i < len; i += 16)
|
||||
{
|
||||
|
@ -217,7 +217,7 @@ static unsigned char dwarf2_parse_byte(dwarf2_traverse_context_t* ctx)
|
|||
|
||||
static unsigned short dwarf2_get_u2(const unsigned char* ptr)
|
||||
{
|
||||
return *(const unsigned short*)ptr;
|
||||
return *(const UINT16*)ptr;
|
||||
}
|
||||
|
||||
static unsigned short dwarf2_parse_u2(dwarf2_traverse_context_t* ctx)
|
||||
|
@ -229,7 +229,7 @@ static unsigned short dwarf2_parse_u2(dwarf2_traverse_context_t* ctx)
|
|||
|
||||
static unsigned long dwarf2_get_u4(const unsigned char* ptr)
|
||||
{
|
||||
return *(const unsigned long*)ptr;
|
||||
return *(const UINT32*)ptr;
|
||||
}
|
||||
|
||||
static unsigned long dwarf2_parse_u4(dwarf2_traverse_context_t* ctx)
|
||||
|
@ -239,6 +239,18 @@ static unsigned long dwarf2_parse_u4(dwarf2_traverse_context_t* ctx)
|
|||
return uvalue;
|
||||
}
|
||||
|
||||
static DWORD64 dwarf2_get_u8(const unsigned char* ptr)
|
||||
{
|
||||
return *(const UINT64*)ptr;
|
||||
}
|
||||
|
||||
static DWORD64 dwarf2_parse_u8(dwarf2_traverse_context_t* ctx)
|
||||
{
|
||||
DWORD64 uvalue = dwarf2_get_u8(ctx->data);
|
||||
ctx->data += 8;
|
||||
return uvalue;
|
||||
}
|
||||
|
||||
static unsigned long dwarf2_get_leb128_as_unsigned(const unsigned char* ptr, const unsigned char** end)
|
||||
{
|
||||
unsigned long ret = 0;
|
||||
|
@ -309,6 +321,13 @@ static unsigned dwarf2_leb128_length(const dwarf2_traverse_context_t* ctx)
|
|||
return ret + 1;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* dwarf2_get_addr
|
||||
*
|
||||
* Returns an address.
|
||||
* We assume that in all cases word size from Dwarf matches the size of
|
||||
* addresses in platform where the exec is compiled.
|
||||
*/
|
||||
static unsigned long dwarf2_get_addr(const unsigned char* ptr, unsigned word_size)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
@ -318,6 +337,9 @@ static unsigned long dwarf2_get_addr(const unsigned char* ptr, unsigned word_siz
|
|||
case 4:
|
||||
ret = dwarf2_get_u4(ptr);
|
||||
break;
|
||||
case 8:
|
||||
ret = dwarf2_get_u8(ptr);
|
||||
break;
|
||||
default:
|
||||
FIXME("Unsupported Word Size %u\n", word_size);
|
||||
ret = 0;
|
||||
|
@ -490,7 +512,9 @@ static void dwarf2_fill_attr(const dwarf2_parse_context_t* ctx,
|
|||
break;
|
||||
|
||||
case DW_FORM_data8:
|
||||
FIXME("Unhandled 64bits support\n");
|
||||
attr->u.block.size = 8;
|
||||
attr->u.block.ptr = data;
|
||||
data += 8;
|
||||
break;
|
||||
|
||||
case DW_FORM_ref1:
|
||||
|
@ -652,7 +676,7 @@ static enum location_error
|
|||
compute_location(dwarf2_traverse_context_t* ctx, struct location* loc,
|
||||
HANDLE hproc, const struct location* frame)
|
||||
{
|
||||
unsigned long stack[64];
|
||||
DWORD_PTR tmp, stack[64];
|
||||
unsigned stk;
|
||||
unsigned char op;
|
||||
BOOL piece_found = FALSE;
|
||||
|
@ -665,27 +689,11 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc,
|
|||
while (ctx->data < ctx->end_data)
|
||||
{
|
||||
op = dwarf2_parse_byte(ctx);
|
||||
switch (op)
|
||||
|
||||
if (op >= DW_OP_lit0 && op <= DW_OP_lit31)
|
||||
stack[++stk] = op - DW_OP_lit0;
|
||||
else if (op >= DW_OP_reg0 && op <= DW_OP_reg31)
|
||||
{
|
||||
case DW_OP_addr: stack[++stk] = dwarf2_parse_addr(ctx); break;
|
||||
case DW_OP_const1u: stack[++stk] = dwarf2_parse_byte(ctx); break;
|
||||
case DW_OP_const1s: stack[++stk] = (long)(signed char)dwarf2_parse_byte(ctx); break;
|
||||
case DW_OP_const2u: stack[++stk] = dwarf2_parse_u2(ctx); break;
|
||||
case DW_OP_const2s: stack[++stk] = (long)(short)dwarf2_parse_u2(ctx); break;
|
||||
case DW_OP_const4u: stack[++stk] = dwarf2_parse_u4(ctx); break;
|
||||
case DW_OP_const4s: stack[++stk] = dwarf2_parse_u4(ctx); break;
|
||||
case DW_OP_constu: stack[++stk] = dwarf2_leb128_as_unsigned(ctx); break;
|
||||
case DW_OP_consts: stack[++stk] = dwarf2_leb128_as_signed(ctx); break;
|
||||
case DW_OP_plus_uconst:
|
||||
stack[stk] += dwarf2_leb128_as_unsigned(ctx); break;
|
||||
case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3:
|
||||
case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7:
|
||||
case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11:
|
||||
case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15:
|
||||
case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19:
|
||||
case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23:
|
||||
case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27:
|
||||
case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31:
|
||||
/* dbghelp APIs don't know how to cope with this anyway
|
||||
* (for example 'long long' stored in two registers)
|
||||
* FIXME: We should tell winedbg how to deal with it (sigh)
|
||||
|
@ -698,15 +706,9 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc,
|
|||
loc->reg = dwarf2_map_register(op - DW_OP_reg0);
|
||||
}
|
||||
loc->kind = loc_register;
|
||||
break;
|
||||
case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3:
|
||||
case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7:
|
||||
case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11:
|
||||
case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15:
|
||||
case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19:
|
||||
case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23:
|
||||
case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27:
|
||||
case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31:
|
||||
}
|
||||
else if (op >= DW_OP_breg0 && op <= DW_OP_breg31)
|
||||
{
|
||||
/* dbghelp APIs don't know how to cope with this anyway
|
||||
* (for example 'long long' stored in two registers)
|
||||
* FIXME: We should tell winedbg how to deal with it (sigh)
|
||||
|
@ -714,13 +716,71 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc,
|
|||
if (!piece_found)
|
||||
{
|
||||
if (loc->reg != Wine_DW_no_register)
|
||||
FIXME("Only supporting one reg (%d -> %d)\n",
|
||||
FIXME("Only supporting one breg (%d -> %d)\n",
|
||||
loc->reg, dwarf2_map_register(op - DW_OP_breg0));
|
||||
loc->reg = dwarf2_map_register(op - DW_OP_breg0);
|
||||
}
|
||||
stack[++stk] = dwarf2_leb128_as_signed(ctx);
|
||||
loc->kind = loc_regrel;
|
||||
break;
|
||||
}
|
||||
else switch (op)
|
||||
{
|
||||
case DW_OP_nop: break;
|
||||
case DW_OP_addr: stack[++stk] = dwarf2_parse_addr(ctx); break;
|
||||
case DW_OP_const1u: stack[++stk] = dwarf2_parse_byte(ctx); break;
|
||||
case DW_OP_const1s: stack[++stk] = dwarf2_parse_byte(ctx); break;
|
||||
case DW_OP_const2u: stack[++stk] = dwarf2_parse_u2(ctx); break;
|
||||
case DW_OP_const2s: stack[++stk] = dwarf2_parse_u2(ctx); break;
|
||||
case DW_OP_const4u: stack[++stk] = dwarf2_parse_u4(ctx); break;
|
||||
case DW_OP_const4s: stack[++stk] = dwarf2_parse_u4(ctx); break;
|
||||
case DW_OP_const8u: stack[++stk] = dwarf2_parse_u8(ctx); break;
|
||||
case DW_OP_const8s: stack[++stk] = dwarf2_parse_u8(ctx); break;
|
||||
case DW_OP_constu: stack[++stk] = dwarf2_leb128_as_unsigned(ctx); break;
|
||||
case DW_OP_consts: stack[++stk] = dwarf2_leb128_as_signed(ctx); break;
|
||||
case DW_OP_dup: stack[stk + 1] = stack[stk]; stk++; break;
|
||||
case DW_OP_drop: stk--; break;
|
||||
case DW_OP_over: stack[stk + 1] = stack[stk - 1]; stk++; break;
|
||||
case DW_OP_pick: stack[stk + 1] = stack[stk - dwarf2_parse_byte(ctx)]; stk++; break;
|
||||
case DW_OP_swap: tmp = stack[stk]; stack[stk] = stack[stk-1]; stack[stk-1] = tmp; break;
|
||||
case DW_OP_rot: tmp = stack[stk]; stack[stk] = stack[stk-1]; stack[stk-1] = stack[stk-2]; stack[stk-2] = tmp; break;
|
||||
case DW_OP_abs: stack[stk] = labs(stack[stk]); break;
|
||||
case DW_OP_neg: stack[stk] = -stack[stk]; break;
|
||||
case DW_OP_not: stack[stk] = ~stack[stk]; break;
|
||||
case DW_OP_and: stack[stk-1] &= stack[stk]; stk--; break;
|
||||
case DW_OP_or: stack[stk-1] |= stack[stk]; stk--; break;
|
||||
case DW_OP_minus: stack[stk-1] -= stack[stk]; stk--; break;
|
||||
case DW_OP_mul: stack[stk-1] *= stack[stk]; stk--; break;
|
||||
case DW_OP_plus: stack[stk-1] += stack[stk]; stk--; break;
|
||||
case DW_OP_xor: stack[stk-1] ^= stack[stk]; stk--; break;
|
||||
case DW_OP_shl: stack[stk-1] <<= stack[stk]; stk--; break;
|
||||
case DW_OP_shr: stack[stk-1] >>= stack[stk]; stk--; break;
|
||||
case DW_OP_plus_uconst: stack[stk] += dwarf2_leb128_as_unsigned(ctx); break;
|
||||
case DW_OP_shra: stack[stk-1] = stack[stk-1] / (1 << stack[stk]); stk--; break;
|
||||
case DW_OP_div: stack[stk-1] = stack[stk-1] / stack[stk]; stk--; break;
|
||||
case DW_OP_mod: stack[stk-1] = stack[stk-1] % stack[stk]; stk--; break;
|
||||
case DW_OP_ge: stack[stk-1] = (stack[stk-1] >= stack[stk]); stk--; break;
|
||||
case DW_OP_gt: stack[stk-1] = (stack[stk-1] > stack[stk]); stk--; break;
|
||||
case DW_OP_le: stack[stk-1] = (stack[stk-1] <= stack[stk]); stk--; break;
|
||||
case DW_OP_lt: stack[stk-1] = (stack[stk-1] < stack[stk]); stk--; break;
|
||||
case DW_OP_eq: stack[stk-1] = (stack[stk-1] == stack[stk]); stk--; break;
|
||||
case DW_OP_ne: stack[stk-1] = (stack[stk-1] != stack[stk]); stk--; break;
|
||||
case DW_OP_skip: tmp = dwarf2_parse_u2(ctx); ctx->data += tmp; break;
|
||||
case DW_OP_bra: tmp = dwarf2_parse_u2(ctx); if (!stack[stk--]) ctx->data += tmp; break;
|
||||
case DW_OP_regx:
|
||||
if (loc->reg != Wine_DW_no_register)
|
||||
FIXME("Only supporting one regx\n");
|
||||
loc->reg = dwarf2_map_register(dwarf2_leb128_as_unsigned(ctx));
|
||||
loc->kind = loc_register;
|
||||
break;
|
||||
case DW_OP_bregx:
|
||||
tmp = dwarf2_leb128_as_unsigned(ctx);
|
||||
ctx->data++;
|
||||
if (loc->reg != Wine_DW_no_register)
|
||||
FIXME("Only supporting one regx\n");
|
||||
loc->reg = dwarf2_map_register(tmp) + dwarf2_leb128_as_signed(ctx);
|
||||
loc->kind = loc_register;
|
||||
break;
|
||||
case DW_OP_fbreg:
|
||||
if (loc->reg != Wine_DW_no_register)
|
||||
FIXME("Only supporting one reg (%d -> -2)\n", loc->reg);
|
||||
|
@ -765,12 +825,12 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc,
|
|||
}
|
||||
if (hproc)
|
||||
{
|
||||
DWORD addr = stack[stk--];
|
||||
DWORD deref;
|
||||
DWORD_PTR addr = stack[stk--];
|
||||
DWORD_PTR deref;
|
||||
|
||||
if (!ReadProcessMemory(hproc, (void*)addr, &deref, sizeof(deref), NULL))
|
||||
{
|
||||
WARN("Couldn't read memory at %x\n", addr);
|
||||
WARN("Couldn't read memory at %lx\n", addr);
|
||||
return loc_err_cant_read;
|
||||
}
|
||||
stack[++stk] = deref;
|
||||
|
@ -780,8 +840,46 @@ compute_location(dwarf2_traverse_context_t* ctx, struct location* loc,
|
|||
loc->kind = loc_dwarf2_block;
|
||||
}
|
||||
break;
|
||||
case DW_OP_deref_size:
|
||||
if (!stk)
|
||||
{
|
||||
FIXME("Unexpected empty stack\n");
|
||||
return loc_err_internal;
|
||||
}
|
||||
if (loc->reg != Wine_DW_no_register)
|
||||
{
|
||||
WARN("Too complex expression for deref\n");
|
||||
return loc_err_too_complex;
|
||||
}
|
||||
if (hproc)
|
||||
{
|
||||
DWORD_PTR addr = stack[stk--];
|
||||
BYTE derefsize = dwarf2_parse_byte(ctx);
|
||||
DWORD64 deref;
|
||||
|
||||
if (!ReadProcessMemory(hproc, (void*)addr, &deref, derefsize, NULL))
|
||||
{
|
||||
WARN("Couldn't read memory at %lx\n", addr);
|
||||
return loc_err_cant_read;
|
||||
}
|
||||
|
||||
switch (derefsize)
|
||||
{
|
||||
case 1: stack[++stk] = *(unsigned char*)&deref; break;
|
||||
case 2: stack[++stk] = *(unsigned short*)&deref; break;
|
||||
case 4: stack[++stk] = *(DWORD*)&deref; break;
|
||||
case 8: if (ctx->word_size >= derefsize) stack[++stk] = deref; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
loc->kind = loc_dwarf2_block;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FIXME("Unhandled attr op: %x\n", op);
|
||||
if (op < DW_OP_lo_user) /* as DW_OP_hi_user is 0xFF, we don't need to test against it */
|
||||
FIXME("Unhandled attr op: %x\n", op);
|
||||
/* FIXME else unhandled extension */
|
||||
return loc_err_internal;
|
||||
}
|
||||
}
|
||||
|
@ -1163,7 +1261,8 @@ static void dwarf2_parse_udt_member(dwarf2_parse_context_t* ctx,
|
|||
if (!dwarf2_find_attribute(ctx, di, DW_AT_byte_size, &nbytes))
|
||||
{
|
||||
DWORD64 size;
|
||||
nbytes.u.uvalue = symt_get_info(elt_type, TI_GET_LENGTH, &size) ? (unsigned long)size : 0;
|
||||
nbytes.u.uvalue = symt_get_info(ctx->module, elt_type, TI_GET_LENGTH, &size) ?
|
||||
(unsigned long)size : 0;
|
||||
}
|
||||
bit_offset.u.uvalue = nbytes.u.uvalue * 8 - bit_offset.u.uvalue - bit_size.u.uvalue;
|
||||
}
|
||||
|
@ -1214,6 +1313,10 @@ static struct symt* dwarf2_parse_udt_type(dwarf2_parse_context_t* ctx,
|
|||
case DW_TAG_union_type:
|
||||
case DW_TAG_typedef:
|
||||
/* FIXME: we need to handle nested udt definitions */
|
||||
case DW_TAG_inheritance:
|
||||
case DW_TAG_subprogram:
|
||||
case DW_TAG_variable:
|
||||
/* FIXME: some C++ related stuff */
|
||||
break;
|
||||
default:
|
||||
FIXME("Unhandled Tag type 0x%lx at %s, for %s\n",
|
||||
|
@ -1334,6 +1437,8 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm,
|
|||
|
||||
switch (loc.kind)
|
||||
{
|
||||
case loc_error:
|
||||
break;
|
||||
case loc_absolute:
|
||||
/* it's a global variable */
|
||||
/* FIXME: we don't handle its scope yet */
|
||||
|
@ -1389,11 +1494,28 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm,
|
|||
v.n1.n2.n3.byref = pool_strdup(&subpgm->ctx->module->pool, value.u.string);
|
||||
break;
|
||||
|
||||
case DW_FORM_data8:
|
||||
case DW_FORM_block:
|
||||
case DW_FORM_block1:
|
||||
case DW_FORM_block2:
|
||||
case DW_FORM_block4:
|
||||
v.n1.n2.vt = VT_I4;
|
||||
switch (value.u.block.size)
|
||||
{
|
||||
case 1: v.n1.n2.n3.lVal = *(BYTE*)value.u.block.ptr; break;
|
||||
case 2: v.n1.n2.n3.lVal = *(USHORT*)value.u.block.ptr; break;
|
||||
case 4: v.n1.n2.n3.lVal = *(DWORD*)value.u.block.ptr; break;
|
||||
default:
|
||||
v.n1.n2.vt = VT_I1 | VT_BYREF;
|
||||
v.n1.n2.n3.byref = pool_alloc(&subpgm->ctx->module->pool, value.u.block.size);
|
||||
memcpy(v.n1.n2.n3.byref, value.u.block.ptr, value.u.block.size);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_FORM_data8:
|
||||
v.n1.n2.vt = VT_I1 | VT_BYREF;
|
||||
v.n1.n2.n3.byref = pool_alloc(&subpgm->ctx->module->pool, value.u.block.size);
|
||||
memcpy(v.n1.n2.n3.byref, value.u.block.ptr, value.u.block.size);
|
||||
break;
|
||||
|
||||
default:
|
||||
FIXME("Unsupported form for const value %s (%lx)\n",
|
||||
|
@ -1786,6 +1908,11 @@ static void dwarf2_load_one_entry(dwarf2_parse_context_t* ctx,
|
|||
dwarf2_parse_variable(&subpgm, NULL, di);
|
||||
}
|
||||
break;
|
||||
/* silence a couple of C++ defines */
|
||||
case DW_TAG_namespace:
|
||||
case DW_TAG_imported_module:
|
||||
case DW_TAG_imported_declaration:
|
||||
break;
|
||||
default:
|
||||
FIXME("Unhandled Tag type 0x%lx at %s, for %lu\n",
|
||||
di->abbrev->tag, dwarf2_debug_ctx(ctx), di->abbrev->entry_code);
|
||||
|
@ -2010,7 +2137,7 @@ static BOOL dwarf2_parse_compilation_unit(const dwarf2_section_t* sections,
|
|||
cu_ctx.word_size = dwarf2_parse_byte(&cu_ctx);
|
||||
|
||||
TRACE("Compilation Unit Header found at 0x%x:\n",
|
||||
comp_unit_start - sections[section_debug].address);
|
||||
(int)(comp_unit_start - sections[section_debug].address));
|
||||
TRACE("- length: %lu\n", cu_length);
|
||||
TRACE("- version: %u\n", cu_version);
|
||||
TRACE("- abbrev_offset: %lu\n", cu_abbrev_offset);
|
||||
|
|
|
@ -376,6 +376,18 @@ typedef enum dwarf_operation_e
|
|||
DW_OP_call2 = 0x98,
|
||||
DW_OP_call4 = 0x99,
|
||||
DW_OP_call_ref = 0x9a,
|
||||
DW_OP_form_tls_address = 0x9b,
|
||||
DW_OP_call_frame_cfa = 0x9c,
|
||||
DW_OP_bit_piece = 0x9d,
|
||||
|
||||
/* Implementation defined extensions */
|
||||
DW_OP_lo_user = 0xe0,
|
||||
DW_OP_hi_user = 0xff,
|
||||
|
||||
/* GNU extensions */
|
||||
DW_OP_GNU_push_tls_address = 0xe0,
|
||||
DW_OP_GNU_uninit = 0xf0,
|
||||
DW_OP_GNU_encoded_addr = 0xf1,
|
||||
} dwarf_operation_t;
|
||||
|
||||
enum dwarf_calling_convention
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
|
||||
struct elf_module_info
|
||||
{
|
||||
unsigned long elf_addr;
|
||||
DWORD_PTR elf_addr;
|
||||
unsigned short elf_mark : 1,
|
||||
elf_loader : 1;
|
||||
};
|
||||
|
@ -93,22 +93,36 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
|||
struct elf_info
|
||||
{
|
||||
unsigned flags; /* IN one (or several) of the ELF_INFO constants */
|
||||
unsigned long dbg_hdr_addr; /* OUT address of debug header (if ELF_INFO_DEBUG_HEADER is set) */
|
||||
DWORD_PTR dbg_hdr_addr; /* OUT address of debug header (if ELF_INFO_DEBUG_HEADER is set) */
|
||||
struct module* module; /* OUT loaded module (if ELF_INFO_MODULE is set) */
|
||||
const WCHAR* module_name; /* OUT found module name (if ELF_INFO_NAME is set) */
|
||||
};
|
||||
|
||||
#ifdef _WIN64
|
||||
#define Elf_Ehdr Elf64_Ehdr
|
||||
#define Elf_Shdr Elf64_Shdr
|
||||
#define Elf_Phdr Elf64_Phdr
|
||||
#define Elf_Dyn Elf64_Dyn
|
||||
#define Elf_Sym Elf64_Sym
|
||||
#else
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Phdr Elf32_Phdr
|
||||
#define Elf_Dyn Elf32_Dyn
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#endif
|
||||
|
||||
/* structure holding information while handling an ELF image
|
||||
* allows one by one section mapping for memory savings
|
||||
*/
|
||||
struct elf_file_map
|
||||
{
|
||||
Elf32_Ehdr elfhdr;
|
||||
Elf_Ehdr elfhdr;
|
||||
size_t elf_size;
|
||||
size_t elf_start;
|
||||
struct
|
||||
{
|
||||
Elf32_Shdr shdr;
|
||||
Elf_Shdr shdr;
|
||||
const char* mapped;
|
||||
}* sect;
|
||||
int fd;
|
||||
|
@ -125,7 +139,7 @@ struct elf_section_map
|
|||
struct symtab_elt
|
||||
{
|
||||
struct hash_table_elt ht_elt;
|
||||
const Elf32_Sym* symp;
|
||||
const Elf_Sym* symp;
|
||||
struct symt_compiland* compiland;
|
||||
unsigned used;
|
||||
};
|
||||
|
@ -237,7 +251,7 @@ static void elf_end_find(struct elf_file_map* fmap)
|
|||
*
|
||||
* Get the size of an ELF section
|
||||
*/
|
||||
static inline unsigned elf_get_map_size(struct elf_section_map* esm)
|
||||
static inline unsigned elf_get_map_size(const struct elf_section_map* esm)
|
||||
{
|
||||
if (esm->sidx < 0 || esm->sidx >= esm->fmap->elfhdr.e_shnum)
|
||||
return 0;
|
||||
|
@ -254,7 +268,7 @@ static BOOL elf_map_file(const WCHAR* filenameW, struct elf_file_map* fmap)
|
|||
static const BYTE elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
|
||||
struct stat statbuf;
|
||||
int i;
|
||||
Elf32_Phdr phdr;
|
||||
Elf_Phdr phdr;
|
||||
unsigned tmp, page_mask = getpagesize() - 1;
|
||||
char* filename;
|
||||
unsigned len;
|
||||
|
@ -279,7 +293,12 @@ static BOOL elf_map_file(const WCHAR* filenameW, struct elf_file_map* fmap)
|
|||
/* and check for an ELF header */
|
||||
if (memcmp(fmap->elfhdr.e_ident,
|
||||
elf_signature, sizeof(elf_signature))) goto done;
|
||||
|
||||
/* and check 32 vs 64 size according to current machine */
|
||||
#ifdef _WIN64
|
||||
if (fmap->elfhdr.e_ident[EI_CLASS] != ELFCLASS64) goto done;
|
||||
#else
|
||||
if (fmap->elfhdr.e_ident[EI_CLASS] != ELFCLASS32) goto done;
|
||||
#endif
|
||||
fmap->sect = HeapAlloc(GetProcessHeap(), 0,
|
||||
fmap->elfhdr.e_shnum * sizeof(fmap->sect[0]));
|
||||
if (!fmap->sect) goto done;
|
||||
|
@ -350,7 +369,7 @@ int elf_is_in_thunk_area(unsigned long addr,
|
|||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; thunks[i].symname; i++)
|
||||
if (thunks) for (i = 0; thunks[i].symname; i++)
|
||||
{
|
||||
if (addr >= thunks[i].rva_start && addr < thunks[i].rva_end)
|
||||
return i;
|
||||
|
@ -372,13 +391,13 @@ static void elf_hash_symtab(struct module* module, struct pool* pool,
|
|||
const char* symname;
|
||||
struct symt_compiland* compiland = NULL;
|
||||
const char* ptr;
|
||||
const Elf32_Sym* symp;
|
||||
const Elf_Sym* symp;
|
||||
struct symtab_elt* ste;
|
||||
struct elf_section_map esm, esm_str;
|
||||
|
||||
if (!elf_find_section(fmap, ".symtab", SHT_SYMTAB, &esm) &&
|
||||
!elf_find_section(fmap, ".dynsym", SHT_DYNSYM, &esm)) return;
|
||||
if ((symp = (const Elf32_Sym*)elf_map_section(&esm)) == ELF_NO_MAP) return;
|
||||
if ((symp = (const Elf_Sym*)elf_map_section(&esm)) == ELF_NO_MAP) return;
|
||||
esm_str.fmap = fmap;
|
||||
esm_str.sidx = fmap->sect[esm.sidx].shdr.sh_link;
|
||||
if ((strp = elf_map_section(&esm_str)) == ELF_NO_MAP) return;
|
||||
|
@ -471,9 +490,9 @@ static void elf_hash_symtab(struct module* module, struct pool* pool,
|
|||
*
|
||||
* lookup a symbol by name in our internal hash table for the symtab
|
||||
*/
|
||||
static const Elf32_Sym* elf_lookup_symtab(const struct module* module,
|
||||
static const Elf_Sym* elf_lookup_symtab(const struct module* module,
|
||||
const struct hash_table* ht_symtab,
|
||||
const char* name, struct symt* compiland)
|
||||
const char* name, const struct symt* compiland)
|
||||
{
|
||||
struct symtab_elt* weak_result = NULL; /* without compiland name */
|
||||
struct symtab_elt* result = NULL;
|
||||
|
@ -490,7 +509,7 @@ static const Elf32_Sym* elf_lookup_symtab(const struct module* module,
|
|||
if (compiland)
|
||||
{
|
||||
compiland_name = source_get(module,
|
||||
((struct symt_compiland*)compiland)->source);
|
||||
((const struct symt_compiland*)compiland)->source);
|
||||
compiland_basename = strrchr(compiland_name, '/');
|
||||
if (!compiland_basename++) compiland_basename = compiland_name;
|
||||
}
|
||||
|
@ -542,12 +561,12 @@ static const Elf32_Sym* elf_lookup_symtab(const struct module* module,
|
|||
* - get any relevant information (address & size) from the bits we got from the
|
||||
* stabs debugging information
|
||||
*/
|
||||
static void elf_finish_stabs_info(struct module* module, struct hash_table* symtab)
|
||||
static void elf_finish_stabs_info(struct module* module, const struct hash_table* symtab)
|
||||
{
|
||||
struct hash_table_iter hti;
|
||||
void* ptr;
|
||||
struct symt_ht* sym;
|
||||
const Elf32_Sym* symp;
|
||||
const Elf_Sym* symp;
|
||||
|
||||
hash_table_iter_init(&module->ht_symbols, &hti, NULL);
|
||||
while ((ptr = hash_table_iter_up(&hti)))
|
||||
|
@ -623,13 +642,13 @@ static void elf_finish_stabs_info(struct module* module, struct hash_table* symt
|
|||
*
|
||||
* creating the thunk objects for a wine native DLL
|
||||
*/
|
||||
static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symtab,
|
||||
static int elf_new_wine_thunks(struct module* module, const struct hash_table* ht_symtab,
|
||||
const struct elf_thunk_area* thunks)
|
||||
{
|
||||
int j;
|
||||
struct hash_table_iter hti;
|
||||
struct symtab_elt* ste;
|
||||
DWORD addr;
|
||||
DWORD_PTR addr;
|
||||
struct symt_ht* symt;
|
||||
|
||||
hash_table_iter_init(ht_symtab, &hti, NULL);
|
||||
|
@ -650,8 +669,8 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt
|
|||
ULONG64 ref_addr;
|
||||
|
||||
symt = symt_find_nearest(module, addr);
|
||||
if (symt)
|
||||
symt_get_info(&symt->symt, TI_GET_ADDRESS, &ref_addr);
|
||||
if (symt && !symt_get_info(module, &symt->symt, TI_GET_ADDRESS, &ref_addr))
|
||||
ref_addr = addr;
|
||||
if (!symt || addr != ref_addr)
|
||||
{
|
||||
/* creating public symbols for all the ELF symbols which haven't been
|
||||
|
@ -687,9 +706,9 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt
|
|||
ULONG64 xaddr = 0, xsize = 0;
|
||||
DWORD kind = -1;
|
||||
|
||||
symt_get_info(&symt->symt, TI_GET_ADDRESS, &xaddr);
|
||||
symt_get_info(&symt->symt, TI_GET_LENGTH, &xsize);
|
||||
symt_get_info(&symt->symt, TI_GET_DATAKIND, &kind);
|
||||
symt_get_info(module, &symt->symt, TI_GET_ADDRESS, &xaddr);
|
||||
symt_get_info(module, &symt->symt, TI_GET_LENGTH, &xsize);
|
||||
symt_get_info(module, &symt->symt, TI_GET_DATAKIND, &kind);
|
||||
|
||||
/* If none of symbols has a correct size, we consider they are both markers
|
||||
* Hence, we can silence this warning
|
||||
|
@ -698,7 +717,7 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt
|
|||
*/
|
||||
if ((xsize || ste->symp->st_size) &&
|
||||
(kind == (ELF32_ST_BIND(ste->symp->st_info) == STB_LOCAL) ? DataIsFileStatic : DataIsGlobal))
|
||||
FIXME("Duplicate in %s: %s<%08x-%08x> %s<%s-%s>\n",
|
||||
FIXME("Duplicate in %s: %s<%08lx-%08x> %s<%s-%s>\n",
|
||||
debugstr_w(module->module.ModuleName),
|
||||
ste->ht_elt.name, addr, (unsigned int)ste->symp->st_size,
|
||||
symt->hash_elt.name,
|
||||
|
@ -716,7 +735,7 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt
|
|||
*
|
||||
* Creates a set of public symbols from an ELF symtab
|
||||
*/
|
||||
static int elf_new_public_symbols(struct module* module, struct hash_table* symtab)
|
||||
static int elf_new_public_symbols(struct module* module, const struct hash_table* symtab)
|
||||
{
|
||||
struct hash_table_iter hti;
|
||||
struct symtab_elt* ste;
|
||||
|
@ -730,142 +749,19 @@ static int elf_new_public_symbols(struct module* module, struct hash_table* symt
|
|||
{
|
||||
symt_new_public(module, ste->compiland, ste->ht_elt.name,
|
||||
module->elf_info->elf_addr + ste->symp->st_value,
|
||||
ste->symp->st_size, TRUE /* FIXME */,
|
||||
ELF32_ST_TYPE(ste->symp->st_info) == STT_FUNC);
|
||||
ste->symp->st_size);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Copyright (C) 1986 Gary S. Brown. Modified by Robert Shearman. You may use
|
||||
the following calc_crc32 code or tables extracted from it, as desired without
|
||||
restriction. */
|
||||
|
||||
/**********************************************************************\
|
||||
|* Demonstration program to compute the 32-bit CRC used as the frame *|
|
||||
|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *|
|
||||
|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *|
|
||||
|* protocol). The 32-bit FCS was added via the Federal Register, *|
|
||||
|* 1 June 1982, p.23798. I presume but don't know for certain that *|
|
||||
|* this polynomial is or will be included in CCITT V.41, which *|
|
||||
|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *|
|
||||
|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *|
|
||||
|* errors by a factor of 10^-5 over 16-bit FCS. *|
|
||||
\**********************************************************************/
|
||||
|
||||
/* First, the polynomial itself and its table of feedback terms. The */
|
||||
/* polynomial is */
|
||||
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
|
||||
/* Note that we take it "backwards" and put the highest-order term in */
|
||||
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
|
||||
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
|
||||
/* the MSB being 1. */
|
||||
|
||||
/* Note that the usual hardware shift register implementation, which */
|
||||
/* is what we're using (we're merely optimizing it by doing eight-bit */
|
||||
/* chunks at a time) shifts bits into the lowest-order term. In our */
|
||||
/* implementation, that means shifting towards the right. Why do we */
|
||||
/* do it this way? Because the calculated CRC must be transmitted in */
|
||||
/* order from highest-order term to lowest-order term. UARTs transmit */
|
||||
/* characters in order from LSB to MSB. By storing the CRC this way, */
|
||||
/* we hand it to the UART in the order low-byte to high-byte; the UART */
|
||||
/* sends each low-bit to hight-bit; and the result is transmission bit */
|
||||
/* by bit from highest- to lowest-order term without requiring any bit */
|
||||
/* shuffling on our part. Reception works similarly. */
|
||||
|
||||
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
|
||||
/* */
|
||||
/* 1. The table can be generated at runtime if desired; code to do so */
|
||||
/* is shown later. It might not be obvious, but the feedback */
|
||||
/* terms simply represent the results of eight shift/xor opera- */
|
||||
/* tions for all combinations of data and CRC register values. */
|
||||
/* */
|
||||
/* 2. The CRC accumulation logic is the same for all CRC polynomials, */
|
||||
/* be they sixteen or thirty-two bits wide. You simply choose the */
|
||||
/* appropriate table. Alternatively, because the table can be */
|
||||
/* generated at runtime, you can start by generating the table for */
|
||||
/* the polynomial in question and use exactly the same "updcrc", */
|
||||
/* if your application needn't simultaneously handle two CRC */
|
||||
/* polynomials. (Note, however, that XMODEM is strange.) */
|
||||
/* */
|
||||
/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */
|
||||
/* of course, 32-bit entries work OK if the high 16 bits are zero. */
|
||||
/* */
|
||||
/* 4. The values must be right-shifted by eight bits by the "updcrc" */
|
||||
/* logic; the shift must be unsigned (bring in zeroes). On some */
|
||||
/* hardware you could probably optimize the shift in assembler by */
|
||||
/* using byte-swap instructions. */
|
||||
|
||||
|
||||
static DWORD calc_crc32(struct elf_file_map* fmap)
|
||||
{
|
||||
#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
|
||||
static const DWORD crc_32_tab[] =
|
||||
{ /* CRC polynomial 0xedb88320 */
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
int i, r;
|
||||
unsigned char buffer[256];
|
||||
DWORD crc = ~0;
|
||||
|
||||
lseek(fmap->fd, 0, SEEK_SET);
|
||||
while ((r = read(fmap->fd, buffer, sizeof(buffer))) > 0)
|
||||
{
|
||||
for (i = 0; i < r; i++) crc = UPDC32(buffer[i], crc);
|
||||
}
|
||||
return ~crc;
|
||||
#undef UPDC32
|
||||
}
|
||||
|
||||
static BOOL elf_check_debug_link(const WCHAR* file, struct elf_file_map* fmap, DWORD crc)
|
||||
{
|
||||
BOOL ret;
|
||||
if (!elf_map_file(file, fmap)) return FALSE;
|
||||
if (!(ret = crc == calc_crc32(fmap)))
|
||||
if (!(ret = crc == calc_crc32(fmap->fd)))
|
||||
{
|
||||
WARN("Bad CRC for file %s (got %08x while expecting %08x)\n",
|
||||
debugstr_w(file), calc_crc32(fmap), crc);
|
||||
debugstr_w(file), calc_crc32(fmap->fd), crc);
|
||||
elf_unmap_file(fmap);
|
||||
}
|
||||
return ret;
|
||||
|
@ -952,7 +848,7 @@ found:
|
|||
* Parses a .gnu_debuglink section and loads the debug info from
|
||||
* the external file specified there.
|
||||
*/
|
||||
static BOOL elf_debuglink_parse(struct elf_file_map* fmap, struct module* module,
|
||||
static BOOL elf_debuglink_parse(struct elf_file_map* fmap, const struct module* module,
|
||||
const BYTE* debuglink)
|
||||
{
|
||||
/* The content of a debug link section is:
|
||||
|
@ -1039,7 +935,8 @@ static BOOL elf_load_debug_info_from_map(struct module* module,
|
|||
/* OK, now just parse all of the stabs. */
|
||||
lret = stabs_parse(module, module->elf_info->elf_addr,
|
||||
stab, elf_get_map_size(&stab_sect),
|
||||
stabstr, elf_get_map_size(&stabstr_sect));
|
||||
stabstr, elf_get_map_size(&stabstr_sect),
|
||||
NULL, NULL);
|
||||
if (lret)
|
||||
/* and fill in the missing information for stabs */
|
||||
elf_finish_stabs_info(module, ht_symtab);
|
||||
|
@ -1160,7 +1057,7 @@ BOOL elf_fetch_file_info(const WCHAR* name, DWORD* base,
|
|||
if (!elf_map_file(name, &fmap)) return FALSE;
|
||||
if (base) *base = fmap.elf_start;
|
||||
*size = fmap.elf_size;
|
||||
*checksum = calc_crc32(&fmap);
|
||||
*checksum = calc_crc32(fmap.fd);
|
||||
elf_unmap_file(&fmap);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1184,7 +1081,7 @@ static BOOL elf_load_file(struct process* pcs, const WCHAR* filename,
|
|||
|
||||
TRACE("Processing elf file '%s' at %08lx\n", debugstr_w(filename), load_offset);
|
||||
|
||||
if (!elf_map_file(filename, &fmap)) goto leave;
|
||||
if (!elf_map_file(filename, &fmap)) return ret;
|
||||
|
||||
/* Next, we need to find a few of the internal ELF headers within
|
||||
* this thing. We need the main executable header, and the section
|
||||
|
@ -1206,7 +1103,7 @@ static BOOL elf_load_file(struct process* pcs, const WCHAR* filename,
|
|||
|
||||
if (elf_find_section(&fmap, ".dynamic", SHT_DYNAMIC, &esm))
|
||||
{
|
||||
Elf32_Dyn dyn;
|
||||
Elf_Dyn dyn;
|
||||
char* ptr = (char*)fmap.sect[esm.sidx].shdr.sh_addr;
|
||||
unsigned long len;
|
||||
|
||||
|
@ -1234,7 +1131,7 @@ static BOOL elf_load_file(struct process* pcs, const WCHAR* filename,
|
|||
if (!elf_module_info) goto leave;
|
||||
elf_info->module = module_new(pcs, filename, DMT_ELF, FALSE,
|
||||
(load_offset) ? load_offset : fmap.elf_start,
|
||||
fmap.elf_size, 0, calc_crc32(&fmap));
|
||||
fmap.elf_size, 0, calc_crc32(fmap.fd));
|
||||
if (!elf_info->module)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, elf_module_info);
|
||||
|
@ -1389,7 +1286,7 @@ static BOOL elf_search_and_load_file(struct process* pcs, const WCHAR* filename,
|
|||
*/
|
||||
static BOOL elf_enum_modules_internal(const struct process* pcs,
|
||||
const WCHAR* main_name,
|
||||
elf_enum_modules_cb cb, void* user)
|
||||
enum_modules_cb cb, void* user)
|
||||
{
|
||||
struct r_debug dbg_hdr;
|
||||
void* lm_addr;
|
||||
|
@ -1492,9 +1389,7 @@ static BOOL elf_search_loader(struct process* pcs, struct elf_info* elf_info)
|
|||
const char* ptr;
|
||||
|
||||
/* All binaries are loaded with WINELOADER (if run from tree) or by the
|
||||
* main executable (either wine-kthread or wine-pthread)
|
||||
* FIXME: the heuristic used to know whether we need to load wine-pthread
|
||||
* or wine-kthread is not 100% safe
|
||||
* main executable
|
||||
*/
|
||||
if ((ptr = getenv("WINELOADER")))
|
||||
{
|
||||
|
@ -1504,8 +1399,7 @@ static BOOL elf_search_loader(struct process* pcs, struct elf_info* elf_info)
|
|||
}
|
||||
else
|
||||
{
|
||||
ret = elf_search_and_load_file(pcs, S_WineKThreadW, 0, elf_info) ||
|
||||
elf_search_and_load_file(pcs, S_WinePThreadW, 0, elf_info);
|
||||
ret = elf_search_and_load_file(pcs, S_WineW, 0, elf_info);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -1533,7 +1427,7 @@ BOOL elf_read_wine_loader_dbg_info(struct process* pcs)
|
|||
* This function doesn't require that someone has called SymInitialize
|
||||
* on this very process.
|
||||
*/
|
||||
BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb cb, void* user)
|
||||
BOOL elf_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
|
||||
{
|
||||
struct process pcs;
|
||||
struct elf_info elf_info;
|
||||
|
@ -1638,7 +1532,7 @@ BOOL elf_read_wine_loader_dbg_info(struct process* pcs)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb cb, void* user)
|
||||
BOOL elf_enum_modules(HANDLE hProc, enum_modules_cb cb, void* user)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
|
1434
reactos/dll/win32/dbghelp/macho_module.c
Normal file
1434
reactos/dll/win32/dbghelp/macho_module.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -34,7 +34,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
|||
|
||||
struct dump_memory
|
||||
{
|
||||
ULONG base;
|
||||
ULONG64 base;
|
||||
ULONG size;
|
||||
ULONG rva;
|
||||
};
|
||||
|
@ -42,7 +42,7 @@ struct dump_memory
|
|||
struct dump_module
|
||||
{
|
||||
unsigned is_elf;
|
||||
ULONG base;
|
||||
ULONG64 base;
|
||||
ULONG size;
|
||||
DWORD timestamp;
|
||||
DWORD checksum;
|
||||
|
@ -59,6 +59,7 @@ struct dump_context
|
|||
/* module information */
|
||||
struct dump_module* modules;
|
||||
unsigned num_modules;
|
||||
unsigned alloc_modules;
|
||||
/* exception information */
|
||||
/* output information */
|
||||
MINIDUMP_TYPE type;
|
||||
|
@ -66,6 +67,7 @@ struct dump_context
|
|||
RVA rva;
|
||||
struct dump_memory* mem;
|
||||
unsigned num_mem;
|
||||
unsigned alloc_mem;
|
||||
/* callback information */
|
||||
MINIDUMP_CALLBACK_INFORMATION* cb;
|
||||
};
|
||||
|
@ -98,10 +100,9 @@ static BOOL fetch_processes_info(struct dump_context* dc)
|
|||
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);
|
||||
if (HandleToUlong(dc->spi->UniqueProcessId) == dc->pid) return TRUE;
|
||||
if (!dc->spi->NextEntryOffset) break;
|
||||
dc->spi = (SYSTEM_PROCESS_INFORMATION*)((char*)dc->spi + dc->spi->NextEntryOffset);
|
||||
}
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, dc->pcs_buffer);
|
||||
|
@ -114,58 +115,25 @@ static void fetch_thread_stack(struct dump_context* dc, const void* teb_addr,
|
|||
const CONTEXT* ctx, MINIDUMP_MEMORY_DESCRIPTOR* mmd)
|
||||
{
|
||||
NT_TIB tib;
|
||||
ADDRESS64 addr;
|
||||
|
||||
if (ReadProcessMemory(dc->hProcess, teb_addr, &tib, sizeof(tib), NULL))
|
||||
if (ReadProcessMemory(dc->hProcess, teb_addr, &tib, sizeof(tib), NULL) &&
|
||||
dbghelp_current_cpu &&
|
||||
dbghelp_current_cpu->get_addr(NULL /* FIXME */, ctx, cpu_addr_stack, &addr) && addr.Mode == AddrModeFlat)
|
||||
{
|
||||
#ifdef __i386__
|
||||
/* limiting the stack dumping to the size actually used */
|
||||
if (ctx->Esp){
|
||||
|
||||
/* make sure ESP is within the established range of the stack. It could have
|
||||
if (addr.Offset)
|
||||
{
|
||||
addr.Offset -= dbghelp_current_cpu->word_size;
|
||||
/* make sure stack pointer is within the established range of the stack. It could have
|
||||
been clobbered by whatever caused the original exception. */
|
||||
if (ctx->Esp - 4 < (ULONG_PTR)tib.StackLimit || ctx->Esp - 4 > (ULONG_PTR)tib.StackBase)
|
||||
if (addr.Offset < (ULONG_PTR)tib.StackLimit || addr.Offset > (ULONG_PTR)tib.StackBase)
|
||||
mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
|
||||
|
||||
else
|
||||
mmd->StartOfMemoryRange = (ctx->Esp - 4);
|
||||
mmd->StartOfMemoryRange = addr.Offset;
|
||||
}
|
||||
|
||||
else
|
||||
mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
|
||||
|
||||
#elif defined(__powerpc__)
|
||||
if (ctx->Iar){
|
||||
|
||||
/* make sure IAR is within the established range of the stack. It could have
|
||||
been clobbered by whatever caused the original exception. */
|
||||
if (ctx->Iar - 4 < (ULONG_PTR)tib.StackLimit || ctx->Iar - 4 > (ULONG_PTR)tib.StackBase)
|
||||
mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
|
||||
|
||||
else
|
||||
mmd->StartOfMemoryRange = (ctx->Iar - 4);
|
||||
}
|
||||
|
||||
else
|
||||
mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
if (ctx->Rsp){
|
||||
|
||||
/* make sure RSP is within the established range of the stack. It could have
|
||||
been clobbered by whatever caused the original exception. */
|
||||
if (ctx->Rsp - 8 < (ULONG_PTR)tib.StackLimit || ctx->Rsp - 8 > (ULONG_PTR)tib.StackBase)
|
||||
mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
|
||||
|
||||
else
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -179,13 +147,13 @@ 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;
|
||||
DWORD tid = HandleToUlong(dc->spi->ti[thd_idx].ClientId.UniqueThread);
|
||||
HANDLE hThread;
|
||||
THREAD_BASIC_INFORMATION tbi;
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
mdThd->ThreadId = dc->spi->ti[thd_idx].dwThreadID;
|
||||
mdThd->ThreadId = tid;
|
||||
mdThd->SuspendCount = 0;
|
||||
mdThd->Teb = 0;
|
||||
mdThd->Stack.StartOfMemoryRange = 0;
|
||||
|
@ -198,8 +166,7 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
|
|||
|
||||
if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL)
|
||||
{
|
||||
FIXME("Couldn't open thread %u (%u)\n",
|
||||
dc->spi->ti[thd_idx].dwThreadID, GetLastError());
|
||||
FIXME("Couldn't open thread %u (%u)\n", tid, GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -230,7 +197,7 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
|
|||
ReadProcessMemory(dc->hProcess, except->ExceptionPointers,
|
||||
&ep, sizeof(ep), NULL);
|
||||
ReadProcessMemory(dc->hProcess, ep.ContextRecord,
|
||||
&ctx, sizeof(ctx), NULL);
|
||||
&lctx, sizeof(lctx), NULL);
|
||||
pctx = &lctx;
|
||||
}
|
||||
else pctx = except->ExceptionPointers->ContextRecord;
|
||||
|
@ -251,27 +218,38 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
|
|||
* 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,
|
||||
DWORD64 base, DWORD size, DWORD timestamp, DWORD checksum,
|
||||
BOOL is_elf)
|
||||
{
|
||||
if (!dc->modules)
|
||||
{
|
||||
dc->alloc_modules = 32;
|
||||
dc->modules = HeapAlloc(GetProcessHeap(), 0,
|
||||
++dc->num_modules * sizeof(*dc->modules));
|
||||
else
|
||||
dc->alloc_modules * sizeof(*dc->modules));
|
||||
}
|
||||
else if(dc->num_modules >= dc->alloc_modules)
|
||||
{
|
||||
dc->alloc_modules *= 2;
|
||||
dc->modules = HeapReAlloc(GetProcessHeap(), 0, dc->modules,
|
||||
++dc->num_modules * sizeof(*dc->modules));
|
||||
if (!dc->modules) return FALSE;
|
||||
dc->alloc_modules * sizeof(*dc->modules));
|
||||
}
|
||||
if (!dc->modules)
|
||||
{
|
||||
dc->alloc_modules = dc->num_modules = 0;
|
||||
return FALSE;
|
||||
}
|
||||
if (is_elf ||
|
||||
!GetModuleFileNameExW(dc->hProcess, (HMODULE)base,
|
||||
dc->modules[dc->num_modules - 1].name,
|
||||
sizeof(dc->modules[dc->num_modules - 1].name) / sizeof(WCHAR)))
|
||||
lstrcpynW(dc->modules[dc->num_modules - 1].name, name,
|
||||
sizeof(dc->modules[dc->num_modules - 1].name) / sizeof(WCHAR));
|
||||
dc->modules[dc->num_modules - 1].base = base;
|
||||
dc->modules[dc->num_modules - 1].size = size;
|
||||
dc->modules[dc->num_modules - 1].timestamp = timestamp;
|
||||
dc->modules[dc->num_modules - 1].checksum = checksum;
|
||||
dc->modules[dc->num_modules - 1].is_elf = is_elf;
|
||||
!GetModuleFileNameExW(dc->hProcess, (HMODULE)(DWORD_PTR)base,
|
||||
dc->modules[dc->num_modules].name,
|
||||
sizeof(dc->modules[dc->num_modules].name) / sizeof(WCHAR)))
|
||||
lstrcpynW(dc->modules[dc->num_modules].name, name,
|
||||
sizeof(dc->modules[dc->num_modules].name) / sizeof(WCHAR));
|
||||
dc->modules[dc->num_modules].base = base;
|
||||
dc->modules[dc->num_modules].size = size;
|
||||
dc->modules[dc->num_modules].timestamp = timestamp;
|
||||
dc->modules[dc->num_modules].checksum = checksum;
|
||||
dc->modules[dc->num_modules].is_elf = is_elf;
|
||||
dc->num_modules++;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -284,13 +262,13 @@ static BOOL add_module(struct dump_context* dc, const WCHAR* name,
|
|||
static BOOL WINAPI fetch_pe_module_info_cb(PCWSTR name, DWORD64 base, ULONG size,
|
||||
PVOID user)
|
||||
{
|
||||
struct dump_context* dc = (struct dump_context*)user;
|
||||
struct dump_context* dc = 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,
|
||||
add_module(user, name, base, size,
|
||||
nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum,
|
||||
FALSE);
|
||||
return TRUE;
|
||||
|
@ -304,7 +282,7 @@ static BOOL WINAPI fetch_pe_module_info_cb(PCWSTR name, DWORD64 base, ULONG size
|
|||
static BOOL fetch_elf_module_info_cb(const WCHAR* name, unsigned long base,
|
||||
void* user)
|
||||
{
|
||||
struct dump_context* dc = (struct dump_context*)user;
|
||||
struct dump_context* dc = user;
|
||||
DWORD rbase, size, checksum;
|
||||
|
||||
/* FIXME: there's no relevant timestamp on ELF modules */
|
||||
|
@ -318,6 +296,27 @@ static BOOL fetch_elf_module_info_cb(const WCHAR* name, unsigned long base,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* fetch_macho_module_info_cb
|
||||
*
|
||||
* Callback for accumulating in dump_context a Mach-O modules set
|
||||
*/
|
||||
static BOOL fetch_macho_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 Mach-O modules */
|
||||
/* NB: if we have a non-null base from the live-target use it. If we have
|
||||
* a null base, then grab its base address from Mach-O file.
|
||||
*/
|
||||
if (!macho_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_modules_info(struct dump_context* dc)
|
||||
{
|
||||
EnumerateLoadedModulesW64(dc->hProcess, fetch_pe_module_info_cb, dc);
|
||||
|
@ -327,6 +326,7 @@ static void fetch_modules_info(struct dump_context* dc)
|
|||
* a given application in a post mortem debugging condition.
|
||||
*/
|
||||
elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc);
|
||||
macho_enum_modules(dc->hProcess, fetch_macho_module_info_cb, dc);
|
||||
}
|
||||
|
||||
static void fetch_module_versioninfo(LPCWSTR filename, VS_FIXEDFILEINFO* ffi)
|
||||
|
@ -361,18 +361,25 @@ static void fetch_module_versioninfo(LPCWSTR filename, VS_FIXEDFILEINFO* ffi)
|
|||
*/
|
||||
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->alloc_mem = 32;
|
||||
dc->mem = HeapAlloc(GetProcessHeap(), 0, dc->alloc_mem * sizeof(*dc->mem));
|
||||
}
|
||||
else if (dc->num_mem >= dc->alloc_mem)
|
||||
{
|
||||
dc->alloc_mem *= 2;
|
||||
dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem,
|
||||
dc->alloc_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;
|
||||
dc->mem[dc->num_mem].base = base;
|
||||
dc->mem[dc->num_mem].size = size;
|
||||
dc->mem[dc->num_mem].rva = rva;
|
||||
dc->num_mem++;
|
||||
}
|
||||
else dc->num_mem = 0;
|
||||
else dc->num_mem = dc->alloc_mem = 0;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
@ -394,7 +401,7 @@ static void writeat(struct dump_context* dc, RVA rva, const void* data, unsigned
|
|||
* 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)
|
||||
static void append(struct dump_context* dc, const void* data, unsigned size)
|
||||
{
|
||||
writeat(dc, dc->rva, data, size);
|
||||
dc->rva += size;
|
||||
|
@ -683,7 +690,7 @@ static unsigned dump_threads(struct dump_context* dc,
|
|||
{
|
||||
MINIDUMP_THREAD mdThd;
|
||||
MINIDUMP_THREAD_LIST mdThdList;
|
||||
unsigned i;
|
||||
unsigned i, sz;
|
||||
RVA rva_base;
|
||||
DWORD flags_out;
|
||||
CONTEXT ctx;
|
||||
|
@ -691,8 +698,7 @@ static unsigned dump_threads(struct dump_context* dc,
|
|||
mdThdList.NumberOfThreads = 0;
|
||||
|
||||
rva_base = dc->rva;
|
||||
dc->rva += sizeof(mdThdList.NumberOfThreads) +
|
||||
dc->spi->dwThreadCount * sizeof(mdThd);
|
||||
dc->rva += sz = sizeof(mdThdList.NumberOfThreads) + dc->spi->dwThreadCount * sizeof(mdThd);
|
||||
|
||||
for (i = 0; i < dc->spi->dwThreadCount; i++)
|
||||
{
|
||||
|
@ -713,7 +719,7 @@ static unsigned dump_threads(struct dump_context* dc,
|
|||
cbin.ProcessId = dc->pid;
|
||||
cbin.ProcessHandle = dc->hProcess;
|
||||
cbin.CallbackType = ThreadCallback;
|
||||
cbin.u.Thread.ThreadId = dc->spi->ti[i].dwThreadID;
|
||||
cbin.u.Thread.ThreadId = HandleToUlong(dc->spi->ti[i].ClientId.UniqueThread);
|
||||
cbin.u.Thread.ThreadHandle = 0; /* FIXME */
|
||||
cbin.u.Thread.Context = ctx;
|
||||
cbin.u.Thread.SizeOfContext = sizeof(CONTEXT);
|
||||
|
@ -760,7 +766,7 @@ static unsigned dump_threads(struct dump_context* dc,
|
|||
writeat(dc, rva_base,
|
||||
&mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads));
|
||||
|
||||
return dc->rva - rva_base;
|
||||
return sz;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
@ -795,7 +801,7 @@ static unsigned dump_memory_info(struct dump_context* dc)
|
|||
{
|
||||
len = min(dc->mem[i].size - pos, sizeof(tmp));
|
||||
if (ReadProcessMemory(dc->hProcess,
|
||||
(void*)(dc->mem[i].base + pos),
|
||||
(void*)(DWORD_PTR)(dc->mem[i].base + pos),
|
||||
tmp, len, NULL))
|
||||
WriteFile(dc->hFile, tmp, len, &written, NULL);
|
||||
}
|
||||
|
@ -847,10 +853,12 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
|
|||
dc.pid = pid;
|
||||
dc.modules = NULL;
|
||||
dc.num_modules = 0;
|
||||
dc.alloc_modules = 0;
|
||||
dc.cb = CallbackParam;
|
||||
dc.type = DumpType;
|
||||
dc.mem = NULL;
|
||||
dc.num_mem = 0;
|
||||
dc.alloc_mem = 0;
|
||||
dc.rva = 0;
|
||||
|
||||
if (!fetch_processes_info(&dc)) return FALSE;
|
||||
|
@ -973,7 +981,7 @@ BOOL WINAPI MiniDumpReadDumpStream(PVOID base, ULONG str_idx,
|
|||
PMINIDUMP_DIRECTORY* pdir,
|
||||
PVOID* stream, ULONG* size)
|
||||
{
|
||||
MINIDUMP_HEADER* mdHead = (MINIDUMP_HEADER*)base;
|
||||
MINIDUMP_HEADER* mdHead = base;
|
||||
|
||||
if (mdHead->Signature == MINIDUMP_SIGNATURE)
|
||||
{
|
||||
|
@ -985,9 +993,9 @@ BOOL WINAPI MiniDumpReadDumpStream(PVOID base, ULONG str_idx,
|
|||
{
|
||||
if (dir->StreamType == str_idx)
|
||||
{
|
||||
*pdir = dir;
|
||||
*stream = (char*)base + dir->Location.Rva;
|
||||
*size = dir->Location.DataSize;
|
||||
if (pdir) *pdir = dir;
|
||||
if (stream) *stream = (char*)base + dir->Location.Rva;
|
||||
if (size) *size = dir->Location.DataSize;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,10 +35,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
|||
const WCHAR S_ElfW[] = {'<','e','l','f','>','\0'};
|
||||
const WCHAR S_WineLoaderW[] = {'<','w','i','n','e','-','l','o','a','d','e','r','>','\0'};
|
||||
static const WCHAR S_DotSoW[] = {'.','s','o','\0'};
|
||||
static const WCHAR S_DotDylibW[] = {'.','d','y','l','i','b','\0'};
|
||||
static const WCHAR S_DotPdbW[] = {'.','p','d','b','\0'};
|
||||
static const WCHAR S_DotDbgW[] = {'.','d','b','g','\0'};
|
||||
const WCHAR S_WinePThreadW[] = {'w','i','n','e','-','p','t','h','r','e','a','d','\0'};
|
||||
const WCHAR S_WineKThreadW[] = {'w','i','n','e','-','k','t','h','r','e','a','d','\0'};
|
||||
const WCHAR S_WineW[] = {'w','i','n','e',0};
|
||||
const WCHAR S_SlashW[] = {'/','\0'};
|
||||
|
||||
static const WCHAR S_AcmW[] = {'.','a','c','m','\0'};
|
||||
|
@ -87,9 +87,7 @@ static void module_fill_module(const WCHAR* in, WCHAR* out, size_t size)
|
|||
out[len] = '\0';
|
||||
if (len > 4 && (l = match_ext(out, len)))
|
||||
out[len - l] = '\0';
|
||||
else if (len > 12 &&
|
||||
(!strcmpiW(out + len - 12, S_WinePThreadW) ||
|
||||
!strcmpiW(out + len - 12, S_WineKThreadW)))
|
||||
else if (len > 4 && !strcmpiW(out + len - 4, S_WineW))
|
||||
lstrcpynW(out, S_WineLoaderW, size);
|
||||
else
|
||||
{
|
||||
|
@ -114,6 +112,7 @@ static const char* get_module_type(enum module_type type, BOOL virtual)
|
|||
{
|
||||
case DMT_ELF: return virtual ? "Virtual ELF" : "ELF";
|
||||
case DMT_PE: return virtual ? "Virtual PE" : "PE";
|
||||
case DMT_MACHO: return virtual ? "Virtual Mach-O" : "Mach-O";
|
||||
default: return "---";
|
||||
}
|
||||
}
|
||||
|
@ -123,20 +122,21 @@ static const char* get_module_type(enum module_type type, BOOL virtual)
|
|||
*/
|
||||
struct module* module_new(struct process* pcs, const WCHAR* name,
|
||||
enum module_type type, BOOL virtual,
|
||||
unsigned long mod_addr, unsigned long size,
|
||||
DWORD64 mod_addr, DWORD64 size,
|
||||
unsigned long stamp, unsigned long checksum)
|
||||
{
|
||||
struct module* module;
|
||||
|
||||
assert(type == DMT_ELF || type == DMT_PE);
|
||||
assert(type == DMT_ELF || type == DMT_PE || type == DMT_MACHO);
|
||||
if (!(module = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*module))))
|
||||
return NULL;
|
||||
|
||||
module->next = pcs->lmodules;
|
||||
pcs->lmodules = module;
|
||||
|
||||
TRACE("=> %s %08lx-%08lx %s\n",
|
||||
get_module_type(type, virtual), mod_addr, mod_addr + size,
|
||||
TRACE("=> %s %s-%s %s\n",
|
||||
get_module_type(type, virtual),
|
||||
wine_dbgstr_longlong(mod_addr), wine_dbgstr_longlong(mod_addr + size),
|
||||
debugstr_w(name));
|
||||
|
||||
pool_init(&module->pool, 65536);
|
||||
|
@ -169,7 +169,12 @@ struct module* module_new(struct process* pcs, const WCHAR* name,
|
|||
module->type = type;
|
||||
module->is_virtual = virtual ? TRUE : FALSE;
|
||||
module->sortlist_valid = FALSE;
|
||||
module->sorttab_size = 0;
|
||||
module->addr_sorttab = NULL;
|
||||
module->num_sorttab = 0;
|
||||
module->num_symbols = 0;
|
||||
|
||||
vector_init(&module->vsymt, sizeof(struct symt*), 128);
|
||||
/* FIXME: this seems a bit too high (on a per module basis)
|
||||
* need some statistics about this
|
||||
*/
|
||||
|
@ -188,7 +193,7 @@ struct module* module_new(struct process* pcs, const WCHAR* name,
|
|||
* module_find_by_name
|
||||
*
|
||||
*/
|
||||
struct module* module_find_by_name(const struct process* pcs, const WCHAR* name)
|
||||
static struct module* module_find_by_name(const struct process* pcs, const WCHAR* name)
|
||||
{
|
||||
struct module* module;
|
||||
|
||||
|
@ -238,7 +243,7 @@ struct module* module_is_already_loaded(const struct process* pcs, const WCHAR*
|
|||
* module_get_container
|
||||
*
|
||||
*/
|
||||
struct module* module_get_container(const struct process* pcs,
|
||||
static struct module* module_get_container(const struct process* pcs,
|
||||
const struct module* inner)
|
||||
{
|
||||
struct module* module;
|
||||
|
@ -319,6 +324,9 @@ BOOL module_get_debug(struct module_pair* pair)
|
|||
ret ? CBA_DEFERRED_SYMBOL_LOAD_COMPLETE : CBA_DEFERRED_SYMBOL_LOAD_FAILURE,
|
||||
&idslW64);
|
||||
break;
|
||||
case DMT_MACHO:
|
||||
ret = macho_load_debug_info(pair->effective, NULL);
|
||||
break;
|
||||
default:
|
||||
ret = FALSE;
|
||||
break;
|
||||
|
@ -344,7 +352,8 @@ struct module* module_find_by_addr(const struct process* pcs, unsigned long addr
|
|||
if (type == DMT_UNKNOWN)
|
||||
{
|
||||
if ((module = module_find_by_addr(pcs, addr, DMT_PE)) ||
|
||||
(module = module_find_by_addr(pcs, addr, DMT_ELF)))
|
||||
(module = module_find_by_addr(pcs, addr, DMT_ELF)) ||
|
||||
(module = module_find_by_addr(pcs, addr, DMT_MACHO)))
|
||||
return module;
|
||||
}
|
||||
else
|
||||
|
@ -361,13 +370,13 @@ struct module* module_find_by_addr(const struct process* pcs, unsigned long addr
|
|||
}
|
||||
|
||||
/******************************************************************
|
||||
* module_is_elf_container_loaded
|
||||
* module_is_container_loaded
|
||||
*
|
||||
* checks whether the ELF container, for a (supposed) PE builtin is
|
||||
* checks whether the native container, for a (supposed) PE builtin is
|
||||
* already loaded
|
||||
*/
|
||||
static BOOL module_is_elf_container_loaded(const struct process* pcs,
|
||||
const WCHAR* ImageName, DWORD base)
|
||||
static BOOL module_is_container_loaded(const struct process* pcs,
|
||||
const WCHAR* ImageName, DWORD64 base)
|
||||
{
|
||||
size_t len;
|
||||
struct module* module;
|
||||
|
@ -379,7 +388,7 @@ static BOOL module_is_elf_container_loaded(const struct process* pcs,
|
|||
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (module->type == DMT_ELF &&
|
||||
if ((module->type == DMT_ELF || module->type == DMT_MACHO) &&
|
||||
base >= module->module.BaseOfImage &&
|
||||
base < module->module.BaseOfImage + module->module.ImageSize)
|
||||
{
|
||||
|
@ -419,8 +428,17 @@ enum module_type module_get_type_by_name(const WCHAR* name)
|
|||
} while (len);
|
||||
|
||||
/* check for terminating .so or .so.[digit] */
|
||||
/* FIXME: Can't rely solely on extension; have to check magic or
|
||||
* stop using .so on Mac OS X. For now, base on platform. */
|
||||
if (len > 3 && !memcmp(name + len - 3, S_DotSoW, 3))
|
||||
#ifdef __APPLE__
|
||||
return DMT_MACHO;
|
||||
#else
|
||||
return DMT_ELF;
|
||||
#endif
|
||||
|
||||
if (len > 6 && !strncmpiW(name + len - 6, S_DotDylibW, 6))
|
||||
return DMT_MACHO;
|
||||
|
||||
if (len > 4 && !strncmpiW(name + len - 4, S_DotPdbW, 4))
|
||||
return DMT_PDB;
|
||||
|
@ -428,16 +446,27 @@ enum module_type module_get_type_by_name(const WCHAR* name)
|
|||
if (len > 4 && !strncmpiW(name + len - 4, S_DotDbgW, 4))
|
||||
return DMT_DBG;
|
||||
|
||||
/* wine-[kp]thread is also an ELF module */
|
||||
if (((len > 12 && name[len - 13] == '/') || len == 12) &&
|
||||
(!strncmpiW(name + len - 12, S_WinePThreadW, 12) ||
|
||||
!strncmpiW(name + len - 12, S_WineKThreadW, 12)))
|
||||
/* wine is also a native module (Mach-O on Mac OS X, ELF elsewhere) */
|
||||
if (((len > 4 && name[len - 5] == '/') || len == 4) && !strcmpiW(name + len - 4, S_WineW))
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
return DMT_MACHO;
|
||||
#else
|
||||
return DMT_ELF;
|
||||
#endif
|
||||
}
|
||||
return DMT_PE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* refresh_module_list
|
||||
*/
|
||||
static BOOL refresh_module_list(struct process* pcs)
|
||||
{
|
||||
/* force transparent ELF and Mach-O loading / unloading */
|
||||
return elf_synchronize_module_list(pcs) || macho_synchronize_module_list(pcs);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymLoadModule (DBGHELP.@)
|
||||
*/
|
||||
|
@ -508,8 +537,9 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam
|
|||
|
||||
if (Flags & SLMFLAG_VIRTUAL)
|
||||
{
|
||||
if (!wImageName) return FALSE;
|
||||
module = module_new(pcs, wImageName, module_get_type_by_name(wImageName),
|
||||
TRUE, (DWORD)BaseOfDll, SizeOfDll, 0, 0);
|
||||
TRUE, BaseOfDll, SizeOfDll, 0, 0);
|
||||
if (!module) return FALSE;
|
||||
if (wModuleName) module_set_module(module, wModuleName);
|
||||
module->module.SymType = SymVirtual;
|
||||
|
@ -519,8 +549,7 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam
|
|||
if (Flags & ~(SLMFLAG_VIRTUAL))
|
||||
FIXME("Unsupported Flags %08x for %s\n", Flags, debugstr_w(wImageName));
|
||||
|
||||
/* force transparent ELF loading / unloading */
|
||||
elf_synchronize_module_list(pcs);
|
||||
refresh_module_list(pcs);
|
||||
|
||||
/* this is a Wine extension to the API just to redo the synchronisation */
|
||||
if (!wImageName && !hFile) return 0;
|
||||
|
@ -531,7 +560,7 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam
|
|||
if (wImageName)
|
||||
{
|
||||
module = module_is_already_loaded(pcs, wImageName);
|
||||
if (!module && module_is_elf_container_loaded(pcs, wImageName, BaseOfDll))
|
||||
if (!module && module_is_container_loaded(pcs, wImageName, BaseOfDll))
|
||||
{
|
||||
/* force the loading of DLL as builtin */
|
||||
module = pe_load_builtin_module(pcs, wImageName, BaseOfDll, SizeOfDll);
|
||||
|
@ -540,11 +569,22 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam
|
|||
if (!module)
|
||||
{
|
||||
/* otherwise, try a regular PE module */
|
||||
if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll)))
|
||||
if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll)) &&
|
||||
wImageName)
|
||||
{
|
||||
/* and finally and ELF module */
|
||||
if (module_get_type_by_name(wImageName) == DMT_ELF)
|
||||
module = elf_load_module(pcs, wImageName, BaseOfDll);
|
||||
/* and finally an ELF or Mach-O module */
|
||||
switch (module_get_type_by_name(wImageName))
|
||||
{
|
||||
case DMT_ELF:
|
||||
module = elf_load_module(pcs, wImageName, BaseOfDll);
|
||||
break;
|
||||
case DMT_MACHO:
|
||||
module = macho_load_module(pcs, wImageName, BaseOfDll);
|
||||
break;
|
||||
default:
|
||||
/* Ignored */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!module)
|
||||
|
@ -558,7 +598,8 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam
|
|||
*/
|
||||
if (wModuleName)
|
||||
module_set_module(module, wModuleName);
|
||||
lstrcpynW(module->module.ImageName, wImageName,
|
||||
if (wImageName)
|
||||
lstrcpynW(module->module.ImageName, wImageName,
|
||||
sizeof(module->module.ImageName) / sizeof(WCHAR));
|
||||
|
||||
return module->module.BaseOfImage;
|
||||
|
@ -715,7 +756,8 @@ BOOL WINAPI SymEnumerateModulesW64(HANDLE hProcess,
|
|||
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (!(dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES) && module->type == DMT_ELF)
|
||||
if (!(dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES) &&
|
||||
(module->type == DMT_ELF || module->type == DMT_MACHO))
|
||||
continue;
|
||||
if (!EnumModulesCallback(module->module.ModuleName,
|
||||
module->module.BaseOfImage, UserContext))
|
||||
|
@ -1008,7 +1050,9 @@ DWORD64 WINAPI SymGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr)
|
|||
void module_reset_debug_info(struct module* module)
|
||||
{
|
||||
module->sortlist_valid = TRUE;
|
||||
module->sorttab_size = 0;
|
||||
module->addr_sorttab = NULL;
|
||||
module->num_sorttab = module->num_symbols = 0;
|
||||
hash_table_destroy(&module->ht_symbols);
|
||||
module->ht_symbols.num_buckets = 0;
|
||||
module->ht_symbols.buckets = NULL;
|
||||
|
@ -1020,3 +1064,17 @@ void module_reset_debug_info(struct module* module)
|
|||
module->sources_used = module->sources_alloc = 0;
|
||||
module->sources = NULL;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymRefreshModuleList (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI SymRefreshModuleList(HANDLE hProcess)
|
||||
{
|
||||
struct process* pcs;
|
||||
|
||||
TRACE("(%p)\n", hProcess);
|
||||
|
||||
if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
|
||||
|
||||
return refresh_module_list(pcs);
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ static void dump(const void* ptr, unsigned len)
|
|||
unsigned int i, j;
|
||||
char msg[128];
|
||||
const char* hexof = "0123456789abcdef";
|
||||
const BYTE* x = (const BYTE*)ptr;
|
||||
const BYTE* x = ptr;
|
||||
|
||||
for (i = 0; i < len; i += 16)
|
||||
{
|
||||
|
@ -95,7 +95,7 @@ static void dump(const void* ptr, unsigned len)
|
|||
* Process CodeView type information.
|
||||
*/
|
||||
|
||||
#define MAX_BUILTIN_TYPES 0x0480
|
||||
#define MAX_BUILTIN_TYPES 0x0604
|
||||
#define FIRST_DEFINABLE_TYPE 0x1000
|
||||
|
||||
static struct symt* cv_basic_types[MAX_BUILTIN_TYPES];
|
||||
|
@ -113,6 +113,7 @@ static struct cv_defined_module*cv_current_module;
|
|||
|
||||
static void codeview_init_basic_types(struct module* module)
|
||||
{
|
||||
struct symt_udt* udt;
|
||||
/*
|
||||
* These are the common builtin types that are used by VC++.
|
||||
*/
|
||||
|
@ -169,6 +170,12 @@ static void codeview_init_basic_types(struct module* module)
|
|||
cv_basic_types[T_32PINT8] = &symt_new_pointer(module, cv_basic_types[T_INT8])->symt;
|
||||
cv_basic_types[T_32PUINT8] = &symt_new_pointer(module, cv_basic_types[T_UINT8])->symt;
|
||||
cv_basic_types[T_32PHRESULT]= &symt_new_pointer(module, cv_basic_types[T_HRESULT])->symt;
|
||||
|
||||
/* The .pdb file can refer to 64 bit pointers values even on 32 bits applications. */
|
||||
udt = symt_new_udt(module, "PVOID64", 8, UdtStruct);
|
||||
symt_add_udt_element(module, udt, "ptr64_low", cv_basic_types[T_LONG], 0, 32);
|
||||
symt_add_udt_element(module, udt, "ptr64_high", cv_basic_types[T_LONG], 32, 32);
|
||||
cv_basic_types[0x603]= &udt->symt;
|
||||
}
|
||||
|
||||
static int leaf_as_variant(VARIANT* v, const unsigned short int* leaf)
|
||||
|
@ -486,18 +493,23 @@ static int codeview_add_type(unsigned int typeno, struct symt* dt)
|
|||
if ((typeno >> 24) != 0)
|
||||
FIXME("No module index while inserting type-id assumption is wrong %x\n",
|
||||
typeno);
|
||||
while (typeno - FIRST_DEFINABLE_TYPE >= cv_current_module->num_defined_types)
|
||||
if (typeno - FIRST_DEFINABLE_TYPE >= cv_current_module->num_defined_types)
|
||||
{
|
||||
cv_current_module->num_defined_types += 0x100;
|
||||
if (cv_current_module->defined_types)
|
||||
{
|
||||
cv_current_module->num_defined_types = max( cv_current_module->num_defined_types * 2,
|
||||
typeno - FIRST_DEFINABLE_TYPE + 1 );
|
||||
cv_current_module->defined_types = HeapReAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY, cv_current_module->defined_types,
|
||||
cv_current_module->num_defined_types * sizeof(struct symt*));
|
||||
}
|
||||
else
|
||||
{
|
||||
cv_current_module->num_defined_types = max( 256, typeno - FIRST_DEFINABLE_TYPE + 1 );
|
||||
cv_current_module->defined_types = HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
cv_current_module->num_defined_types * sizeof(struct symt*));
|
||||
|
||||
}
|
||||
if (cv_current_module->defined_types == NULL) return FALSE;
|
||||
}
|
||||
if (cv_current_module->defined_types[typeno - FIRST_DEFINABLE_TYPE])
|
||||
|
@ -581,15 +593,8 @@ static struct symt* codeview_add_type_array(struct codeview_type_parse* ctp,
|
|||
{
|
||||
struct symt* elem = codeview_fetch_type(ctp, elemtype, FALSE);
|
||||
struct symt* index = codeview_fetch_type(ctp, indextype, FALSE);
|
||||
DWORD arr_max = 0;
|
||||
|
||||
if (elem)
|
||||
{
|
||||
DWORD64 elem_size;
|
||||
symt_get_info(elem, TI_GET_LENGTH, &elem_size);
|
||||
if (elem_size) arr_max = arr_len / (DWORD)elem_size;
|
||||
}
|
||||
return &symt_new_array(ctp->module, 0, arr_max, elem, index)->symt;
|
||||
return &symt_new_array(ctp->module, 0, -arr_len, elem, index)->symt;
|
||||
}
|
||||
|
||||
static int codeview_add_type_enum_field_list(struct module* module,
|
||||
|
@ -669,7 +674,7 @@ static void codeview_add_udt_element(struct codeview_type_parse* ctp,
|
|||
if (subtype)
|
||||
{
|
||||
DWORD64 elem_size = 0;
|
||||
symt_get_info(subtype, TI_GET_LENGTH, &elem_size);
|
||||
symt_get_info(ctp->module, subtype, TI_GET_LENGTH, &elem_size);
|
||||
symt_add_udt_element(ctp->module, symt, name, subtype,
|
||||
value << 3, (DWORD)elem_size << 3);
|
||||
}
|
||||
|
@ -1357,48 +1362,72 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B
|
|||
}
|
||||
|
||||
static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const BYTE* linetab, DWORD size,
|
||||
const char* strimage, DWORD strsize)
|
||||
const char* strimage, DWORD strsize)
|
||||
{
|
||||
DWORD offset;
|
||||
unsigned i;
|
||||
DWORD addr;
|
||||
const struct codeview_linetab2_block* lbh;
|
||||
const struct codeview_linetab2_file* fd;
|
||||
const struct codeview_linetab2* lt2;
|
||||
const struct codeview_linetab2* lt2_files = NULL;
|
||||
const struct codeview_lt2blk_lines* lines_blk;
|
||||
const struct codeview_linetab2_file*fd;
|
||||
unsigned source;
|
||||
struct symt_function* func;
|
||||
|
||||
if (*(const DWORD*)linetab != 0x000000f4) return;
|
||||
offset = *((const DWORD*)linetab + 1);
|
||||
|
||||
for (lbh = (const struct codeview_linetab2_block*)(linetab + 8 + offset);
|
||||
(const BYTE*)lbh < linetab + size;
|
||||
lbh = (const struct codeview_linetab2_block*)((const char*)lbh + 8 + lbh->size_of_block))
|
||||
/* locate LT2_FILES_BLOCK (if any) */
|
||||
lt2 = (const struct codeview_linetab2*)linetab;
|
||||
while ((const BYTE*)(lt2 + 1) < linetab + size)
|
||||
{
|
||||
if (lbh->header != 0x000000f2)
|
||||
/* FIXME: should also check that whole lbh fits in linetab + size */
|
||||
if (lt2->header == LT2_FILES_BLOCK)
|
||||
{
|
||||
TRACE("block end %x\n", lbh->header);
|
||||
lt2_files = lt2;
|
||||
break;
|
||||
}
|
||||
addr = codeview_get_address(msc_dbg, lbh->seg, lbh->start);
|
||||
TRACE("block from %04x:%08x #%x (%x lines)\n",
|
||||
lbh->seg, lbh->start, lbh->size, lbh->nlines);
|
||||
fd = (const struct codeview_linetab2_file*)(linetab + 8 + lbh->file_offset);
|
||||
/* FIXME: should check that string is within strimage + strsize */
|
||||
source = source_new(msc_dbg->module, NULL, strimage + fd->offset);
|
||||
func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr);
|
||||
/* FIXME: at least labels support line numbers */
|
||||
if (!func || func->symt.tag != SymTagFunction)
|
||||
lt2 = codeview_linetab2_next_block(lt2);
|
||||
}
|
||||
if (!lt2_files)
|
||||
{
|
||||
TRACE("No LT2_FILES_BLOCK found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lt2 = (const struct codeview_linetab2*)linetab;
|
||||
while ((const BYTE*)(lt2 + 1) < linetab + size)
|
||||
{
|
||||
/* FIXME: should also check that whole lines_blk fits in linetab + size */
|
||||
switch (lt2->header)
|
||||
{
|
||||
WARN("--not a func at %04x:%08x %x tag=%d\n",
|
||||
lbh->seg, lbh->start, addr, func ? func->symt.tag : -1);
|
||||
case LT2_LINES_BLOCK:
|
||||
lines_blk = (const struct codeview_lt2blk_lines*)lt2;
|
||||
/* FIXME: should check that file_offset is within the LT2_FILES_BLOCK we've seen */
|
||||
addr = codeview_get_address(msc_dbg, lines_blk->seg, lines_blk->start);
|
||||
TRACE("block from %04x:%08x #%x (%x lines)\n",
|
||||
lines_blk->seg, lines_blk->start, lines_blk->size, lines_blk->nlines);
|
||||
fd = (const struct codeview_linetab2_file*)((const char*)lt2_files + 8 + lines_blk->file_offset);
|
||||
/* FIXME: should check that string is within strimage + strsize */
|
||||
source = source_new(msc_dbg->module, NULL, strimage + fd->offset);
|
||||
func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr);
|
||||
/* FIXME: at least labels support line numbers */
|
||||
if (!func || func->symt.tag != SymTagFunction)
|
||||
{
|
||||
WARN("--not a func at %04x:%08x %x tag=%d\n",
|
||||
lines_blk->seg, lines_blk->start, addr, func ? func->symt.tag : -1);
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < lines_blk->nlines; i++)
|
||||
{
|
||||
symt_add_func_line(msc_dbg->module, func, source,
|
||||
lines_blk->l[i].lineno ^ 0x80000000,
|
||||
lines_blk->l[i].offset);
|
||||
}
|
||||
break;
|
||||
case LT2_FILES_BLOCK: /* skip */
|
||||
break;
|
||||
default:
|
||||
TRACE("Block end %x\n", lt2->header);
|
||||
lt2 = (const struct codeview_linetab2*)((const char*)linetab + size);
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < lbh->nlines; i++)
|
||||
{
|
||||
symt_add_func_line(msc_dbg->module, func, source,
|
||||
lbh->l[i].lineno ^ 0x80000000, lbh->l[i].offset - lbh->start);
|
||||
}
|
||||
lt2 = codeview_linetab2_next_block(lt2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1897,8 +1926,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT
|
|||
{
|
||||
symt_new_public(msc_dbg->module, compiland,
|
||||
terminate_string(&sym->data_v1.p_name),
|
||||
codeview_get_address(msc_dbg, sym->data_v1.segment, sym->data_v1.offset),
|
||||
1, TRUE /* FIXME */, TRUE /* FIXME */);
|
||||
codeview_get_address(msc_dbg, sym->data_v1.segment, sym->data_v1.offset), 1);
|
||||
}
|
||||
break;
|
||||
case S_PUB_V2: /* FIXME is this really a 'data_v2' structure ?? */
|
||||
|
@ -1906,8 +1934,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT
|
|||
{
|
||||
symt_new_public(msc_dbg->module, compiland,
|
||||
terminate_string(&sym->data_v2.p_name),
|
||||
codeview_get_address(msc_dbg, sym->data_v2.segment, sym->data_v2.offset),
|
||||
1, TRUE /* FIXME */, TRUE /* FIXME */);
|
||||
codeview_get_address(msc_dbg, sym->data_v2.segment, sym->data_v2.offset), 1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1916,8 +1943,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT
|
|||
{
|
||||
symt_new_public(msc_dbg->module, compiland,
|
||||
sym->data_v3.name,
|
||||
codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset),
|
||||
1, FALSE /* FIXME */, FALSE);
|
||||
codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), 1);
|
||||
}
|
||||
break;
|
||||
case S_PUB_FUNC1_V3:
|
||||
|
@ -1928,8 +1954,7 @@ static int codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYT
|
|||
{
|
||||
symt_new_public(msc_dbg->module, compiland,
|
||||
sym->data_v3.name,
|
||||
codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset),
|
||||
1, TRUE /* FIXME */, TRUE);
|
||||
codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), 1);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
@ -2150,7 +2175,7 @@ static void pdb_convert_symbol_file(const PDB_SYMBOLS* symbols,
|
|||
{
|
||||
if (symbols->version < 19970000)
|
||||
{
|
||||
const PDB_SYMBOL_FILE *sym_file = (const PDB_SYMBOL_FILE*)image;
|
||||
const PDB_SYMBOL_FILE *sym_file = image;
|
||||
memset(sfile, 0, sizeof(*sfile));
|
||||
sfile->file = sym_file->file;
|
||||
sfile->range.index = sym_file->range.index;
|
||||
|
@ -2217,7 +2242,8 @@ static void pdb_process_types(const struct msc_debug_info* msc_dbg,
|
|||
case 19950410: /* VC 4.0 */
|
||||
case 19951122:
|
||||
case 19961031: /* VC 5.0 / 6.0 */
|
||||
case 19990903:
|
||||
case 19990903: /* VC 7.0 */
|
||||
case 20040203: /* VC 8.0 */
|
||||
break;
|
||||
default:
|
||||
ERR("-Unknown type info version %d\n", types.version);
|
||||
|
@ -2385,7 +2411,7 @@ static void pdb_process_symbol_imports(const struct process* pcs,
|
|||
imp = (const PDB_SYMBOL_IMPORT*)((const char*)symbols_image + sizeof(PDB_SYMBOLS) +
|
||||
symbols->module_size + symbols->offset_size +
|
||||
symbols->hash_size + symbols->srcmodule_size);
|
||||
first = (const char*)imp;
|
||||
first = imp;
|
||||
last = (const char*)imp + symbols->pdbimport_size;
|
||||
while (imp < (const PDB_SYMBOL_IMPORT*)last)
|
||||
{
|
||||
|
@ -2524,7 +2550,7 @@ static BOOL pdb_process_internal(const struct process* pcs,
|
|||
}
|
||||
file_name = (const char*)file + size;
|
||||
file_name += strlen(file_name) + 1;
|
||||
file = (BYTE*)((DWORD)(file_name + strlen(file_name) + 1 + 3) & ~3);
|
||||
file = (BYTE*)((DWORD_PTR)(file_name + strlen(file_name) + 1 + 3) & ~3);
|
||||
}
|
||||
/* finish the remaining public and global information */
|
||||
if (globalimage)
|
||||
|
|
|
@ -234,7 +234,7 @@ static BOOL do_searchW(PCWSTR file, PWSTR buffer, BOOL recurse,
|
|||
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))
|
||||
else if (SymMatchFileNameW(buffer, file, NULL, NULL))
|
||||
{
|
||||
if (!cb || cb(buffer, user)) found = TRUE;
|
||||
}
|
||||
|
@ -340,13 +340,13 @@ struct sffip
|
|||
*/
|
||||
static BOOL CALLBACK sffip_cb(PCWSTR buffer, PVOID user)
|
||||
{
|
||||
struct sffip* s = (struct sffip*)user;
|
||||
struct sffip* s = user;
|
||||
|
||||
if (!s->cb) return TRUE;
|
||||
/* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
|
||||
* convention to stop/continue enumeration. sigh.
|
||||
*/
|
||||
return !(s->cb)((WCHAR*)buffer, s->user);
|
||||
return !(s->cb)(buffer, s->user);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
@ -461,7 +461,7 @@ struct module_find
|
|||
*/
|
||||
static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user)
|
||||
{
|
||||
struct module_find* mf = (struct module_find*)user;
|
||||
struct module_find* mf = user;
|
||||
DWORD size, checksum, timestamp;
|
||||
unsigned matched = 0;
|
||||
|
||||
|
@ -522,6 +522,21 @@ static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user)
|
|||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case DMT_MACHO:
|
||||
if (macho_fetch_file_info(buffer, 0, &size, &checksum))
|
||||
{
|
||||
matched++;
|
||||
if (checksum == mf->dw1) matched++;
|
||||
else
|
||||
WARN("Found %s, but wrong checksums: %08x %08x\n",
|
||||
debugstr_w(buffer), checksum, mf->dw1);
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN("Couldn't read %s\n", debugstr_w(buffer));
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case DMT_PDB:
|
||||
{
|
||||
struct pdb_lookup pdb_lookup;
|
||||
|
@ -580,7 +595,7 @@ static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user)
|
|||
if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
|
||||
{
|
||||
const IMAGE_SEPARATE_DEBUG_HEADER* hdr;
|
||||
hdr = (const IMAGE_SEPARATE_DEBUG_HEADER*)mapping;
|
||||
hdr = mapping;
|
||||
|
||||
if (hdr->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE)
|
||||
{
|
||||
|
|
|
@ -35,6 +35,141 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
/******************************************************************
|
||||
* pe_locate_with_coff_symbol_table
|
||||
*
|
||||
* Use the COFF symbol table (if any) from the IMAGE_FILE_HEADER to set the absolute address
|
||||
* of global symbols.
|
||||
* Mingw32 requires this for stabs debug information as address for global variables isn't filled in
|
||||
* (this is similar to what is done in elf_module.c when using the .symtab ELF section)
|
||||
*/
|
||||
static BOOL pe_locate_with_coff_symbol_table(struct module* module, IMAGE_NT_HEADERS* nth, void* mapping)
|
||||
{
|
||||
const IMAGE_SYMBOL* isym;
|
||||
int i, numsym, naux;
|
||||
const char* strtable;
|
||||
char tmp[9];
|
||||
const char* name;
|
||||
struct hash_table_iter hti;
|
||||
void* ptr;
|
||||
struct symt_data* sym;
|
||||
const IMAGE_SECTION_HEADER* sect;
|
||||
|
||||
numsym = nth->FileHeader.NumberOfSymbols;
|
||||
if (!nth->FileHeader.PointerToSymbolTable || !numsym)
|
||||
return TRUE;
|
||||
isym = (const IMAGE_SYMBOL*)((char*)mapping + nth->FileHeader.PointerToSymbolTable);
|
||||
/* FIXME: no way to get strtable size */
|
||||
strtable = (const char*)&isym[numsym];
|
||||
sect = IMAGE_FIRST_SECTION(nth);
|
||||
|
||||
for (i = 0; i < numsym; i+= naux, isym += naux)
|
||||
{
|
||||
if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
|
||||
isym->SectionNumber > 0 && isym->SectionNumber <= nth->FileHeader.NumberOfSections)
|
||||
{
|
||||
if (isym->N.Name.Short)
|
||||
{
|
||||
name = memcpy(tmp, isym->N.ShortName, 8);
|
||||
tmp[8] = '\0';
|
||||
}
|
||||
else name = strtable + isym->N.Name.Long;
|
||||
if (name[0] == '_') name++;
|
||||
hash_table_iter_init(&module->ht_symbols, &hti, name);
|
||||
while ((ptr = hash_table_iter_up(&hti)))
|
||||
{
|
||||
sym = GET_ENTRY(ptr, struct symt_data, hash_elt);
|
||||
if (sym->symt.tag == SymTagData &&
|
||||
(sym->kind == DataIsGlobal || sym->kind == DataIsFileStatic) &&
|
||||
!strcmp(sym->hash_elt.name, name))
|
||||
{
|
||||
TRACE("Changing absolute address for %d.%s: %lx -> %s\n",
|
||||
isym->SectionNumber, name, sym->u.var.offset,
|
||||
wine_dbgstr_longlong(module->module.BaseOfImage +
|
||||
sect[isym->SectionNumber - 1].VirtualAddress + isym->Value));
|
||||
sym->u.var.offset = module->module.BaseOfImage +
|
||||
sect[isym->SectionNumber - 1].VirtualAddress + isym->Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
naux = isym->NumberOfAuxSymbols + 1;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* pe_load_coff_symbol_table
|
||||
*
|
||||
* Load public symbols out of the COFF symbol table (if any).
|
||||
*/
|
||||
static BOOL pe_load_coff_symbol_table(struct module* module, IMAGE_NT_HEADERS* nth, void* mapping)
|
||||
{
|
||||
const IMAGE_SYMBOL* isym;
|
||||
int i, numsym, naux;
|
||||
const char* strtable;
|
||||
char tmp[9];
|
||||
const char* name;
|
||||
const char* lastfilename = NULL;
|
||||
struct symt_compiland* compiland = NULL;
|
||||
const IMAGE_SECTION_HEADER* sect;
|
||||
|
||||
numsym = nth->FileHeader.NumberOfSymbols;
|
||||
if (!nth->FileHeader.PointerToSymbolTable || !numsym)
|
||||
return TRUE;
|
||||
isym = (const IMAGE_SYMBOL*)((char*)mapping + nth->FileHeader.PointerToSymbolTable);
|
||||
/* FIXME: no way to get strtable size */
|
||||
strtable = (const char*)&isym[numsym];
|
||||
sect = IMAGE_FIRST_SECTION(nth);
|
||||
|
||||
for (i = 0; i < numsym; i+= naux, isym += naux)
|
||||
{
|
||||
if (isym->StorageClass == IMAGE_SYM_CLASS_FILE)
|
||||
{
|
||||
lastfilename = (const char*)(isym + 1);
|
||||
compiland = NULL;
|
||||
}
|
||||
if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
|
||||
isym->SectionNumber > 0 && isym->SectionNumber <= nth->FileHeader.NumberOfSections)
|
||||
{
|
||||
if (isym->N.Name.Short)
|
||||
{
|
||||
name = memcpy(tmp, isym->N.ShortName, 8);
|
||||
tmp[8] = '\0';
|
||||
}
|
||||
else name = strtable + isym->N.Name.Long;
|
||||
if (name[0] == '_') name++;
|
||||
|
||||
if (!compiland && lastfilename)
|
||||
compiland = symt_new_compiland(module, 0,
|
||||
source_new(module, NULL, lastfilename));
|
||||
symt_new_public(module, compiland, name,
|
||||
module->module.BaseOfImage + sect[isym->SectionNumber - 1].VirtualAddress + isym->Value,
|
||||
1);
|
||||
}
|
||||
naux = isym->NumberOfAuxSymbols + 1;
|
||||
}
|
||||
module->module.SymType = SymCoff;
|
||||
module->module.LineNumbers = FALSE;
|
||||
module->module.GlobalSymbols = FALSE;
|
||||
module->module.TypeInfo = FALSE;
|
||||
module->module.SourceIndexed = FALSE;
|
||||
module->module.Publics = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void* pe_get_sect(IMAGE_NT_HEADERS* nth, void* mapping,
|
||||
IMAGE_SECTION_HEADER* sect)
|
||||
{
|
||||
return (sect) ? RtlImageRvaToVa(nth, mapping, sect->VirtualAddress, NULL) : NULL;
|
||||
}
|
||||
|
||||
static inline DWORD pe_get_sect_size(IMAGE_SECTION_HEADER* sect)
|
||||
{
|
||||
return (sect) ? sect->SizeOfRawData : 0;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* pe_load_stabs
|
||||
*
|
||||
|
@ -45,37 +180,85 @@ static BOOL pe_load_stabs(const struct process* pcs, struct module* module,
|
|||
void* mapping, IMAGE_NT_HEADERS* nth)
|
||||
{
|
||||
IMAGE_SECTION_HEADER* section;
|
||||
int i, stabsize = 0, stabstrsize = 0;
|
||||
unsigned int stabs = 0, stabstr = 0;
|
||||
IMAGE_SECTION_HEADER* sect_stabs = NULL;
|
||||
IMAGE_SECTION_HEADER* sect_stabstr = NULL;
|
||||
int i;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
section = (IMAGE_SECTION_HEADER*)
|
||||
((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
|
||||
for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
|
||||
{
|
||||
if (!strcasecmp((const char*)section->Name, ".stab"))
|
||||
{
|
||||
stabs = section->VirtualAddress;
|
||||
stabsize = section->SizeOfRawData;
|
||||
}
|
||||
else if (!strncasecmp((const char*)section->Name, ".stabstr", 8))
|
||||
{
|
||||
stabstr = section->VirtualAddress;
|
||||
stabstrsize = section->SizeOfRawData;
|
||||
}
|
||||
if (!strcasecmp((const char*)section->Name, ".stab")) sect_stabs = section;
|
||||
else if (!strncasecmp((const char*)section->Name, ".stabstr", 8)) sect_stabstr = section;
|
||||
}
|
||||
|
||||
if (stabstrsize && stabsize)
|
||||
if (sect_stabs && sect_stabstr)
|
||||
{
|
||||
ret = stabs_parse(module,
|
||||
module->module.BaseOfImage - nth->OptionalHeader.ImageBase,
|
||||
RtlImageRvaToVa(nth, mapping, stabs, NULL),
|
||||
stabsize,
|
||||
RtlImageRvaToVa(nth, mapping, stabstr, NULL),
|
||||
stabstrsize);
|
||||
ret = stabs_parse(module,
|
||||
module->module.BaseOfImage - nth->OptionalHeader.ImageBase,
|
||||
pe_get_sect(nth, mapping, sect_stabs), pe_get_sect_size(sect_stabs),
|
||||
pe_get_sect(nth, mapping, sect_stabstr), pe_get_sect_size(sect_stabstr),
|
||||
NULL, NULL);
|
||||
if (ret) pe_locate_with_coff_symbol_table(module, nth, mapping);
|
||||
}
|
||||
|
||||
TRACE("%s the STABS debug info\n", ret ? "successfully loaded" : "failed to load");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* pe_load_dwarf
|
||||
*
|
||||
* look for dwarf information in PE header (it's also a way for the mingw compiler
|
||||
* to provide its debugging information)
|
||||
*/
|
||||
static BOOL pe_load_dwarf(const struct process* pcs, struct module* module,
|
||||
void* mapping, IMAGE_NT_HEADERS* nth)
|
||||
{
|
||||
IMAGE_SECTION_HEADER* section;
|
||||
IMAGE_SECTION_HEADER* sect_debuginfo = NULL;
|
||||
IMAGE_SECTION_HEADER* sect_debugstr = NULL;
|
||||
IMAGE_SECTION_HEADER* sect_debugabbrev = NULL;
|
||||
IMAGE_SECTION_HEADER* sect_debugline = NULL;
|
||||
IMAGE_SECTION_HEADER* sect_debugloc = NULL;
|
||||
int i;
|
||||
const char* strtable;
|
||||
const char* sectname;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (nth->FileHeader.PointerToSymbolTable && nth->FileHeader.NumberOfSymbols)
|
||||
/* FIXME: no way to get strtable size */
|
||||
strtable = (const char*)mapping + nth->FileHeader.PointerToSymbolTable +
|
||||
nth->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL);
|
||||
else strtable = NULL;
|
||||
|
||||
section = (IMAGE_SECTION_HEADER*)
|
||||
((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
|
||||
for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
|
||||
{
|
||||
sectname = (const char*)section->Name;
|
||||
/* long section names start with a '/' (at least on MinGW32) */
|
||||
if (*sectname == '/' && strtable)
|
||||
sectname = strtable + atoi(sectname + 1);
|
||||
if (!strcasecmp(sectname, ".debug_info")) sect_debuginfo = section;
|
||||
else if (!strcasecmp(sectname, ".debug_str")) sect_debugstr = section;
|
||||
else if (!strcasecmp(sectname, ".debug_abbrev")) sect_debugabbrev = section;
|
||||
else if (!strcasecmp(sectname, ".debug_line")) sect_debugline = section;
|
||||
else if (!strcasecmp(sectname, ".debug_loc")) sect_debugloc = section;
|
||||
}
|
||||
if (sect_debuginfo)
|
||||
{
|
||||
ret = dwarf2_parse(module,
|
||||
module->module.BaseOfImage - nth->OptionalHeader.ImageBase,
|
||||
NULL, /* FIXME: some thunks to deal with ? */
|
||||
pe_get_sect(nth, mapping, sect_debuginfo), pe_get_sect_size(sect_debuginfo),
|
||||
pe_get_sect(nth, mapping, sect_debugabbrev), pe_get_sect_size(sect_debugabbrev),
|
||||
pe_get_sect(nth, mapping, sect_debugstr), pe_get_sect_size(sect_debugstr),
|
||||
pe_get_sect(nth, mapping, sect_debugline), pe_get_sect_size(sect_debugline),
|
||||
pe_get_sect(nth, mapping, sect_debugloc), pe_get_sect_size(sect_debugloc));
|
||||
}
|
||||
TRACE("%s the DWARF debug info\n", ret ? "successfully loaded" : "failed to load");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -133,7 +316,7 @@ static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module,
|
|||
*/
|
||||
static BOOL pe_load_msc_debug_info(const struct process* pcs,
|
||||
struct module* module,
|
||||
void* mapping, IMAGE_NT_HEADERS* nth)
|
||||
void* mapping, const IMAGE_NT_HEADERS* nth)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
const IMAGE_DATA_DIRECTORY* dir;
|
||||
|
@ -181,7 +364,7 @@ static BOOL pe_load_msc_debug_info(const struct process* pcs,
|
|||
*/
|
||||
static BOOL pe_load_export_debug_info(const struct process* pcs,
|
||||
struct module* module,
|
||||
void* mapping, IMAGE_NT_HEADERS* nth)
|
||||
void* mapping, const IMAGE_NT_HEADERS* nth)
|
||||
{
|
||||
unsigned int i;
|
||||
const IMAGE_EXPORT_DIRECTORY* exports;
|
||||
|
@ -193,14 +376,12 @@ 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, 1,
|
||||
TRUE /* FIXME */, TRUE /* FIXME */);
|
||||
symt_new_public(module, NULL, module->module.ModuleName, base, 1);
|
||||
#endif
|
||||
|
||||
/* Add entry point */
|
||||
symt_new_public(module, NULL, "EntryPoint",
|
||||
base + nth->OptionalHeader.AddressOfEntryPoint, 1,
|
||||
TRUE, TRUE);
|
||||
base + nth->OptionalHeader.AddressOfEntryPoint, 1);
|
||||
#if 0
|
||||
/* FIXME: we'd better store addresses linked to sections rather than
|
||||
absolute values */
|
||||
|
@ -211,8 +392,7 @@ static BOOL pe_load_export_debug_info(const struct process* pcs,
|
|||
for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
|
||||
{
|
||||
symt_new_public(module, NULL, section->Name,
|
||||
RtlImageRvaToVa(nth, mapping, section->VirtualAddress, NULL),
|
||||
1, TRUE /* FIXME */, TRUE /* FIXME */);
|
||||
RtlImageRvaToVa(nth, mapping, section->VirtualAddress, NULL), 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -237,8 +417,7 @@ static BOOL pe_load_export_debug_info(const struct process* pcs,
|
|||
if (!names[i]) continue;
|
||||
symt_new_public(module, NULL,
|
||||
RtlImageRvaToVa(nth, mapping, names[i], NULL),
|
||||
base + functions[ordinals[i]],
|
||||
1, TRUE /* FIXME */, TRUE /* FIXME */);
|
||||
base + functions[ordinals[i]], 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < exports->NumberOfFunctions; i++)
|
||||
|
@ -249,8 +428,7 @@ static BOOL pe_load_export_debug_info(const struct process* pcs,
|
|||
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 */);
|
||||
symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -284,7 +462,9 @@ BOOL pe_load_debug_info(const struct process* pcs, struct module* module)
|
|||
if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
|
||||
{
|
||||
ret = pe_load_stabs(pcs, module, mapping, nth) ||
|
||||
pe_load_msc_debug_info(pcs, module, mapping, nth);
|
||||
pe_load_dwarf(pcs, module, mapping, nth) ||
|
||||
pe_load_msc_debug_info(pcs, module, mapping, nth) ||
|
||||
pe_load_coff_symbol_table(module, nth, mapping);
|
||||
/* if we still have no debug info (we could only get SymExport at this
|
||||
* point), then do the SymExport except if we have an ELF container,
|
||||
* in which case we'll rely on the export's on the ELF side
|
||||
|
@ -367,13 +547,13 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name,
|
|||
* pe_load_nt_header
|
||||
*
|
||||
*/
|
||||
BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth)
|
||||
BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth)
|
||||
{
|
||||
IMAGE_DOS_HEADER dos;
|
||||
|
||||
return ReadProcessMemory(hProc, (char*)base, &dos, sizeof(dos), NULL) &&
|
||||
return ReadProcessMemory(hProc, (char*)(DWORD_PTR)base, &dos, sizeof(dos), NULL) &&
|
||||
dos.e_magic == IMAGE_DOS_SIGNATURE &&
|
||||
ReadProcessMemory(hProc, (char*)(base + dos.e_lfanew),
|
||||
ReadProcessMemory(hProc, (char*)(DWORD_PTR)(base + dos.e_lfanew),
|
||||
nth, sizeof(*nth), NULL) &&
|
||||
nth->Signature == IMAGE_NT_SIGNATURE;
|
||||
}
|
||||
|
@ -383,7 +563,7 @@ BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth)
|
|||
*
|
||||
*/
|
||||
struct module* pe_load_builtin_module(struct process* pcs, const WCHAR* name,
|
||||
DWORD base, DWORD size)
|
||||
DWORD64 base, DWORD64 size)
|
||||
{
|
||||
struct module* module = NULL;
|
||||
|
||||
|
@ -435,7 +615,7 @@ PVOID WINAPI ImageDirectoryEntryToDataEx( PVOID base, BOOLEAN image, USHORT dir,
|
|||
*size = nt->OptionalHeader.DataDirectory[dir].Size;
|
||||
if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)base + addr;
|
||||
|
||||
return RtlImageRvaToVa( nt, (HMODULE)base, addr, section );
|
||||
return RtlImageRvaToVa( nt, base, addr, section );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -309,42 +309,6 @@ SymGetHomeDirectoryW(DWORD dwType,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
SymGetLineFromName64(HANDLE hProcess,
|
||||
PCSTR pszModuleName,
|
||||
PCSTR pszFileName,
|
||||
DWORD dwLineNumber,
|
||||
PLONG plDisplacement,
|
||||
PIMAGEHLP_LINE64 Line)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
SymGetLineFromName(HANDLE hProcess,
|
||||
PCSTR pszModuleName,
|
||||
PCSTR pszFileName,
|
||||
DWORD dwLineNumber,
|
||||
PLONG plDisplacement,
|
||||
PIMAGEHLP_LINE Line)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
SymGetLineFromNameW64(HANDLE hProcess,
|
||||
PCWSTR pszModuleName,
|
||||
PCWSTR pszFileName,
|
||||
DWORD dwLineNumber,
|
||||
PLONG lpDisplacement,
|
||||
PIMAGEHLP_LINEW64 Line)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
SymGetLineNextW64(HANDLE hProcess,
|
||||
PIMAGEHLP_LINEW64 Line)
|
||||
|
@ -459,31 +423,6 @@ SymGetSourceVarFromTokenW(
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
SymGetSymFromName64(HANDLE hProcess,
|
||||
PCSTR pszName,
|
||||
PIMAGEHLP_SYMBOL64 Symbol)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
SymGetSymNext64(HANDLE hProcess,
|
||||
PIMAGEHLP_SYMBOL64 Symbol)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
SymGetSymPrev64(HANDLE hProcess,
|
||||
PIMAGEHLP_SYMBOL64 Symbol)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
SymGetSymbolFile(HANDLE hProcess,
|
||||
PCSTR pszSymPath,
|
||||
|
@ -581,16 +520,6 @@ SymPrevW(HANDLE hProcess,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
SymRefreshModuleList(
|
||||
HANDLE hProcess)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
PCHAR WINAPI
|
||||
SymSetHomeDirectory(HANDLE hProcess,
|
||||
PCSTR pszDir)
|
||||
|
@ -766,15 +695,6 @@ SymSrvStoreSupplementW(HANDLE hProcess,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
SymUnDName64(PIMAGEHLP_SYMBOL64 Symbol,
|
||||
PSTR pszUndecoratedName,
|
||||
DWORD dwUndecoratedNameLength)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
UnDecorateSymbolNameW(PCWSTR DecoratedName,
|
||||
PWSTR pszUnDecoratedName,
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
|
||||
#include "dbghelp_private.h"
|
||||
#include "wine/debug.h"
|
||||
#ifdef HAVE_REGEX_H
|
||||
# include <regex.h>
|
||||
#endif
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
|
@ -79,13 +76,18 @@ unsigned source_new(struct module* module, const char* base, const char* name)
|
|||
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_alloc = (module->sources_used + len + 1 + 255) & ~255;
|
||||
module->sources = HeapAlloc(GetProcessHeap(), 0, module->sources_alloc);
|
||||
}
|
||||
else
|
||||
{
|
||||
module->sources_alloc = max( module->sources_alloc * 2,
|
||||
(module->sources_used + len + 1 + 255) & ~255 );
|
||||
module->sources = HeapReAlloc(GetProcessHeap(), 0, module->sources,
|
||||
module->sources_alloc);
|
||||
}
|
||||
}
|
||||
ret = module->sources_used;
|
||||
memcpy(module->sources + module->sources_used, full, len);
|
||||
|
@ -154,116 +156,6 @@ BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG64 ModBase, PCSTR Mask,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void re_append(char** mask, unsigned* len, char ch)
|
||||
{
|
||||
*mask = HeapReAlloc(GetProcessHeap(), 0, *mask, ++(*len));
|
||||
(*mask)[*len - 2] = ch;
|
||||
}
|
||||
|
||||
static BOOL compile_regex(regex_t* re, const char* srcfile)
|
||||
{
|
||||
char* mask;
|
||||
unsigned len = 1;
|
||||
|
||||
mask = HeapAlloc(GetProcessHeap(), 0, 1);
|
||||
re_append(&mask, &len, '^');
|
||||
if (!srcfile || !*srcfile) re_append(&mask, &len, '*');
|
||||
else while (*srcfile)
|
||||
{
|
||||
switch (*srcfile)
|
||||
{
|
||||
case '\\':
|
||||
case '/':
|
||||
re_append(&mask, &len, '[');
|
||||
re_append(&mask, &len, '\\');
|
||||
re_append(&mask, &len, '\\');
|
||||
re_append(&mask, &len, '/');
|
||||
re_append(&mask, &len, ']');
|
||||
break;
|
||||
case '.':
|
||||
re_append(&mask, &len, '\\');
|
||||
re_append(&mask, &len, '.');
|
||||
break;
|
||||
default:
|
||||
re_append(&mask, &len, *srcfile);
|
||||
break;
|
||||
}
|
||||
srcfile++;
|
||||
}
|
||||
re_append(&mask, &len, '$');
|
||||
mask[len - 1] = '\0';
|
||||
len = regcomp(re, mask, REG_NOSUB);
|
||||
HeapFree(GetProcessHeap(), 0, mask);
|
||||
if (len)
|
||||
{
|
||||
FIXME("Couldn't compile %s\n", mask);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
if (!compile_regex(&re, srcfile)) 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)))
|
||||
{
|
||||
unsigned 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
regfree(&re);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* SymGetSourceFileToken (DBGHELP.@)
|
||||
*
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* The "stabs" debug format
|
||||
* by Julia Menapace, Jim Kingdon, David Mackenzie
|
||||
* of Cygnus Support
|
||||
* available (hopefully) from http:\\sources.redhat.com\gdb\onlinedocs
|
||||
* available (hopefully) from http://sources.redhat.com/gdb/onlinedocs
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
@ -53,6 +53,10 @@
|
|||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef HAVE_MACH_O_NLIST_H
|
||||
# include <mach-o/nlist.h>
|
||||
#endif
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winnls.h"
|
||||
|
@ -65,9 +69,24 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_stabs);
|
|||
|
||||
#define strtoull _strtoui64
|
||||
|
||||
/* Masks for n_type field */
|
||||
#ifndef N_STAB
|
||||
#define N_STAB 0xe0
|
||||
#endif
|
||||
#ifndef N_TYPE
|
||||
#define N_TYPE 0x1e
|
||||
#endif
|
||||
#ifndef N_EXT
|
||||
#define N_EXT 0x01
|
||||
#endif
|
||||
|
||||
/* Values for (n_type & N_TYPE) */
|
||||
#ifndef N_UNDF
|
||||
#define N_UNDF 0x00
|
||||
#endif
|
||||
#ifndef N_ABS
|
||||
#define N_ABS 0x02
|
||||
#endif
|
||||
|
||||
#define N_GSYM 0x20
|
||||
#define N_FUN 0x24
|
||||
|
@ -81,6 +100,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_stabs);
|
|||
#define N_SLINE 0x44
|
||||
#define N_ENSYM 0x4e
|
||||
#define N_SO 0x64
|
||||
#define N_OSO 0x66
|
||||
#define N_LSYM 0x80
|
||||
#define N_BINCL 0x82
|
||||
#define N_SOL 0x84
|
||||
|
@ -162,14 +182,18 @@ static int stabs_new_include(const char* file, unsigned long val)
|
|||
{
|
||||
if (num_include_def == num_alloc_include_def)
|
||||
{
|
||||
num_alloc_include_def += 256;
|
||||
if (!include_defs)
|
||||
include_defs = HeapAlloc(GetProcessHeap(), 0,
|
||||
{
|
||||
num_alloc_include_def = 256;
|
||||
include_defs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
sizeof(include_defs[0]) * num_alloc_include_def);
|
||||
}
|
||||
else
|
||||
include_defs = HeapReAlloc(GetProcessHeap(), 0, include_defs,
|
||||
{
|
||||
num_alloc_include_def *= 2;
|
||||
include_defs = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, include_defs,
|
||||
sizeof(include_defs[0]) * num_alloc_include_def);
|
||||
memset(include_defs + num_include_def, 0, sizeof(include_defs[0]) * 256);
|
||||
}
|
||||
}
|
||||
include_defs[num_include_def].name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(file) + 1), file);
|
||||
include_defs[num_include_def].value = val;
|
||||
|
@ -244,13 +268,13 @@ static struct symt** stabs_find_ref(long filenr, long subnr)
|
|||
{
|
||||
if (cu_nrofentries <= subnr)
|
||||
{
|
||||
cu_nrofentries = max( cu_nrofentries * 2, subnr + 1 );
|
||||
if (!cu_vector)
|
||||
cu_vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
sizeof(cu_vector[0]) * (subnr+1));
|
||||
cu_vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
sizeof(cu_vector[0]) * cu_nrofentries);
|
||||
else
|
||||
cu_vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
cu_vector, sizeof(cu_vector[0]) * (subnr+1));
|
||||
cu_nrofentries = subnr + 1;
|
||||
cu_vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
cu_vector, sizeof(cu_vector[0]) * cu_nrofentries);
|
||||
}
|
||||
ret = &cu_vector[subnr];
|
||||
}
|
||||
|
@ -263,13 +287,13 @@ static struct symt** stabs_find_ref(long filenr, long subnr)
|
|||
|
||||
if (idef->nrofentries <= subnr)
|
||||
{
|
||||
idef->nrofentries = max( idef->nrofentries * 2, subnr + 1 );
|
||||
if (!idef->vector)
|
||||
idef->vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
sizeof(idef->vector[0]) * (subnr+1));
|
||||
idef->vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
sizeof(idef->vector[0]) * idef->nrofentries);
|
||||
else
|
||||
idef->vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
idef->vector, sizeof(idef->vector[0]) * (subnr+1));
|
||||
idef->nrofentries = subnr + 1;
|
||||
idef->vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
idef->vector, sizeof(idef->vector[0]) * idef->nrofentries);
|
||||
}
|
||||
ret = &idef->vector[subnr];
|
||||
}
|
||||
|
@ -630,25 +654,21 @@ static inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd,
|
|||
|
||||
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &adt) == -1);
|
||||
|
||||
if (doadd)
|
||||
if (doadd && adt)
|
||||
{
|
||||
char tmp[256];
|
||||
WCHAR* name;
|
||||
DWORD64 size;
|
||||
|
||||
symt_get_info(adt, TI_GET_SYMNAME, &name);
|
||||
strcpy(tmp, "__inherited_class_");
|
||||
WideCharToMultiByte(CP_ACP, 0, name, -1,
|
||||
tmp + strlen(tmp), sizeof(tmp) - strlen(tmp),
|
||||
NULL, NULL);
|
||||
HeapFree(GetProcessHeap(), 0, name);
|
||||
strcat(tmp, symt_get_name(adt));
|
||||
|
||||
/* FIXME: TI_GET_LENGTH will not always work, especially when adt
|
||||
* has just been seen as a forward definition and not the real stuff
|
||||
* yet.
|
||||
* As we don't use much the size of members in structs, this may not
|
||||
* be much of a problem
|
||||
*/
|
||||
symt_get_info(adt, TI_GET_LENGTH, &size);
|
||||
symt_get_info(ptd->module, adt, TI_GET_LENGTH, &size);
|
||||
symt_add_udt_element(ptd->module, sdt, tmp, adt, ofs, (DWORD)size * 8);
|
||||
}
|
||||
PTS_ABORTIF(ptd, *ptd->ptr++ != ';');
|
||||
|
@ -1094,6 +1114,12 @@ static struct symt* stabs_parse_type(const char* stab)
|
|||
return *stabs_read_type_enum(&c);
|
||||
}
|
||||
|
||||
enum pending_obj_kind
|
||||
{
|
||||
PENDING_VAR,
|
||||
PENDING_LINE,
|
||||
};
|
||||
|
||||
struct pending_loc_var
|
||||
{
|
||||
char name[256];
|
||||
|
@ -1102,44 +1128,99 @@ struct pending_loc_var
|
|||
struct location loc;
|
||||
};
|
||||
|
||||
struct pending_block
|
||||
struct pending_line
|
||||
{
|
||||
struct pending_loc_var* vars;
|
||||
int source_idx;
|
||||
int line_num;
|
||||
unsigned long offset;
|
||||
unsigned long load_offset;
|
||||
};
|
||||
|
||||
struct pending_object
|
||||
{
|
||||
enum pending_obj_kind tag;
|
||||
union {
|
||||
struct pending_loc_var var;
|
||||
struct pending_line line;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct pending_list
|
||||
{
|
||||
struct pending_object* objs;
|
||||
unsigned num;
|
||||
unsigned allocated;
|
||||
};
|
||||
|
||||
static inline void pending_add(struct pending_block* pending, const char* name,
|
||||
enum DataKind dt, const struct location* loc)
|
||||
static inline void pending_make_room(struct pending_list* pending)
|
||||
{
|
||||
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]));
|
||||
if (!pending->objs)
|
||||
{
|
||||
pending->allocated = 8;
|
||||
pending->objs = HeapAlloc(GetProcessHeap(), 0,
|
||||
pending->allocated * sizeof(pending->objs[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
pending->allocated *= 2;
|
||||
pending->objs = HeapReAlloc(GetProcessHeap(), 0, pending->objs,
|
||||
pending->allocated * sizeof(pending->objs[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;
|
||||
}
|
||||
|
||||
static inline void pending_add_var(struct pending_list* pending, const char* name,
|
||||
enum DataKind dt, const struct location* loc)
|
||||
{
|
||||
pending_make_room(pending);
|
||||
pending->objs[pending->num].tag = PENDING_VAR;
|
||||
stab_strcpy(pending->objs[pending->num].u.var.name,
|
||||
sizeof(pending->objs[pending->num].u.var.name), name);
|
||||
pending->objs[pending->num].u.var.type = stabs_parse_type(name);
|
||||
pending->objs[pending->num].u.var.kind = dt;
|
||||
pending->objs[pending->num].u.var.loc = *loc;
|
||||
pending->num++;
|
||||
}
|
||||
|
||||
static void pending_flush(struct pending_block* pending, struct module* module,
|
||||
static inline void pending_add_line(struct pending_list* pending, int source_idx,
|
||||
int line_num, unsigned long offset,
|
||||
unsigned long load_offset)
|
||||
{
|
||||
pending_make_room(pending);
|
||||
pending->objs[pending->num].tag = PENDING_LINE;
|
||||
pending->objs[pending->num].u.line.source_idx = source_idx;
|
||||
pending->objs[pending->num].u.line.line_num = line_num;
|
||||
pending->objs[pending->num].u.line.offset = offset;
|
||||
pending->objs[pending->num].u.line.load_offset = load_offset;
|
||||
pending->num++;
|
||||
}
|
||||
|
||||
static void pending_flush(struct pending_list* pending, struct module* module,
|
||||
struct symt_function* func, struct symt_block* block)
|
||||
{
|
||||
unsigned 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);
|
||||
switch (pending->objs[i].tag)
|
||||
{
|
||||
case PENDING_VAR:
|
||||
symt_add_func_local(module, func,
|
||||
pending->objs[i].u.var.kind, &pending->objs[i].u.var.loc,
|
||||
block, pending->objs[i].u.var.type, pending->objs[i].u.var.name);
|
||||
break;
|
||||
case PENDING_LINE:
|
||||
if (module->type == DMT_MACHO)
|
||||
pending->objs[i].u.line.offset -= func->address - pending->objs[i].u.line.load_offset;
|
||||
symt_add_func_line(module, func, pending->objs[i].u.line.source_idx,
|
||||
pending->objs[i].u.line.line_num, pending->objs[i].u.line.offset);
|
||||
break;
|
||||
default:
|
||||
ERR("Unknown pending object tag %u\n", (unsigned)pending->objs[i].tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pending->num = 0;
|
||||
}
|
||||
|
@ -1156,7 +1237,7 @@ static void pending_flush(struct pending_block* pending, struct module* module,
|
|||
static void stabs_finalize_function(struct module* module, struct symt_function* func,
|
||||
unsigned long size)
|
||||
{
|
||||
IMAGEHLP_LINE il;
|
||||
IMAGEHLP_LINE64 il;
|
||||
struct location loc;
|
||||
|
||||
if (!func) return;
|
||||
|
@ -1175,9 +1256,25 @@ static void stabs_finalize_function(struct module* module, struct symt_function*
|
|||
if (size) func->size = size;
|
||||
}
|
||||
|
||||
static inline void stabbuf_append(char **buf, unsigned *buf_size, const char *str)
|
||||
{
|
||||
unsigned str_len, buf_len;
|
||||
|
||||
str_len = strlen(str);
|
||||
buf_len = strlen(*buf);
|
||||
|
||||
if(str_len+buf_len >= *buf_size) {
|
||||
*buf_size += buf_len + str_len;
|
||||
*buf = HeapReAlloc(GetProcessHeap(), 0, *buf, *buf_size);
|
||||
}
|
||||
|
||||
strcpy(*buf+buf_len, str);
|
||||
}
|
||||
|
||||
BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
||||
const void* pv_stab_ptr, int stablen,
|
||||
const char* strs, int strtablen)
|
||||
const char* strs, int strtablen,
|
||||
stabs_def_cb callback, void* user)
|
||||
{
|
||||
struct symt_function* curr_func = NULL;
|
||||
struct symt_block* block = NULL;
|
||||
|
@ -1195,16 +1292,19 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
unsigned incl[32];
|
||||
int incl_stk = -1;
|
||||
int source_idx = -1;
|
||||
struct pending_block pending;
|
||||
struct pending_list pending_block;
|
||||
struct pending_list pending_func;
|
||||
BOOL ret = TRUE;
|
||||
struct location loc;
|
||||
unsigned char type;
|
||||
|
||||
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));
|
||||
memset(&pending_block, 0, sizeof(pending_block));
|
||||
memset(&pending_func, 0, sizeof(pending_func));
|
||||
|
||||
/*
|
||||
* Allocate a buffer into which we can build stab strings for cases
|
||||
|
@ -1230,23 +1330,22 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
* next record. Repeat the process until we find a stab without the
|
||||
* '/' character, as this indicates we have the whole thing.
|
||||
*/
|
||||
unsigned len = strlen(ptr);
|
||||
if (strlen(stabbuff) + len > stabbufflen)
|
||||
{
|
||||
stabbufflen += 65536;
|
||||
stabbuff = HeapReAlloc(GetProcessHeap(), 0, stabbuff, stabbufflen);
|
||||
}
|
||||
strncat(stabbuff, ptr, len - 1);
|
||||
stabbuf_append(&stabbuff, &stabbufflen, ptr);
|
||||
continue;
|
||||
}
|
||||
else if (stabbuff[0] != '\0')
|
||||
{
|
||||
strcat(stabbuff, ptr);
|
||||
stabbuf_append(&stabbuff, &stabbufflen, ptr);
|
||||
ptr = stabbuff;
|
||||
}
|
||||
|
||||
if (stab_ptr->n_type & N_STAB)
|
||||
type = stab_ptr->n_type;
|
||||
else
|
||||
type = (stab_ptr->n_type & N_TYPE);
|
||||
|
||||
/* only symbol entries contain a typedef */
|
||||
switch (stab_ptr->n_type)
|
||||
switch (type)
|
||||
{
|
||||
case N_GSYM:
|
||||
case N_LCSYM:
|
||||
|
@ -1263,7 +1362,8 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
*/
|
||||
if (ptr != stabbuff)
|
||||
{
|
||||
strcpy(stabbuff, ptr);
|
||||
stabbuff[0] = 0;
|
||||
stabbuf_append(&stabbuff, &stabbufflen, ptr);
|
||||
ptr = stabbuff;
|
||||
}
|
||||
stab_strcpy(symname, sizeof(symname), ptr);
|
||||
|
@ -1276,7 +1376,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
}
|
||||
}
|
||||
|
||||
switch (stab_ptr->n_type)
|
||||
switch (type)
|
||||
{
|
||||
case N_GSYM:
|
||||
/*
|
||||
|
@ -1305,7 +1405,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
{
|
||||
block = symt_open_func_block(module, curr_func, block,
|
||||
stab_ptr->n_value, 0);
|
||||
pending_flush(&pending, module, curr_func, block);
|
||||
pending_flush(&pending_block, module, curr_func, block);
|
||||
}
|
||||
break;
|
||||
case N_RBRAC:
|
||||
|
@ -1356,6 +1456,22 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
case 17:
|
||||
case 18:
|
||||
case 19: loc.reg = CV_REG_ST0 + stab_ptr->n_value - 12; break;
|
||||
case 21:
|
||||
case 22:
|
||||
case 23:
|
||||
case 24:
|
||||
case 25:
|
||||
case 26:
|
||||
case 27:
|
||||
case 28: loc.reg = CV_REG_XMM0 + stab_ptr->n_value - 21; break;
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
case 32:
|
||||
case 33:
|
||||
case 34:
|
||||
case 35:
|
||||
case 36: loc.reg = CV_REG_MM0 + stab_ptr->n_value - 29; break;
|
||||
default:
|
||||
FIXME("Unknown register value (%lu)\n", stab_ptr->n_value);
|
||||
loc.reg = CV_REG_NONE;
|
||||
|
@ -1373,7 +1489,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
param_type);
|
||||
}
|
||||
else
|
||||
pending_add(&pending, ptr, DataIsLocal, &loc);
|
||||
pending_add_var(&pending_block, ptr, DataIsLocal, &loc);
|
||||
}
|
||||
break;
|
||||
case N_LSYM:
|
||||
|
@ -1381,19 +1497,24 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
loc.kind = loc_regrel;
|
||||
loc.reg = 0; /* FIXME */
|
||||
loc.offset = stab_ptr->n_value;
|
||||
if (curr_func != NULL) pending_add(&pending, ptr, DataIsLocal, &loc);
|
||||
if (curr_func != NULL) pending_add_var(&pending_block, ptr, DataIsLocal, &loc);
|
||||
break;
|
||||
case N_SLINE:
|
||||
/*
|
||||
* This is a line number. These are always relative to the start
|
||||
* of the function (N_FUN), and this makes the lookup easier.
|
||||
*/
|
||||
assert(source_idx >= 0);
|
||||
if (curr_func != NULL)
|
||||
{
|
||||
assert(source_idx >= 0);
|
||||
unsigned long offset = stab_ptr->n_value;
|
||||
if (module->type == DMT_MACHO)
|
||||
offset -= curr_func->address - load_offset;
|
||||
symt_add_func_line(module, curr_func, source_idx,
|
||||
stab_ptr->n_desc, stab_ptr->n_value);
|
||||
stab_ptr->n_desc, offset);
|
||||
}
|
||||
else pending_add_line(&pending_func, source_idx, stab_ptr->n_desc,
|
||||
stab_ptr->n_value, load_offset);
|
||||
break;
|
||||
case N_FUN:
|
||||
/*
|
||||
|
@ -1428,6 +1549,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
curr_func = symt_new_function(module, compiland, symname,
|
||||
load_offset + stab_ptr->n_value, 0,
|
||||
&func_type->symt);
|
||||
pending_flush(&pending_func, module, curr_func, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1508,10 +1630,38 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
break;
|
||||
case N_BNSYM:
|
||||
case N_ENSYM:
|
||||
case N_OSO:
|
||||
/* Always ignore these, they seem to be used only on Darwin. */
|
||||
break;
|
||||
case N_ABS:
|
||||
#ifdef N_SECT
|
||||
case N_SECT:
|
||||
#endif
|
||||
/* FIXME: Other definition types (N_TEXT, N_DATA, N_BSS, ...)? */
|
||||
if (callback)
|
||||
{
|
||||
BOOL is_public = (stab_ptr->n_type & N_EXT);
|
||||
BOOL is_global = is_public;
|
||||
|
||||
#ifdef N_PEXT
|
||||
/* "private extern"; shared among compilation units in a shared
|
||||
* library, but not accessible from outside the library. */
|
||||
if (stab_ptr->n_type & N_PEXT)
|
||||
{
|
||||
is_public = FALSE;
|
||||
is_global = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (*ptr == '_') ptr++;
|
||||
stab_strcpy(symname, sizeof(symname), ptr);
|
||||
|
||||
callback(module, load_offset, symname, stab_ptr->n_value,
|
||||
is_public, is_global, stab_ptr->n_other, compiland, user);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERR("Unknown stab type 0x%02x\n", stab_ptr->n_type);
|
||||
ERR("Unknown stab type 0x%02x\n", type);
|
||||
break;
|
||||
}
|
||||
stabbuff[0] = '\0';
|
||||
|
@ -1529,7 +1679,8 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
done:
|
||||
HeapFree(GetProcessHeap(), 0, stabbuff);
|
||||
stabs_free_includes();
|
||||
HeapFree(GetProcessHeap(), 0, pending.vars);
|
||||
HeapFree(GetProcessHeap(), 0, pending_block.objs);
|
||||
HeapFree(GetProcessHeap(), 0, pending_func.objs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -27,40 +27,45 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "dbghelp_private.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/winbase16.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||
|
||||
enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done};
|
||||
|
||||
static const char* wine_dbgstr_addr(const ADDRESS* addr)
|
||||
static DWORD64 WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS64* addr)
|
||||
{
|
||||
if (!addr) return "(null)";
|
||||
LDT_ENTRY le;
|
||||
|
||||
switch (addr->Mode)
|
||||
{
|
||||
case AddrModeFlat:
|
||||
return wine_dbg_sprintf("flat<%08x>", addr->Offset);
|
||||
case AddrMode1616:
|
||||
return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, addr->Offset);
|
||||
if (GetThreadSelectorEntry(hThread, addr->Segment, &le))
|
||||
return (le.HighWord.Bits.BaseHi << 24) +
|
||||
(le.HighWord.Bits.BaseMid << 16) + le.BaseLow + LOWORD(addr->Offset);
|
||||
break;
|
||||
case AddrMode1632:
|
||||
return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, addr->Offset);
|
||||
if (GetThreadSelectorEntry(hThread, addr->Segment, &le))
|
||||
return (le.HighWord.Bits.BaseHi << 24) +
|
||||
(le.HighWord.Bits.BaseMid << 16) + le.BaseLow + addr->Offset;
|
||||
break;
|
||||
case AddrModeReal:
|
||||
return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, addr->Offset);
|
||||
return (DWORD)(LOWORD(addr->Segment) << 4) + addr->Offset;
|
||||
case AddrModeFlat:
|
||||
return addr->Offset;
|
||||
default:
|
||||
return "unknown";
|
||||
FIXME("Unsupported (yet) mode (%x)\n", addr->Mode);
|
||||
return 0;
|
||||
}
|
||||
FIXME("Failed to linearize address %04x:%s (mode %x)\n",
|
||||
addr->Segment, wine_dbgstr_longlong(addr->Offset), addr->Mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 (!ReadProcessMemory(hProcess, (void*)(DWORD_PTR)addr, buffer, size, &r)) return FALSE;
|
||||
if (nread) *nread = r;
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -74,39 +79,6 @@ static BOOL CALLBACK read_mem64(HANDLE hProcess, DWORD64 addr, void* buffer,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* indexes in Reserved array */
|
||||
#define __CurrentMode 0
|
||||
#define __CurrentSwitch 1
|
||||
#define __NextSwitch 2
|
||||
|
||||
#define curr_mode (frame->Reserved[__CurrentMode])
|
||||
#define curr_switch (frame->Reserved[__CurrentSwitch])
|
||||
#define next_switch (frame->Reserved[__NextSwitch])
|
||||
|
||||
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;
|
||||
|
@ -121,379 +93,113 @@ static inline void addr_64to32(const ADDRESS64* addr64, ADDRESS* addr32)
|
|||
addr32->Mode = addr64->Mode;
|
||||
}
|
||||
|
||||
static inline BOOL sw_read_mem(struct stack_walk_callback* cb, DWORD addr, void* ptr, DWORD sz)
|
||||
BOOL sw_read_mem(struct cpu_stack_walk* csw, DWORD64 addr, void* ptr, DWORD sz)
|
||||
{
|
||||
if (cb->is32)
|
||||
return cb->u.s32.f_read_mem(cb->hProcess, addr, ptr, sz, NULL);
|
||||
if (csw->is32)
|
||||
return csw->u.s32.f_read_mem(csw->hProcess, addr, ptr, sz, NULL);
|
||||
else
|
||||
return cb->u.s64.f_read_mem(cb->hProcess, addr, ptr, sz, NULL);
|
||||
return csw->u.s64.f_read_mem(csw->hProcess, addr, ptr, sz, NULL);
|
||||
}
|
||||
|
||||
static inline DWORD sw_xlat_addr(struct stack_walk_callback* cb, ADDRESS* addr)
|
||||
DWORD64 sw_xlat_addr(struct cpu_stack_walk* csw, ADDRESS64* 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)
|
||||
if (csw->is32)
|
||||
{
|
||||
ADDRESS64 addr64;
|
||||
ADDRESS addr32;
|
||||
|
||||
addr_32to64(addr, &addr64);
|
||||
return cb->u.s64.f_xlat_adr(cb->hProcess, cb->hThread, &addr64);
|
||||
addr_64to32(addr, &addr32);
|
||||
return csw->u.s32.f_xlat_adr(csw->hProcess, csw->hThread, &addr32);
|
||||
}
|
||||
return addr_to_linear(cb->hProcess, cb->hThread, addr);
|
||||
else if (csw->u.s64.f_xlat_adr)
|
||||
return csw->u.s64.f_xlat_adr(csw->hProcess, csw->hThread, addr);
|
||||
return addr_to_linear(csw->hProcess, csw->hThread, addr);
|
||||
}
|
||||
|
||||
static inline void* sw_tabl_acs(struct stack_walk_callback* cb, DWORD addr)
|
||||
void* sw_table_access(struct cpu_stack_walk* csw, DWORD64 addr)
|
||||
{
|
||||
if (cb->is32)
|
||||
return cb->u.s32.f_tabl_acs(cb->hProcess, addr);
|
||||
if (csw->is32)
|
||||
return csw->u.s32.f_tabl_acs(csw->hProcess, addr);
|
||||
else
|
||||
return cb->u.s64.f_tabl_acs(cb->hProcess, addr);
|
||||
return csw->u.s64.f_tabl_acs(csw->hProcess, addr);
|
||||
}
|
||||
|
||||
static inline DWORD sw_modl_bas(struct stack_walk_callback* cb, DWORD addr)
|
||||
DWORD64 sw_module_base(struct cpu_stack_walk* csw, DWORD64 addr)
|
||||
{
|
||||
if (cb->is32)
|
||||
return cb->u.s32.f_modl_bas(cb->hProcess, addr);
|
||||
if (csw->is32)
|
||||
return csw->u.s32.f_modl_bas(csw->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;
|
||||
char ch;
|
||||
ADDRESS tmp;
|
||||
DWORD p;
|
||||
WORD val;
|
||||
BOOL do_switch;
|
||||
|
||||
/* sanity check */
|
||||
if (curr_mode >= stm_done) return FALSE;
|
||||
|
||||
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),
|
||||
curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
|
||||
curr_switch, next_switch);
|
||||
|
||||
if (curr_mode == stm_start)
|
||||
{
|
||||
THREAD_BASIC_INFORMATION info;
|
||||
|
||||
if ((frame->AddrPC.Mode == AddrModeFlat) &&
|
||||
(frame->AddrFrame.Mode != AddrModeFlat))
|
||||
{
|
||||
WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n");
|
||||
goto done_err;
|
||||
}
|
||||
|
||||
/* Init done */
|
||||
curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ?
|
||||
stm_32bit : stm_16bit;
|
||||
|
||||
/* cur_switch holds address of WOW32Reserved field in TEB in debuggee
|
||||
* address space
|
||||
*/
|
||||
if (NtQueryInformationThread(cb->hThread, ThreadBasicInformation, &info,
|
||||
sizeof(info), NULL) == STATUS_SUCCESS)
|
||||
{
|
||||
curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved);
|
||||
if (!sw_read_mem(cb, curr_switch, &next_switch, sizeof(next_switch)))
|
||||
{
|
||||
WARN("Can't read TEB:WOW32Reserved\n");
|
||||
goto done_err;
|
||||
}
|
||||
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
|
||||
/* 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
|
||||
{
|
||||
if (frame->AddrFrame.Offset == 0) goto done_err;
|
||||
if (frame->AddrFrame.Mode == AddrModeFlat)
|
||||
{
|
||||
assert(curr_mode == stm_32bit);
|
||||
do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(curr_mode == stm_16bit);
|
||||
do_switch = curr_switch &&
|
||||
frame->AddrFrame.Segment == SELECTOROF(curr_switch) &&
|
||||
frame->AddrFrame.Offset >= OFFSETOF(curr_switch);
|
||||
}
|
||||
|
||||
if (do_switch)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
frame->AddrPC.Mode = AddrModeFlat;
|
||||
frame->AddrPC.Segment = 0;
|
||||
frame->AddrPC.Offset = frame32.retaddr;
|
||||
frame->AddrFrame.Mode = AddrModeFlat;
|
||||
frame->AddrFrame.Segment = 0;
|
||||
frame->AddrFrame.Offset = frame32.ebp;
|
||||
|
||||
frame->AddrStack.Mode = AddrModeFlat;
|
||||
frame->AddrStack.Segment = 0;
|
||||
frame->AddrReturn.Mode = AddrModeFlat;
|
||||
frame->AddrReturn.Segment = 0;
|
||||
|
||||
next_switch = curr_switch;
|
||||
tmp.Mode = AddrMode1616;
|
||||
tmp.Segment = SELECTOROF(next_switch);
|
||||
tmp.Offset = OFFSETOF(next_switch);
|
||||
p = 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;
|
||||
curr_mode = stm_32bit;
|
||||
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 = 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;
|
||||
}
|
||||
|
||||
TRACE("Got a 16 bit stack switch:"
|
||||
"\n\tframe32: %08lx"
|
||||
"\n\tedx:%08x ecx:%08x ebp:%08x"
|
||||
"\n\tds:%04x es:%04x fs:%04x gs:%04x"
|
||||
"\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,
|
||||
frame16.ds, frame16.es, frame16.fs, frame16.gs,
|
||||
frame16.callfrom_ip, frame16.module_cs, frame16.relay,
|
||||
frame16.entry_ip, frame16.entry_point,
|
||||
frame16.bp, frame16.ip, frame16.cs);
|
||||
|
||||
|
||||
frame->AddrPC.Mode = AddrMode1616;
|
||||
frame->AddrPC.Segment = frame16.cs;
|
||||
frame->AddrPC.Offset = frame16.ip;
|
||||
|
||||
frame->AddrFrame.Mode = AddrMode1616;
|
||||
frame->AddrFrame.Segment = SELECTOROF(next_switch);
|
||||
frame->AddrFrame.Offset = frame16.bp;
|
||||
|
||||
frame->AddrStack.Mode = AddrMode1616;
|
||||
frame->AddrStack.Segment = SELECTOROF(next_switch);
|
||||
|
||||
frame->AddrReturn.Mode = AddrMode1616;
|
||||
frame->AddrReturn.Segment = frame16.cs;
|
||||
|
||||
next_switch = curr_switch;
|
||||
if (!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 = 0;
|
||||
curr_mode = stm_16bit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frame->AddrPC = frame->AddrReturn;
|
||||
if (curr_mode == stm_16bit)
|
||||
{
|
||||
frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD);
|
||||
/* "pop up" previous BP value */
|
||||
if (!sw_read_mem(cb, sw_xlat_addr(cb, &frame->AddrFrame),
|
||||
&val, sizeof(WORD)))
|
||||
goto done_err;
|
||||
frame->AddrFrame.Offset = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD);
|
||||
/* "pop up" previous EBP value */
|
||||
if (!sw_read_mem(cb, frame->AddrFrame.Offset,
|
||||
&frame->AddrFrame.Offset, sizeof(DWORD)))
|
||||
goto done_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_mode == stm_16bit)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
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 (!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,
|
||||
* but check whether it could be anyway
|
||||
*/
|
||||
if ((val & 7) == 7 && val != frame->AddrReturn.Segment)
|
||||
{
|
||||
LDT_ENTRY 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
|
||||
*/
|
||||
frame->AddrReturn.Segment = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
frame->AddrFrame.Offset &= ~1;
|
||||
/* we "pop" parameters as 16 bit entities... of course, this won't
|
||||
* work if the parameter is in fact bigger than 16bit, but
|
||||
* there's no way to know that here
|
||||
*/
|
||||
for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
|
||||
{
|
||||
sw_read_mem(cb, p + (2 + i) * sizeof(WORD), &val, sizeof(val));
|
||||
frame->Params[i] = val;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
sw_read_mem(cb, frame->AddrFrame.Offset + 2 * sizeof(DWORD),
|
||||
frame->Params, sizeof(frame->Params));
|
||||
}
|
||||
|
||||
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=%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),
|
||||
curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
|
||||
curr_switch, next_switch, frame->FuncTableEntry);
|
||||
|
||||
return TRUE;
|
||||
done_err:
|
||||
curr_mode = stm_done;
|
||||
return FALSE;
|
||||
return csw->u.s64.f_modl_bas(csw->hProcess, addr);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* StackWalk (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
|
||||
LPSTACKFRAME frame, PVOID ctx,
|
||||
LPSTACKFRAME frame32, 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;
|
||||
struct cpu_stack_walk csw;
|
||||
STACKFRAME64 frame64;
|
||||
BOOL ret;
|
||||
struct cpu* cpu;
|
||||
|
||||
TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p)\n",
|
||||
MachineType, hProcess, hThread, frame, ctx,
|
||||
MachineType, hProcess, hThread, frame32, ctx,
|
||||
f_read_mem, FunctionTableAccessRoutine,
|
||||
GetModuleBaseRoutine, f_xlat_adr);
|
||||
|
||||
if (MachineType != IMAGE_FILE_MACHINE_I386)
|
||||
if (!(cpu = cpu_find(MachineType)))
|
||||
{
|
||||
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;
|
||||
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.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 */
|
||||
|
||||
return stack_walk(&swcb, frame);
|
||||
csw.hProcess = hProcess;
|
||||
csw.hThread = hThread;
|
||||
csw.is32 = TRUE;
|
||||
/* sigh... MS isn't even consistent in the func prototypes */
|
||||
csw.u.s32.f_read_mem = (f_read_mem) ? f_read_mem : read_mem;
|
||||
csw.u.s32.f_xlat_adr = f_xlat_adr;
|
||||
csw.u.s32.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess;
|
||||
csw.u.s32.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase;
|
||||
|
||||
if ((ret = cpu->stack_walk(&csw, &frame64)))
|
||||
{
|
||||
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->Params[0] = frame64.Params[0];
|
||||
frame32->Params[1] = frame64.Params[1];
|
||||
frame32->Params[2] = frame64.Params[2];
|
||||
frame32->Params[3] = frame64.Params[3];
|
||||
frame32->Far = frame64.Far;
|
||||
frame32->Virtual = frame64.Virtual;
|
||||
frame32->Reserved[0] = frame64.Reserved[0];
|
||||
frame32->Reserved[1] = frame64.Reserved[1];
|
||||
frame32->Reserved[2] = frame64.Reserved[2];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -501,78 +207,49 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
|
|||
* StackWalk64 (DBGHELP.@)
|
||||
*/
|
||||
BOOL WINAPI StackWalk64(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
|
||||
LPSTACKFRAME64 frame64, PVOID ctx,
|
||||
LPSTACKFRAME64 frame, 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;
|
||||
struct cpu_stack_walk csw;
|
||||
struct cpu* cpu;
|
||||
|
||||
TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p)\n",
|
||||
MachineType, hProcess, hThread, frame64, ctx,
|
||||
MachineType, hProcess, hThread, frame, ctx,
|
||||
f_read_mem, FunctionTableAccessRoutine,
|
||||
GetModuleBaseRoutine, f_xlat_adr);
|
||||
|
||||
if (MachineType != IMAGE_FILE_MACHINE_I386)
|
||||
if (!(cpu = cpu_find(MachineType)))
|
||||
{
|
||||
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;
|
||||
csw.hProcess = hProcess;
|
||||
csw.hThread = hThread;
|
||||
csw.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;
|
||||
csw.u.s64.f_read_mem = (f_read_mem) ? f_read_mem : read_mem64;
|
||||
csw.u.s64.f_xlat_adr = (f_xlat_adr) ? f_xlat_adr : addr_to_linear;
|
||||
csw.u.s64.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess64;
|
||||
csw.u.s64.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase64;
|
||||
|
||||
ret = stack_walk(&swcb, &frame32);
|
||||
if (!cpu->stack_walk(&csw, frame)) return FALSE;
|
||||
|
||||
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;
|
||||
frame->KdHelp.Thread = 0xC000FADE;
|
||||
frame->KdHelp.ThCallbackStack = 0x10;
|
||||
frame->KdHelp.ThCallbackBStore = 0;
|
||||
frame->KdHelp.NextCallback = 0;
|
||||
frame->KdHelp.FramePointer = 0;
|
||||
frame->KdHelp.KiCallUserMode = 0xD000DAFE;
|
||||
frame->KdHelp.KeUserCallbackDispatcher = 0xE000F000;
|
||||
frame->KdHelp.SystemRangeStart = 0xC0000000;
|
||||
frame->KdHelp.Reserved[0] /* KiUserExceptionDispatcher */ = 0xE0005000;
|
||||
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
|
|
@ -34,14 +34,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
|||
|
||||
struct pool_arena
|
||||
{
|
||||
struct pool_arena* next;
|
||||
char* current;
|
||||
struct list entry;
|
||||
char *current;
|
||||
char *end;
|
||||
};
|
||||
|
||||
void pool_init(struct pool* a, unsigned arena_size)
|
||||
void pool_init(struct pool* a, size_t arena_size)
|
||||
{
|
||||
list_init( &a->arena_list );
|
||||
list_init( &a->arena_full );
|
||||
a->arena_size = arena_size;
|
||||
a->first = NULL;
|
||||
}
|
||||
|
||||
void pool_destroy(struct pool* pool)
|
||||
|
@ -50,58 +52,73 @@ void pool_destroy(struct pool* pool)
|
|||
struct pool_arena* next;
|
||||
|
||||
#ifdef USE_STATS
|
||||
unsigned alloc, used, num;
|
||||
|
||||
size_t alloc, used, num;
|
||||
|
||||
alloc = used = num = 0;
|
||||
arena = pool->first;
|
||||
while (arena)
|
||||
LIST_FOR_EACH_ENTRY( arena, &pool->arena_list, struct pool_arena, entry )
|
||||
{
|
||||
alloc += pool->arena_size;
|
||||
alloc += arena->end - (char *)arena;
|
||||
used += arena->current - (char*)arena;
|
||||
num++;
|
||||
}
|
||||
LIST_FOR_EACH_ENTRY( arena, &pool->arena_full, struct pool_arena, entry )
|
||||
{
|
||||
alloc += arena->end - (char *)arena;
|
||||
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);
|
||||
FIXME("STATS: pool %p has allocated %u kbytes, used %u kbytes in %u arenas, non-allocation ratio: %.2f%%\n",
|
||||
pool, (unsigned)(alloc >> 10), (unsigned)(used >> 10), (unsigned)num,
|
||||
100.0 - (float)used / (float)alloc * 100.0);
|
||||
#endif
|
||||
|
||||
arena = pool->first;
|
||||
while (arena)
|
||||
LIST_FOR_EACH_ENTRY_SAFE( arena, next, &pool->arena_list, struct pool_arena, entry )
|
||||
{
|
||||
next = arena->next;
|
||||
list_remove( &arena->entry );
|
||||
HeapFree(GetProcessHeap(), 0, arena);
|
||||
}
|
||||
LIST_FOR_EACH_ENTRY_SAFE( arena, next, &pool->arena_full, struct pool_arena, entry )
|
||||
{
|
||||
list_remove( &arena->entry );
|
||||
HeapFree(GetProcessHeap(), 0, arena);
|
||||
arena = next;
|
||||
}
|
||||
pool_init(pool, 0);
|
||||
}
|
||||
|
||||
void* pool_alloc(struct pool* pool, unsigned len)
|
||||
void* pool_alloc(struct pool* pool, size_t len)
|
||||
{
|
||||
struct pool_arena* arena;
|
||||
void* ret;
|
||||
size_t size;
|
||||
|
||||
len = (len + 3) & ~3; /* round up size on DWORD boundary */
|
||||
assert(sizeof(struct pool_arena) + len <= pool->arena_size && len);
|
||||
|
||||
for (arena = pool->first; arena; arena = arena->next)
|
||||
LIST_FOR_EACH_ENTRY( arena, &pool->arena_list, struct pool_arena, entry )
|
||||
{
|
||||
if ((char*)arena + pool->arena_size - arena->current >= len)
|
||||
if (arena->end - arena->current >= len)
|
||||
{
|
||||
ret = arena->current;
|
||||
arena->current += len;
|
||||
if (arena->current + 16 >= arena->end)
|
||||
{
|
||||
list_remove( &arena->entry );
|
||||
list_add_tail( &pool->arena_full, &arena->entry );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
arena = HeapAlloc(GetProcessHeap(), 0, pool->arena_size);
|
||||
if (!arena) {ERR("OOM\n");return NULL;}
|
||||
size = max( pool->arena_size, len );
|
||||
arena = HeapAlloc(GetProcessHeap(), 0, size + sizeof(struct pool_arena));
|
||||
if (!arena) return NULL;
|
||||
|
||||
ret = (char*)arena + sizeof(*arena);
|
||||
arena->next = pool->first;
|
||||
pool->first = arena;
|
||||
ret = arena + 1;
|
||||
arena->current = (char*)ret + len;
|
||||
arena->end = (char*)ret + size;
|
||||
if (arena->current + 16 >= arena->end)
|
||||
list_add_tail( &pool->arena_full, &arena->entry );
|
||||
else
|
||||
list_add_head( &pool->arena_list, &arena->entry );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -298,7 +315,7 @@ unsigned sparse_array_length(const struct sparse_array* sa)
|
|||
return sa->elements.num_elts;
|
||||
}
|
||||
|
||||
unsigned hash_table_hash(const char* name, unsigned num_buckets)
|
||||
static unsigned hash_table_hash(const char* name, unsigned num_buckets)
|
||||
{
|
||||
unsigned hash = 0;
|
||||
while (*name)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -304,6 +304,21 @@ struct symt_array* symt_new_array(struct module* module, int min, int max,
|
|||
return sym;
|
||||
}
|
||||
|
||||
static inline DWORD symt_array_count(struct module* module, const struct symt_array* array)
|
||||
{
|
||||
if (array->end < 0)
|
||||
{
|
||||
DWORD64 elem_size;
|
||||
/* One could want to also set the array->end field in array, but we won't do it
|
||||
* as long as all the get_type() helpers use const objects
|
||||
*/
|
||||
if (symt_get_info(module, array->base_type, TI_GET_LENGTH, &elem_size) && elem_size)
|
||||
return -array->end / (DWORD)elem_size;
|
||||
return 0;
|
||||
}
|
||||
return array->end - array->start + 1;
|
||||
}
|
||||
|
||||
struct symt_function_signature* symt_new_function_signature(struct module* module,
|
||||
struct symt* ret_type,
|
||||
enum CV_call_e call_conv)
|
||||
|
@ -400,9 +415,9 @@ BOOL WINAPI SymEnumTypes(HANDLE hProcess, ULONG64 BaseOfDll,
|
|||
for (i=0; i<vector_length(&pair.effective->vtypes); i++)
|
||||
{
|
||||
type = *(struct symt**)vector_at(&pair.effective->vtypes, i);
|
||||
sym_info->TypeIndex = (DWORD)type;
|
||||
sym_info->TypeIndex = symt_ptr2index(pair.effective, type);
|
||||
sym_info->info = 0; /* FIXME */
|
||||
symt_get_info(type, TI_GET_LENGTH, &size);
|
||||
symt_get_info(pair.effective, type, TI_GET_LENGTH, &size);
|
||||
sym_info->Size = size;
|
||||
sym_info->ModBase = pair.requested->module.BaseOfImage;
|
||||
sym_info->Flags = 0; /* FIXME */
|
||||
|
@ -462,8 +477,8 @@ BOOL WINAPI SymEnumTypesW(HANDLE hProcess, ULONG64 BaseOfDll,
|
|||
*
|
||||
* Retrieves information about a symt (either symbol or type)
|
||||
*/
|
||||
BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
|
||||
void* pInfo)
|
||||
BOOL symt_get_info(struct module* module, const struct symt* type,
|
||||
IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo)
|
||||
{
|
||||
unsigned len;
|
||||
|
||||
|
@ -495,7 +510,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
|
|||
for (i = 0; i < tifp->Count; i++)
|
||||
{
|
||||
if (!(pt = vector_at(v, tifp->Start + i))) return FALSE;
|
||||
tifp->ChildId[i] = (DWORD)*pt;
|
||||
tifp->ChildId[i] = symt_ptr2index(module, *pt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -522,7 +537,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
|
|||
case SymTagFuncDebugStart:
|
||||
case SymTagFuncDebugEnd:
|
||||
case SymTagLabel:
|
||||
if (!symt_get_info(((const struct symt_hierarchy_point*)type)->parent,
|
||||
if (!symt_get_info(module, ((const struct symt_hierarchy_point*)type)->parent,
|
||||
req, pInfo))
|
||||
return FALSE;
|
||||
X(ULONG64) += ((const struct symt_hierarchy_point*)type)->loc.offset;
|
||||
|
@ -597,8 +612,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
|
|||
switch (type->tag)
|
||||
{
|
||||
case SymTagArrayType:
|
||||
X(DWORD) = ((const struct symt_array*)type)->end -
|
||||
((const struct symt_array*)type)->start + 1;
|
||||
X(DWORD) = symt_array_count(module, (const struct symt_array*)type);
|
||||
break;
|
||||
case SymTagFunctionType:
|
||||
/* this seems to be wrong for (future) C++ methods, where 'this' parameter
|
||||
|
@ -639,18 +653,17 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
|
|||
return FALSE;
|
||||
X(DWORD64) = ((const struct symt_data*)type)->u.member.length;
|
||||
break;
|
||||
case SymTagArrayType:
|
||||
if (!symt_get_info(((const struct symt_array*)type)->base_type,
|
||||
case SymTagArrayType:
|
||||
if (!symt_get_info(module, ((const struct symt_array*)type)->base_type,
|
||||
TI_GET_LENGTH, pInfo))
|
||||
return FALSE;
|
||||
X(DWORD64) *= ((const struct symt_array*)type)->end -
|
||||
((const struct symt_array*)type)->start + 1;
|
||||
X(DWORD64) *= symt_array_count(module, (const struct symt_array*)type);
|
||||
break;
|
||||
case SymTagPublicSymbol:
|
||||
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);
|
||||
return symt_get_info(module, ((const struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo);
|
||||
case SymTagThunk:
|
||||
X(DWORD64) = ((const struct symt_thunk*)type)->size;
|
||||
break;
|
||||
|
@ -670,19 +683,19 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
|
|||
switch (type->tag)
|
||||
{
|
||||
case SymTagBlock:
|
||||
X(DWORD) = (DWORD)((const struct symt_block*)type)->container;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_block*)type)->container);
|
||||
break;
|
||||
case SymTagData:
|
||||
X(DWORD) = (DWORD)((const struct symt_data*)type)->container;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_data*)type)->container);
|
||||
break;
|
||||
case SymTagFunction:
|
||||
X(DWORD) = (DWORD)((const struct symt_function*)type)->container;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->container);
|
||||
break;
|
||||
case SymTagThunk:
|
||||
X(DWORD) = (DWORD)((const struct symt_thunk*)type)->container;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_thunk*)type)->container);
|
||||
break;
|
||||
case SymTagFunctionArgType:
|
||||
X(DWORD) = (DWORD)((const struct symt_function_arg_type*)type)->container;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_function_arg_type*)type)->container);
|
||||
break;
|
||||
default:
|
||||
FIXME("Unsupported sym-tag %s for get-lexical-parent\n",
|
||||
|
@ -750,29 +763,29 @@ 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)->base_type;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_array*)type)->base_type);
|
||||
break;
|
||||
case SymTagPointerType:
|
||||
X(DWORD) = (DWORD)((const struct symt_pointer*)type)->pointsto;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_pointer*)type)->pointsto);
|
||||
break;
|
||||
case SymTagFunctionType:
|
||||
X(DWORD) = (DWORD)((const struct symt_function_signature*)type)->rettype;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_function_signature*)type)->rettype);
|
||||
break;
|
||||
case SymTagTypedef:
|
||||
X(DWORD) = (DWORD)((const struct symt_typedef*)type)->type;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_typedef*)type)->type);
|
||||
break;
|
||||
/* lexical => hierarchical */
|
||||
case SymTagData:
|
||||
X(DWORD) = (DWORD)((const struct symt_data*)type)->type;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_data*)type)->type);
|
||||
break;
|
||||
case SymTagFunction:
|
||||
X(DWORD) = (DWORD)((const struct symt_function*)type)->type;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->type);
|
||||
break;
|
||||
case SymTagEnum:
|
||||
X(DWORD) = (DWORD)((const struct symt_enum*)type)->base_type;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_enum*)type)->base_type);
|
||||
break;
|
||||
case SymTagFunctionArgType:
|
||||
X(DWORD) = (DWORD)((const struct symt_function_arg_type*)type)->arg_type;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_function_arg_type*)type)->arg_type);
|
||||
break;
|
||||
default:
|
||||
FIXME("Unsupported sym-tag %s for get-type\n",
|
||||
|
@ -806,7 +819,7 @@ BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
|
|||
break;
|
||||
case TI_GET_ARRAYINDEXTYPEID:
|
||||
if (type->tag != SymTagArrayType) return FALSE;
|
||||
X(DWORD) = (DWORD)((const struct symt_array*)type)->index_type;
|
||||
X(DWORD) = symt_ptr2index(module, ((const struct symt_array*)type)->index_type);
|
||||
break;
|
||||
|
||||
case TI_GET_CLASSPARENTID:
|
||||
|
@ -854,7 +867,7 @@ BOOL WINAPI SymGetTypeInfo(HANDLE hProcess, DWORD64 ModBase,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
return symt_get_info((struct symt*)TypeId, GetType, pInfo);
|
||||
return symt_get_info(pair.effective, symt_index2ptr(pair.effective, TypeId), GetType, pInfo);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
@ -865,15 +878,15 @@ BOOL WINAPI SymGetTypeFromName(HANDLE hProcess, ULONG64 BaseOfDll,
|
|||
PCSTR Name, PSYMBOL_INFO Symbol)
|
||||
{
|
||||
struct process* pcs = process_find_by_handle(hProcess);
|
||||
struct module* module;
|
||||
struct module_pair pair;
|
||||
struct symt* type;
|
||||
|
||||
if (!pcs) return FALSE;
|
||||
module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
|
||||
if (!module) return FALSE;
|
||||
type = symt_find_type_by_name(module, SymTagNull, Name);
|
||||
pair.requested = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
|
||||
if (!module_get_debug(&pair)) return FALSE;
|
||||
type = symt_find_type_by_name(pair.effective, SymTagNull, Name);
|
||||
if (!type) return FALSE;
|
||||
Symbol->TypeIndex = (DWORD)type;
|
||||
Symbol->TypeIndex = symt_ptr2index(pair.effective, type);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
26
reactos/dll/win32/dbghelp/version.rc
Normal file
26
reactos/dll/win32/dbghelp/version.rc
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2009 Louis Lenders
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define WINE_FILEDESCRIPTION_STR "Wine Image Helper"
|
||||
#define WINE_FILENAME_STR "dbghelp.dll"
|
||||
#define WINE_FILEVERSION 5,1,2600,3264
|
||||
#define WINE_FILEVERSION_STR "5.1.2600.3264"
|
||||
#define WINE_PRODUCTVERSION 5,1,2600,3264
|
||||
#define WINE_PRODUCTVERSION_STR "5.1.2600.3264"
|
||||
|
||||
#include "wine/wine_common_ver.rc"
|
|
@ -871,20 +871,20 @@ typedef struct _UNWIND_HISTORY_TABLE {
|
|||
*/
|
||||
|
||||
/* This is used by NtQuerySystemInformation */
|
||||
typedef struct _SYSTEM_THREAD_INFORMATION{
|
||||
FILETIME ftKernelTime;
|
||||
FILETIME ftUserTime;
|
||||
FILETIME ftCreateTime;
|
||||
DWORD dwTickCount;
|
||||
DWORD dwStartAddress;
|
||||
DWORD dwOwningPID;
|
||||
DWORD dwThreadID;
|
||||
DWORD dwCurrentPriority;
|
||||
DWORD dwBasePriority;
|
||||
DWORD dwContextSwitches;
|
||||
DWORD dwThreadState;
|
||||
DWORD dwWaitReason;
|
||||
DWORD dwUnknown;
|
||||
typedef struct _SYSTEM_THREAD_INFORMATION
|
||||
{ /* win32/win64 */
|
||||
LARGE_INTEGER KernelTime; /* 00/00 */
|
||||
LARGE_INTEGER UserTime; /* 08/08 */
|
||||
LARGE_INTEGER CreateTime; /* 10/10 */
|
||||
DWORD dwTickCount; /* 18/18 */
|
||||
LPVOID StartAddress; /* 1c/20 */
|
||||
CLIENT_ID ClientId; /* 20/28 */
|
||||
DWORD dwCurrentPriority; /* 28/38 */
|
||||
DWORD dwBasePriority; /* 2c/3c */
|
||||
DWORD dwContextSwitches; /* 30/40 */
|
||||
DWORD dwThreadState; /* 34/44 */
|
||||
DWORD dwWaitReason; /* 38/48 */
|
||||
DWORD dwUnknown; /* 3c/4c */
|
||||
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
|
||||
|
||||
typedef struct _IO_STATUS_BLOCK {
|
||||
|
@ -1195,38 +1195,39 @@ typedef struct _VM_COUNTERS_ {
|
|||
SIZE_T QuotaNonPagedPoolUsage;
|
||||
SIZE_T PagefileUsage;
|
||||
SIZE_T PeakPagefileUsage;
|
||||
SIZE_T PrivatePageCount;
|
||||
} VM_COUNTERS, *PVM_COUNTERS;
|
||||
|
||||
typedef struct _SYSTEM_PROCESS_INFORMATION {
|
||||
#ifdef __WINESRC__
|
||||
DWORD dwOffset;
|
||||
DWORD dwThreadCount;
|
||||
DWORD dwUnknown1[6];
|
||||
FILETIME ftCreationTime;
|
||||
FILETIME ftUserTime;
|
||||
FILETIME ftKernelTime;
|
||||
UNICODE_STRING ProcessName;
|
||||
DWORD dwBasePriority;
|
||||
DWORD dwProcessID;
|
||||
DWORD dwParentProcessID;
|
||||
DWORD dwHandleCount;
|
||||
DWORD dwUnknown3;
|
||||
DWORD dwUnknown4;
|
||||
VM_COUNTERS vmCounters;
|
||||
IO_COUNTERS ioCounters;
|
||||
SYSTEM_THREAD_INFORMATION ti[1];
|
||||
#ifdef __WINESRC__ /* win32/win64 */
|
||||
ULONG NextEntryOffset; /* 00/00 */
|
||||
DWORD dwThreadCount; /* 04/04 */
|
||||
DWORD dwUnknown1[6]; /* 08/08 */
|
||||
LARGE_INTEGER CreationTime; /* 20/20 */
|
||||
LARGE_INTEGER UserTime; /* 28/28 */
|
||||
LARGE_INTEGER KernelTime; /* 30/30 */
|
||||
UNICODE_STRING ProcessName; /* 38/38 */
|
||||
DWORD dwBasePriority; /* 40/48 */
|
||||
HANDLE UniqueProcessId; /* 44/50 */
|
||||
HANDLE ParentProcessId; /* 48/58 */
|
||||
ULONG HandleCount; /* 4c/60 */
|
||||
DWORD dwUnknown3; /* 50/64 */
|
||||
DWORD dwUnknown4; /* 54/68 */
|
||||
VM_COUNTERS vmCounters; /* 58/70 */
|
||||
IO_COUNTERS ioCounters; /* 88/d0 */
|
||||
SYSTEM_THREAD_INFORMATION ti[1]; /* b8/100 */
|
||||
#else
|
||||
ULONG NextEntryOffset;
|
||||
BYTE Reserved1[52];
|
||||
PVOID Reserved2[3];
|
||||
HANDLE UniqueProcessId;
|
||||
PVOID Reserved3;
|
||||
ULONG HandleCount;
|
||||
BYTE Reserved4[4];
|
||||
PVOID Reserved5[11];
|
||||
SIZE_T PeakPagefileUsage;
|
||||
SIZE_T PrivatePageCount;
|
||||
LARGE_INTEGER Reserved6[6];
|
||||
ULONG NextEntryOffset; /* 00/00 */
|
||||
BYTE Reserved1[52]; /* 04/04 */
|
||||
PVOID Reserved2[3]; /* 38/38 */
|
||||
HANDLE UniqueProcessId; /* 44/50 */
|
||||
PVOID Reserved3; /* 48/58 */
|
||||
ULONG HandleCount; /* 4c/60 */
|
||||
BYTE Reserved4[4]; /* 50/64 */
|
||||
PVOID Reserved5[11]; /* 54/68 */
|
||||
SIZE_T PeakPagefileUsage; /* 80/c0 */
|
||||
SIZE_T PrivatePageCount; /* 84/c8 */
|
||||
LARGE_INTEGER Reserved6[6]; /* 88/d0 */
|
||||
#endif
|
||||
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
|
||||
|
||||
|
|
|
@ -1642,14 +1642,28 @@ struct startend
|
|||
unsigned int end;
|
||||
};
|
||||
|
||||
#define LT2_LINES_BLOCK 0x000000f2
|
||||
#define LT2_FILES_BLOCK 0x000000f4
|
||||
|
||||
/* there's a new line tab structure from MS Studio 2005 and after
|
||||
* it's made of:
|
||||
* DWORD 000000f4
|
||||
* DWORD lineblk_offset (counting bytes after this field)
|
||||
* an array of codeview_linetab2_file structures
|
||||
* an array (starting at <lineblk_offset>) of codeview_linetab2_block structures
|
||||
* it's made of a list of codeview_linetab2 blocks.
|
||||
* We've only seen (so far) list with a single LT2_FILES_BLOCK and several
|
||||
* LT2_LINES_BLOCK. The LT2_FILES block has been encountered either as first
|
||||
* or last block of the list.
|
||||
* A LT2_FILES contains one or several codeview_linetab2_file:s
|
||||
*/
|
||||
|
||||
struct codeview_linetab2
|
||||
{
|
||||
DWORD header;
|
||||
DWORD size_of_block;
|
||||
};
|
||||
|
||||
static inline const struct codeview_linetab2* codeview_linetab2_next_block(const struct codeview_linetab2* lt2)
|
||||
{
|
||||
return (const struct codeview_linetab2*)((const char*)(lt2 + 1) + lt2->size_of_block);
|
||||
}
|
||||
|
||||
struct codeview_linetab2_file
|
||||
{
|
||||
DWORD offset; /* offset in string table for filename */
|
||||
|
@ -1658,16 +1672,21 @@ struct codeview_linetab2_file
|
|||
WORD pad0; /* always 0 */
|
||||
};
|
||||
|
||||
struct codeview_linetab2_block
|
||||
struct codeview_lt2blk_files
|
||||
{
|
||||
DWORD header; /* 0x000000f2 */
|
||||
DWORD size_of_block; /* next block is at # bytes after this field */
|
||||
DWORD start; /* start address of function with line numbers */
|
||||
DWORD seg; /* segment of function with line numbers */
|
||||
DWORD size; /* size of function with line numbers */
|
||||
DWORD file_offset; /* offset for accessing corresponding codeview_linetab2_file */
|
||||
DWORD nlines; /* number of lines in this block */
|
||||
DWORD size_lines; /* number of bytes following for line number information */
|
||||
struct codeview_linetab2 lt2; /* LT2_FILES */
|
||||
struct codeview_linetab2_file file[1];
|
||||
};
|
||||
|
||||
struct codeview_lt2blk_lines
|
||||
{
|
||||
struct codeview_linetab2 lt2; /* LT2_LINE_BLOCK */
|
||||
DWORD start; /* start address of function with line numbers */
|
||||
DWORD seg; /* segment of function with line numbers */
|
||||
DWORD size; /* size of function with line numbers */
|
||||
DWORD file_offset; /* offset for accessing corresponding codeview_linetab2_file */
|
||||
DWORD nlines; /* number of lines in this block */
|
||||
DWORD size_lines; /* number of bytes following for line number information */
|
||||
struct {
|
||||
DWORD offset; /* offset (from <seg>:<start>) for line number */
|
||||
DWORD lineno; /* the line number (OR:ed with 0x80000000 why ???) */
|
||||
|
|
Loading…
Reference in a new issue