[DBGHELP]

* Sync with Wine 1.5.26.

svn path=/trunk/; revision=59221
This commit is contained in:
Amine Khaldi 2013-06-15 11:57:55 +00:00
parent ca1b982148
commit 3d0929403b
27 changed files with 1598 additions and 6495 deletions

View file

@ -2,7 +2,6 @@
add_definitions(
-D__WINESRC__
-D_WINE
-DHAVE_REGEX_H
-DHAVE_ALLOCA_H
-D_IMAGEHLP_SOURCE_)
@ -10,15 +9,18 @@ if(ARCH STREQUAL "amd64")
add_definitions(-DUNW_FLAG_NHANDLER=0 -DUNW_FLAG_EHANDLER=1 -DUNW_FLAG_UHANDLER=2 -DUNW_FLAG_CHAININFO=3)
endif()
include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine)
include_directories(
${REACTOS_SOURCE_DIR}/include/reactos/wine
${REACTOS_SOURCE_DIR}/include/reactos/libs/zlib)
spec2def(dbghelp.dll dbghelp.spec ADD_IMPORTLIB)
list(APPEND SOURCE
coff.c
cpu_arm.c
cpu_arm64.c
cpu_i386.c
cpu_ppc.c
cpu_sparc.c
cpu_x86_64.c
crc32.c
dbghelp.c
@ -38,7 +40,6 @@ list(APPEND SOURCE
storage.c
symbol.c
type.c
regex.c
${CMAKE_CURRENT_BINARY_DIR}/dbghelp_stubs.c
${CMAKE_CURRENT_BINARY_DIR}/dbghelp.def)
@ -51,7 +52,7 @@ if(NOT MSVC)
endif()
set_module_type(dbghelp win32dll)
target_link_libraries(dbghelp wine ${PSEH_LIB} oldnames)
target_link_libraries(dbghelp wine ${PSEH_LIB} oldnames zlib)
add_delay_importlibs(dbghelp version)
add_importlibs(dbghelp psapi msvcrt kernel32 ntdll)
add_pch(dbghelp dbghelp_private.h)

View file

@ -424,26 +424,26 @@ DECLSPEC_HIDDEN BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
* If we have spilled onto the next entrypoint, then
* bump the counter..
*/
for (;;)
for (; l+1 < coff_files.files[j].neps; l++)
{
if (l+1 >= coff_files.files[j].neps) break;
symt_get_address(coff_files.files[j].entries[l+1], &addr);
if (((msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress) < addr))
if (symt_get_address(coff_files.files[j].entries[l+1], &addr) &&
msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress < addr)
{
if (coff_files.files[j].entries[l+1]->tag == SymTagFunction)
{
/*
* Add the line number. This is always relative to the
* start of the function, so we need to subtract that offset
* first.
*/
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);
}
break;
l++;
}
if (coff_files.files[j].entries[l+1]->tag == SymTagFunction)
{
/*
* Add the line number. This is always relative to the
* start of the function, so we need to subtract that offset
* first.
*/
symt_get_address(coff_files.files[j].entries[l+1], &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);
}
}
}
}

View file

@ -99,13 +99,6 @@ static BOOL arm_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CON
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 */
set_curr_mode(stm_arm);
frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrModeFlat;
@ -222,8 +215,30 @@ static const char* arm_fetch_regname(unsigned regno)
return NULL;
}
static BOOL arm_fetch_minidump_thread(struct dump_context* dc, unsigned index, unsigned flags, const CONTEXT* ctx)
{
if (ctx->ContextFlags && (flags & ThreadWriteInstructionWindow))
{
/* FIXME: crop values across module boundaries, */
#ifdef __arm__
ULONG base = ctx->Pc <= 0x80 ? 0 : ctx->Pc - 0x80;
minidump_add_memory_block(dc, base, ctx->Pc + 0x80 - base, 0);
#endif
}
return TRUE;
}
static BOOL arm_fetch_minidump_module(struct dump_context* dc, unsigned index, unsigned flags)
{
/* FIXME: actually, we should probably take care of FPO data, unless it's stored in
* function table minidump stream
*/
return FALSE;
}
DECLSPEC_HIDDEN struct cpu cpu_arm = {
IMAGE_FILE_MACHINE_ARMV7,
IMAGE_FILE_MACHINE_ARMNT,
4,
CV_ARM_R0 + 11,
arm_get_addr,
@ -232,4 +247,6 @@ DECLSPEC_HIDDEN struct cpu cpu_arm = {
arm_map_dwarf_register,
arm_fetch_context_reg,
arm_fetch_regname,
arm_fetch_minidump_thread,
arm_fetch_minidump_module,
};

View file

@ -0,0 +1,287 @@
/*
* File cpu_arm64.c
*
* Copyright (C) 2009 Eric Pouech
* Copyright (C) 2010-2013 Andrأ© Hentschel
*
* 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 arm64_get_addr(HANDLE hThread, const CONTEXT* ctx,
enum cpu_addr ca, ADDRESS64* addr)
{
addr->Mode = AddrModeFlat;
addr->Segment = 0; /* don't need segment */
switch (ca)
{
#ifdef __aarch64__
case cpu_addr_pc: addr->Offset = ctx->Pc; return TRUE;
case cpu_addr_stack: addr->Offset = ctx->Sp; return TRUE;
case cpu_addr_frame: addr->Offset = ctx->X29; return TRUE;
#endif
default: addr->Mode = -1;
return FALSE;
}
}
#ifdef __aarch64__
enum st_mode {stm_start, stm_arm64, stm_done};
/* indexes in Reserved array */
#define __CurrentModeCount 0
#define curr_mode (frame->Reserved[__CurrentModeCount] & 0x0F)
#define curr_count (frame->Reserved[__CurrentModeCount] >> 4)
#define set_curr_mode(m) {frame->Reserved[__CurrentModeCount] &= ~0x0F; frame->Reserved[__CurrentModeCount] |= (m & 0x0F);}
#define inc_curr_count() (frame->Reserved[__CurrentModeCount] += 0x10)
/* fetch_next_frame()
*
* modify (at least) context.Pc using unwind information
* either out of debug info (dwarf), or simple Lr trace
*/
static BOOL fetch_next_frame(struct cpu_stack_walk* csw,
CONTEXT* context, DWORD_PTR curr_pc)
{
DWORD_PTR xframe;
DWORD_PTR oldReturn = context->X30;
if (dwarf2_virtual_unwind(csw, curr_pc, context, &xframe))
{
context->Sp = xframe;
context->Pc = oldReturn;
return TRUE;
}
if (context->Pc == context->X30) return FALSE;
context->Pc = oldReturn;
return TRUE;
}
static BOOL arm64_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CONTEXT* context)
{
unsigned deltapc = curr_count <= 1 ? 0 : 4;
/* sanity check */
if (curr_mode >= stm_done) return FALSE;
TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%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" : "ARM64",
wine_dbgstr_longlong(curr_count));
if (curr_mode == stm_start)
{
/* Init done */
set_curr_mode(stm_arm64);
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 (context->Sp != frame->AddrStack.Offset) FIXME("inconsistent Stack Pointer\n");
if (context->Pc != frame->AddrPC.Offset) FIXME("inconsistent Program Counter\n");
if (frame->AddrReturn.Offset == 0) goto done_err;
if (!fetch_next_frame(csw, context, frame->AddrPC.Offset - deltapc))
goto done_err;
}
memset(&frame->Params, 0, sizeof(frame->Params));
/* set frame information */
frame->AddrStack.Offset = context->Sp;
frame->AddrReturn.Offset = context->X30;
frame->AddrFrame.Offset = context->X29;
frame->AddrPC.Offset = context->Pc;
frame->Far = TRUE;
frame->Virtual = TRUE;
inc_curr_count();
TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%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" : "ARM",
wine_dbgstr_longlong(curr_count),
frame->FuncTableEntry);
return TRUE;
done_err:
set_curr_mode(stm_done);
return FALSE;
}
#else
static BOOL arm64_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CONTEXT* context)
{
return FALSE;
}
#endif
static unsigned arm64_map_dwarf_register(unsigned regno)
{
if (regno <= 30) return CV_ARM64_X0 + regno;
if (regno == 31) return CV_ARM64_SP;
FIXME("Don't know how to map register %d\n", regno);
return CV_ARM64_NOREG;
}
static void* arm64_fetch_context_reg(CONTEXT* ctx, unsigned regno, unsigned* size)
{
#ifdef __aarch64__
switch (regno)
{
case CV_ARM64_X0 + 0: *size = sizeof(ctx->X0); return &ctx->X0;
case CV_ARM64_X0 + 1: *size = sizeof(ctx->X1); return &ctx->X1;
case CV_ARM64_X0 + 2: *size = sizeof(ctx->X2); return &ctx->X2;
case CV_ARM64_X0 + 3: *size = sizeof(ctx->X3); return &ctx->X3;
case CV_ARM64_X0 + 4: *size = sizeof(ctx->X4); return &ctx->X4;
case CV_ARM64_X0 + 5: *size = sizeof(ctx->X5); return &ctx->X5;
case CV_ARM64_X0 + 6: *size = sizeof(ctx->X6); return &ctx->X6;
case CV_ARM64_X0 + 7: *size = sizeof(ctx->X7); return &ctx->X7;
case CV_ARM64_X0 + 8: *size = sizeof(ctx->X8); return &ctx->X8;
case CV_ARM64_X0 + 9: *size = sizeof(ctx->X9); return &ctx->X9;
case CV_ARM64_X0 + 10: *size = sizeof(ctx->X10); return &ctx->X10;
case CV_ARM64_X0 + 11: *size = sizeof(ctx->X11); return &ctx->X11;
case CV_ARM64_X0 + 12: *size = sizeof(ctx->X12); return &ctx->X12;
case CV_ARM64_X0 + 13: *size = sizeof(ctx->X13); return &ctx->X13;
case CV_ARM64_X0 + 14: *size = sizeof(ctx->X14); return &ctx->X14;
case CV_ARM64_X0 + 15: *size = sizeof(ctx->X15); return &ctx->X15;
case CV_ARM64_X0 + 16: *size = sizeof(ctx->X16); return &ctx->X16;
case CV_ARM64_X0 + 17: *size = sizeof(ctx->X17); return &ctx->X17;
case CV_ARM64_X0 + 18: *size = sizeof(ctx->X18); return &ctx->X18;
case CV_ARM64_X0 + 19: *size = sizeof(ctx->X19); return &ctx->X19;
case CV_ARM64_X0 + 20: *size = sizeof(ctx->X20); return &ctx->X20;
case CV_ARM64_X0 + 21: *size = sizeof(ctx->X21); return &ctx->X21;
case CV_ARM64_X0 + 22: *size = sizeof(ctx->X22); return &ctx->X22;
case CV_ARM64_X0 + 23: *size = sizeof(ctx->X23); return &ctx->X23;
case CV_ARM64_X0 + 24: *size = sizeof(ctx->X24); return &ctx->X24;
case CV_ARM64_X0 + 25: *size = sizeof(ctx->X25); return &ctx->X25;
case CV_ARM64_X0 + 26: *size = sizeof(ctx->X26); return &ctx->X26;
case CV_ARM64_X0 + 27: *size = sizeof(ctx->X27); return &ctx->X27;
case CV_ARM64_X0 + 28: *size = sizeof(ctx->X28); return &ctx->X28;
case CV_ARM64_X0 + 29: *size = sizeof(ctx->X29); return &ctx->X29;
case CV_ARM64_X0 + 30: *size = sizeof(ctx->X30); return &ctx->X30;
case CV_ARM64_SP: *size = sizeof(ctx->Sp); return &ctx->Sp;
case CV_ARM64_PC: *size = sizeof(ctx->Pc); return &ctx->Pc;
case CV_ARM64_PSTATE: *size = sizeof(ctx->PState); return &ctx->PState;
}
#endif
FIXME("Unknown register %x\n", regno);
return NULL;
}
static const char* arm64_fetch_regname(unsigned regno)
{
switch (regno)
{
case CV_ARM64_X0 + 0: return "x0";
case CV_ARM64_X0 + 1: return "x1";
case CV_ARM64_X0 + 2: return "x2";
case CV_ARM64_X0 + 3: return "x3";
case CV_ARM64_X0 + 4: return "x4";
case CV_ARM64_X0 + 5: return "x5";
case CV_ARM64_X0 + 6: return "x6";
case CV_ARM64_X0 + 7: return "x7";
case CV_ARM64_X0 + 8: return "x8";
case CV_ARM64_X0 + 9: return "x9";
case CV_ARM64_X0 + 10: return "x10";
case CV_ARM64_X0 + 11: return "x11";
case CV_ARM64_X0 + 12: return "x12";
case CV_ARM64_X0 + 13: return "x13";
case CV_ARM64_X0 + 14: return "x14";
case CV_ARM64_X0 + 15: return "x15";
case CV_ARM64_X0 + 16: return "x16";
case CV_ARM64_X0 + 17: return "x17";
case CV_ARM64_X0 + 18: return "x18";
case CV_ARM64_X0 + 19: return "x19";
case CV_ARM64_X0 + 20: return "x20";
case CV_ARM64_X0 + 21: return "x21";
case CV_ARM64_X0 + 22: return "x22";
case CV_ARM64_X0 + 23: return "x23";
case CV_ARM64_X0 + 24: return "x24";
case CV_ARM64_X0 + 25: return "x25";
case CV_ARM64_X0 + 26: return "x26";
case CV_ARM64_X0 + 27: return "x27";
case CV_ARM64_X0 + 28: return "x28";
case CV_ARM64_X0 + 29: return "x29";
case CV_ARM64_X0 + 30: return "x30";
case CV_ARM64_SP: return "sp";
case CV_ARM64_PC: return "pc";
case CV_ARM64_PSTATE: return "cpsr";
}
FIXME("Unknown register %x\n", regno);
return NULL;
}
static BOOL arm64_fetch_minidump_thread(struct dump_context* dc, unsigned index, unsigned flags, const CONTEXT* ctx)
{
if (ctx->ContextFlags && (flags & ThreadWriteInstructionWindow))
{
/* FIXME: crop values across module boundaries, */
#ifdef __aarch64__
ULONG base = ctx->Pc <= 0x80 ? 0 : ctx->Pc - 0x80;
minidump_add_memory_block(dc, base, ctx->Pc + 0x80 - base, 0);
#endif
}
return TRUE;
}
static BOOL arm64_fetch_minidump_module(struct dump_context* dc, unsigned index, unsigned flags)
{
/* FIXME: actually, we should probably take care of FPO data, unless it's stored in
* function table minidump stream
*/
return FALSE;
}
DECLSPEC_HIDDEN struct cpu cpu_arm64 = {
IMAGE_FILE_MACHINE_ARM64,
8,
CV_ARM64_X0 + 29,
arm64_get_addr,
arm64_stack_walk,
NULL,
arm64_map_dwarf_register,
arm64_fetch_context_reg,
arm64_fetch_regname,
arm64_fetch_minidump_thread,
arm64_fetch_minidump_module,
};

View file

@ -115,6 +115,7 @@ static BOOL fetch_next_frame32(struct cpu_stack_walk* csw,
/* do a simple unwind using ebp
* we assume a "regular" prologue in the function has been used
*/
if (!context->Ebp) return FALSE;
context->Esp = context->Ebp + 2 * sizeof(DWORD);
if (!sw_read_mem(csw, context->Ebp + sizeof(DWORD), &val32, sizeof(DWORD)))
{
@ -219,7 +220,7 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
if (NtQueryInformationThread(csw->hThread, ThreadBasicInformation, &info,
sizeof(info), NULL) == STATUS_SUCCESS)
{
curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved);
curr_switch = (DWORD_PTR)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved);
if (!sw_read_mem(csw, curr_switch, &p, sizeof(p)))
{
WARN("Can't read TEB:WOW32Reserved\n");
@ -273,7 +274,6 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
}
else
{
if (frame->AddrFrame.Offset == 0) goto done_err;
if (frame->AddrFrame.Mode == AddrModeFlat)
{
assert(curr_mode == stm_32bit);
@ -339,13 +339,13 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
}
TRACE("Got a 16 bit stack switch:"
"\n\tframe32: %08lx"
"\n\tframe32: %p"
"\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.frame32,
frame16.edx, frame16.ecx, frame16.ebp,
frame16.ds, frame16.es, frame16.fs, frame16.gs,
frame16.callfrom_ip, frame16.module_cs, frame16.relay,
@ -389,7 +389,8 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
frame->AddrPC = frame->AddrReturn;
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),
if (!frame->AddrFrame.Offset ||
!sw_read_mem(csw, sw_xlat_addr(csw, &frame->AddrFrame),
&val16, sizeof(WORD)))
goto done_err;
frame->AddrFrame.Offset = val16;
@ -574,14 +575,16 @@ static void* i386_fetch_context_reg(CONTEXT* ctx, unsigned regno, unsigned* size
case CV_REG_ESP: *size = sizeof(ctx->Esp); return &ctx->Esp;
case CV_REG_EIP: *size = sizeof(ctx->Eip); return &ctx->Eip;
case CV_REG_ST0 + 0: *size = sizeof(long double); return &ctx->FloatSave.RegisterArea[0*sizeof(long double)];
case CV_REG_ST0 + 1: *size = sizeof(long double); return &ctx->FloatSave.RegisterArea[1*sizeof(long double)];
case CV_REG_ST0 + 2: *size = sizeof(long double); return &ctx->FloatSave.RegisterArea[2*sizeof(long double)];
case CV_REG_ST0 + 3: *size = sizeof(long double); return &ctx->FloatSave.RegisterArea[3*sizeof(long double)];
case CV_REG_ST0 + 4: *size = sizeof(long double); return &ctx->FloatSave.RegisterArea[4*sizeof(long double)];
case CV_REG_ST0 + 5: *size = sizeof(long double); return &ctx->FloatSave.RegisterArea[5*sizeof(long double)];
case CV_REG_ST0 + 6: *size = sizeof(long double); return &ctx->FloatSave.RegisterArea[6*sizeof(long double)];
case CV_REG_ST0 + 7: *size = sizeof(long double); return &ctx->FloatSave.RegisterArea[7*sizeof(long double)];
/* These are x87 floating point registers... They do not match a C type in
* the Linux ABI, so hardcode their 80-bitness. */
case CV_REG_ST0 + 0: *size = 10; return &ctx->FloatSave.RegisterArea[0*10];
case CV_REG_ST0 + 1: *size = 10; return &ctx->FloatSave.RegisterArea[1*10];
case CV_REG_ST0 + 2: *size = 10; return &ctx->FloatSave.RegisterArea[2*10];
case CV_REG_ST0 + 3: *size = 10; return &ctx->FloatSave.RegisterArea[3*10];
case CV_REG_ST0 + 4: *size = 10; return &ctx->FloatSave.RegisterArea[4*10];
case CV_REG_ST0 + 5: *size = 10; return &ctx->FloatSave.RegisterArea[5*10];
case CV_REG_ST0 + 6: *size = 10; return &ctx->FloatSave.RegisterArea[6*10];
case CV_REG_ST0 + 7: *size = 10; return &ctx->FloatSave.RegisterArea[7*10];
case CV_REG_CTRL: *size = sizeof(DWORD); return &ctx->FloatSave.ControlWord;
case CV_REG_STAT: *size = sizeof(DWORD); return &ctx->FloatSave.StatusWord;
@ -659,6 +662,28 @@ static const char* i386_fetch_regname(unsigned regno)
return NULL;
}
static BOOL i386_fetch_minidump_thread(struct dump_context* dc, unsigned index, unsigned flags, const CONTEXT* ctx)
{
if (ctx->ContextFlags && (flags & ThreadWriteInstructionWindow))
{
/* FIXME: crop values across module boundaries, */
#ifdef __i386__
ULONG base = ctx->Eip <= 0x80 ? 0 : ctx->Eip - 0x80;
minidump_add_memory_block(dc, base, ctx->Eip + 0x80 - base, 0);
#endif
}
return TRUE;
}
static BOOL i386_fetch_minidump_module(struct dump_context* dc, unsigned index, unsigned flags)
{
/* FIXME: actually, we should probably take care of FPO data, unless it's stored in
* function table minidump stream
*/
return FALSE;
}
DECLSPEC_HIDDEN struct cpu cpu_i386 = {
IMAGE_FILE_MACHINE_I386,
4,
@ -669,4 +694,6 @@ DECLSPEC_HIDDEN struct cpu cpu_i386 = {
i386_map_dwarf_register,
i386_fetch_context_reg,
i386_fetch_regname,
i386_fetch_minidump_thread,
i386_fetch_minidump_module,
};

View file

@ -72,6 +72,18 @@ static const char* ppc_fetch_regname(unsigned regno)
return NULL;
}
static BOOL ppc_fetch_minidump_thread(struct dump_context* dc, unsigned index, unsigned flags, const CONTEXT* ctx)
{
FIXME("NIY\n");
return FALSE;
}
static BOOL ppc_fetch_minidump_module(struct dump_context* dc, unsigned index, unsigned flags)
{
FIXME("NIY\n");
return FALSE;
}
DECLSPEC_HIDDEN struct cpu cpu_ppc = {
IMAGE_FILE_MACHINE_POWERPC,
4,
@ -82,4 +94,6 @@ DECLSPEC_HIDDEN struct cpu cpu_ppc = {
ppc_map_dwarf_register,
ppc_fetch_context_reg,
ppc_fetch_regname,
ppc_fetch_minidump_thread,
ppc_fetch_minidump_module,
};

View file

@ -1,94 +0,0 @@
/*
* File cpu_sparc.c
*
* Copyright (C) 2009-2009, Eric Pouech
* Copyright (C) 2010, Austin English
*
* 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);
#define IMAGE_FILE_MACHINE_SPARC 0x2000
static unsigned sparc_get_addr(HANDLE hThread, const CONTEXT* ctx,
enum cpu_addr ca, ADDRESS64* addr)
{
addr->Mode = AddrModeFlat;
addr->Segment = 0; /* don't need segment */
switch (ca)
{
#ifdef __sparc__
case cpu_addr_pc: addr->Offset = ctx->pc; return TRUE;
case cpu_addr_stack: addr->Offset = ctx->o6; return TRUE;
case cpu_addr_frame: addr->Offset = ctx->i6; return TRUE;
#endif
default: addr->Mode = -1;
return FALSE;
}
}
static BOOL sparc_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CONTEXT* context)
{
FIXME("not done for Sparc\n");
return FALSE;
}
static unsigned sparc_map_dwarf_register(unsigned regno)
{
if (regno <= 7)
return CV_SPARC_G0 + regno;
else if (regno >= 8 && regno <= 15)
return CV_SPARC_O0 + regno - 8;
else if (regno >= 16 && regno <= 23)
return CV_SPARC_L0 + regno - 16;
else if (regno >= 24 && regno <= 31)
return CV_SPARC_I0 + regno - 24;
FIXME("Don't know how to map register %d\n", regno);
return CV_SPARC_NOREG;
}
static void* sparc_fetch_context_reg(CONTEXT* ctx, unsigned regno, unsigned* size)
{
FIXME("not done for Sparc\n");
return NULL;
}
static const char* sparc_fetch_regname(unsigned regno)
{
FIXME("Unknown register %x\n", regno);
return NULL;
}
DECLSPEC_HIDDEN struct cpu cpu_sparc = {
IMAGE_FILE_MACHINE_SPARC,
4,
CV_REG_NONE, /* FIXME */
sparc_get_addr,
sparc_stack_walk,
NULL,
sparc_map_dwarf_register,
sparc_fetch_context_reg,
sparc_fetch_regname,
};

View file

@ -2,7 +2,7 @@
* File cpu_x86_64.c
*
* Copyright (C) 1999, 2005 Alexandre Julliard
* Copyright (C) 2009 Eric Pouech.
* Copyright (C) 2009, 2011 Eric Pouech.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -125,39 +125,45 @@ union handler_data
ULONG handler;
};
static void dump_unwind_info(HANDLE hProcess, ULONG64 base, RUNTIME_FUNCTION *function)
static void dump_unwind_info(struct cpu_stack_walk* csw, ULONG64 base, RUNTIME_FUNCTION *function)
{
static const char * const reg_names[16] =
{ "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
union handler_data *handler_data;
union handler_data handler_data;
char buffer[sizeof(UNWIND_INFO) + 256 * sizeof(UNWIND_CODE)];
UNWIND_INFO* info = (UNWIND_INFO*)buffer;
unsigned int i, count;
SIZE_T r;
RUNTIME_FUNCTION snext;
ULONG64 addr;
TRACE("**** func %x-%x\n", function->BeginAddress, function->EndAddress);
for (;;)
{
if (function->UnwindData & 1)
{
#if 0
RUNTIME_FUNCTION *next = (RUNTIME_FUNCTION*)((char*)base + (function->UnwindData & ~1));
if (!sw_read_mem(csw, base + function->UnwindData, &snext, sizeof(snext)))
{
TRACE("Couldn't unwind RUNTIME_INFO at %lx\n", base + function->UnwindData);
return;
}
TRACE("unwind info for function %p-%p chained to function %p-%p\n",
(char*)base + function->BeginAddress, (char*)base + function->EndAddress,
(char*)base + next->BeginAddress, (char*)base + next->EndAddress);
function = next;
(char*)base + snext.BeginAddress, (char*)base + snext.EndAddress);
function = &snext;
continue;
#else
FIXME("NOT SUPPORTED\n");
#endif
}
ReadProcessMemory(hProcess, (char*)base + function->UnwindData, info, sizeof(*info), &r);
ReadProcessMemory(hProcess, (char*)base + function->UnwindData + FIELD_OFFSET(UNWIND_INFO, UnwindCode),
info->UnwindCode, 256 * sizeof(UNWIND_CODE), &r);
addr = base + function->UnwindData;
if (!sw_read_mem(csw, addr, info, FIELD_OFFSET(UNWIND_INFO, UnwindCode)) ||
!sw_read_mem(csw, addr + FIELD_OFFSET(UNWIND_INFO, UnwindCode),
info->UnwindCode, info->CountOfCodes * sizeof(UNWIND_CODE)))
{
FIXME("couldn't read memory for UNWIND_INFO at %lx\n", addr);
return;
}
TRACE("unwind info at %p flags %x prolog 0x%x bytes function %p-%p\n",
info, info->Flags, info->SizeOfProlog,
(char*)addr, info->Flags, info->SizeOfProlog,
(char*)base + function->BeginAddress, (char*)base + function->EndAddress);
if (info->FrameRegister)
@ -222,18 +228,31 @@ static void dump_unwind_info(HANDLE hProcess, ULONG64 base, RUNTIME_FUNCTION *fu
}
}
handler_data = (union handler_data*)&info->UnwindCode[(info->CountOfCodes + 1) & ~1];
addr += FIELD_OFFSET(UNWIND_INFO, UnwindCode) +
((info->CountOfCodes + 1) & ~1) * sizeof(UNWIND_CODE);
if (info->Flags & UNW_FLAG_CHAININFO)
{
if (!sw_read_mem(csw, addr, &handler_data, sizeof(handler_data.chain)))
{
FIXME("couldn't read memory for handler_data.chain\n");
return;
}
TRACE(" chained to function %p-%p\n",
(char*)base + handler_data->chain.BeginAddress,
(char*)base + handler_data->chain.EndAddress);
function = &handler_data->chain;
(char*)base + handler_data.chain.BeginAddress,
(char*)base + handler_data.chain.EndAddress);
function = &handler_data.chain;
continue;
}
if (info->Flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
{
if (!sw_read_mem(csw, addr, &handler_data, sizeof(handler_data.handler)))
{
FIXME("couldn't read memory for handler_data.handler\n");
return;
}
TRACE(" handler %p data at %p\n",
(char*)base + handler_data->handler, &handler_data->handler + 1);
(char*)base + handler_data.handler, (char*)addr + sizeof(handler_data.handler));
}
break;
}
}
@ -271,9 +290,11 @@ static int get_opcode_size(UNWIND_CODE op)
}
}
static BOOL is_inside_epilog(struct cpu_stack_walk* csw, DWORD64 pc)
static BOOL is_inside_epilog(struct cpu_stack_walk* csw, DWORD64 pc,
DWORD64 base, const RUNTIME_FUNCTION *function )
{
BYTE op0, op1, op2;
BYTE op0, op1, op2;
LONG val32;
if (!sw_read_mem(csw, pc, &op0, 1)) return FALSE;
@ -319,12 +340,9 @@ static BOOL is_inside_epilog(struct cpu_stack_walk* csw, DWORD64 pc)
/* now check for various pop instructions */
for (;;)
{
BYTE rex = 0;
if (!sw_read_mem(csw, pc, &op0, 1)) return FALSE;
if ((op0 & 0xf0) == 0x40)
if ((op0 & 0xf0) == 0x40) /* rex prefix */
{
rex = op0 & 0x0f; /* rex prefix */
if (!sw_read_mem(csw, ++pc, &op0, 1)) return FALSE;
}
@ -343,12 +361,110 @@ static BOOL is_inside_epilog(struct cpu_stack_walk* csw, DWORD64 pc)
case 0xc2: /* ret $nn */
case 0xc3: /* ret */
return TRUE;
/* FIXME: add various jump instructions */
case 0xe9: /* jmp nnnn */
if (!sw_read_mem(csw, pc + 1, &val32, sizeof(LONG))) return FALSE;
pc += 5 + val32;
if (pc - base >= function->BeginAddress && pc - base < function->EndAddress)
continue;
break;
case 0xeb: /* jmp n */
if (!sw_read_mem(csw, pc + 1, &op1, 1)) return FALSE;
pc += 2 + (signed char)op1;
if (pc - base >= function->BeginAddress && pc - base < function->EndAddress)
continue;
break;
case 0xf3: /* rep; ret (for amd64 prediction bug) */
if (!sw_read_mem(csw, pc + 1, &op1, 1)) return FALSE;
return op1 == 0xc3;
}
return FALSE;
}
}
static BOOL interpret_epilog(struct cpu_stack_walk* csw, ULONG64 pc, CONTEXT *context )
{
BYTE insn, val8;
WORD val16;
LONG val32;
DWORD64 val64;
for (;;)
{
BYTE rex = 0;
if (!sw_read_mem(csw, pc, &insn, 1)) return FALSE;
if ((insn & 0xf0) == 0x40)
{
rex = insn & 0x0f; /* rex prefix */
if (!sw_read_mem(csw, ++pc, &insn, 1)) return FALSE;
}
switch (insn)
{
case 0x58: /* pop %rax/r8 */
case 0x59: /* pop %rcx/r9 */
case 0x5a: /* pop %rdx/r10 */
case 0x5b: /* pop %rbx/r11 */
case 0x5c: /* pop %rsp/r12 */
case 0x5d: /* pop %rbp/r13 */
case 0x5e: /* pop %rsi/r14 */
case 0x5f: /* pop %rdi/r15 */
if (!sw_read_mem(csw, context->Rsp, &val64, sizeof(DWORD64))) return FALSE;
set_int_reg(context, insn - 0x58 + (rex & 1) * 8, val64);
context->Rsp += sizeof(ULONG64);
pc++;
continue;
case 0x81: /* add $nnnn,%rsp */
if (!sw_read_mem(csw, pc + 2, &val32, sizeof(LONG))) return FALSE;
context->Rsp += val32;
pc += 2 + sizeof(LONG);
continue;
case 0x83: /* add $n,%rsp */
if (!sw_read_mem(csw, pc + 2, &val8, sizeof(BYTE))) return FALSE;
context->Rsp += (signed char)val8;
pc += 3;
continue;
case 0x8d:
if (!sw_read_mem(csw, pc + 1, &insn, sizeof(BYTE))) return FALSE;
if ((insn >> 6) == 1) /* lea n(reg),%rsp */
{
if (!sw_read_mem(csw, pc + 2, &val8, sizeof(BYTE))) return FALSE;
context->Rsp = get_int_reg( context, (insn & 7) + (rex & 1) * 8 ) + (signed char)val8;
pc += 3;
}
else /* lea nnnn(reg),%rsp */
{
if (!sw_read_mem(csw, pc + 2, &val32, sizeof(LONG))) return FALSE;
context->Rsp = get_int_reg( context, (insn & 7) + (rex & 1) * 8 ) + val32;
pc += 2 + sizeof(LONG);
}
continue;
case 0xc2: /* ret $nn */
if (!sw_read_mem(csw, context->Rsp, &val64, sizeof(DWORD64))) return FALSE;
if (!sw_read_mem(csw, pc + 1, &val16, sizeof(WORD))) return FALSE;
context->Rip = val64;
context->Rsp += sizeof(ULONG64) + val16;
return TRUE;
case 0xc3: /* ret */
case 0xf3: /* rep; ret */
if (!sw_read_mem(csw, context->Rsp, &val64, sizeof(DWORD64))) return FALSE;
context->Rip = val64;
context->Rsp += sizeof(ULONG64);
return TRUE;
case 0xe9: /* jmp nnnn */
if (!sw_read_mem(csw, pc + 1, &val32, sizeof(LONG))) return FALSE;
pc += 5 + val32;
continue;
case 0xeb: /* jmp n */
if (!sw_read_mem(csw, pc + 1, &val8, sizeof(BYTE))) return FALSE;
pc += 2 + (signed char)val8;
continue;
}
FIXME("unsupported insn %x\n", insn);
return FALSE;
}
}
static BOOL default_unwind(struct cpu_stack_walk* csw, CONTEXT* context)
{
if (!sw_read_mem(csw, context->Rsp, &context->Rip, sizeof(DWORD64)))
@ -372,7 +488,7 @@ static BOOL interpret_function_table_entry(struct cpu_stack_walk* csw,
/* FIXME: we have some assumptions here */
assert(context);
dump_unwind_info(csw->hProcess, sw_module_base(csw, context->Rip), function);
dump_unwind_info(csw, sw_module_base(csw, context->Rip), function);
newframe = context->Rsp;
for (;;)
{
@ -402,10 +518,9 @@ static BOOL interpret_function_table_entry(struct cpu_stack_walk* csw,
else
{
prolog_offset = ~0;
if (is_inside_epilog(csw, context->Rip))
if (is_inside_epilog(csw, context->Rip, base, function))
{
FIXME("epilog management not fully done\n");
/* interpret_epilog((const BYTE*)frame->AddrPC.Offset, context); */
interpret_epilog(csw, context->Rip, context);
return TRUE;
}
}
@ -433,22 +548,22 @@ static BOOL interpret_function_table_entry(struct cpu_stack_walk* csw,
break;
case UWOP_SAVE_NONVOL: /* movq %reg,n(%rsp) */
off = newframe + *(USHORT*)&info->UnwindCode[i+1] * 8;
if (!sw_read_mem(csw, context->Rsp, &value, sizeof(DWORD64))) return FALSE;
if (!sw_read_mem(csw, off, &value, sizeof(DWORD64))) return FALSE;
set_int_reg(context, info->UnwindCode[i].OpInfo, value);
break;
case UWOP_SAVE_NONVOL_FAR: /* movq %reg,nn(%rsp) */
off = newframe + *(DWORD*)&info->UnwindCode[i+1];
if (!sw_read_mem(csw, context->Rsp, &value, sizeof(DWORD64))) return FALSE;
if (!sw_read_mem(csw, off, &value, sizeof(DWORD64))) return FALSE;
set_int_reg(context, info->UnwindCode[i].OpInfo, value);
break;
case UWOP_SAVE_XMM128: /* movaps %xmmreg,n(%rsp) */
off = newframe + *(USHORT*)&info->UnwindCode[i+1] * 16;
if (!sw_read_mem(csw, context->Rsp, &floatvalue, sizeof(M128A))) return FALSE;
if (!sw_read_mem(csw, off, &floatvalue, sizeof(M128A))) return FALSE;
set_float_reg(context, info->UnwindCode[i].OpInfo, floatvalue);
break;
case UWOP_SAVE_XMM128_FAR: /* movaps %xmmreg,nn(%rsp) */
off = newframe + *(DWORD*)&info->UnwindCode[i+1];
if (!sw_read_mem(csw, context->Rsp, &floatvalue, sizeof(M128A))) return FALSE;
if (!sw_read_mem(csw, off, &floatvalue, sizeof(M128A))) return FALSE;
set_float_reg(context, info->UnwindCode[i].OpInfo, floatvalue);
break;
case UWOP_PUSH_MACHFRAME:
@ -796,6 +911,64 @@ static const char* x86_64_fetch_regname(unsigned regno)
return NULL;
}
static BOOL x86_64_fetch_minidump_thread(struct dump_context* dc, unsigned index, unsigned flags, const CONTEXT* ctx)
{
if (ctx->ContextFlags && (flags & ThreadWriteInstructionWindow))
{
/* FIXME: crop values across module boundaries, */
#ifdef __x86_64__
ULONG64 base = ctx->Rip <= 0x80 ? 0 : ctx->Rip - 0x80;
minidump_add_memory_block(dc, base, ctx->Rip + 0x80 - base, 0);
#endif
}
return TRUE;
}
static BOOL x86_64_fetch_minidump_module(struct dump_context* dc, unsigned index, unsigned flags)
{
/* FIXME: not sure about the flags... */
if (1)
{
/* FIXME: crop values across module boundaries, */
#ifdef __x86_64__
struct process* pcs;
struct module* module;
const RUNTIME_FUNCTION* rtf;
ULONG size;
if (!(pcs = process_find_by_handle(dc->hProcess)) ||
!(module = module_find_by_addr(pcs, dc->modules[index].base, DMT_UNKNOWN)))
return FALSE;
rtf = (const RUNTIME_FUNCTION*)pe_map_directory(module, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size);
if (rtf)
{
const RUNTIME_FUNCTION* end = (const RUNTIME_FUNCTION*)((const char*)rtf + size);
UNWIND_INFO ui;
while (rtf + 1 < end)
{
while (rtf->UnwindData & 1) /* follow chained entry */
{
FIXME("RunTime_Function outside IMAGE_DIRECTORY_ENTRY_EXCEPTION unimplemented yet!\n");
return FALSE;
/* we need to read into the other process */
/* rtf = (RUNTIME_FUNCTION*)(module->module.BaseOfImage + (rtf->UnwindData & ~1)); */
}
if (ReadProcessMemory(dc->hProcess,
(void*)(dc->modules[index].base + rtf->UnwindData),
&ui, sizeof(ui), NULL))
minidump_add_memory_block(dc, dc->modules[index].base + rtf->UnwindData,
FIELD_OFFSET(UNWIND_INFO, UnwindCode) + ui.CountOfCodes * sizeof(UNWIND_CODE), 0);
rtf++;
}
}
#endif
}
return TRUE;
}
DECLSPEC_HIDDEN struct cpu cpu_x86_64 = {
IMAGE_FILE_MACHINE_AMD64,
8,
@ -806,4 +979,6 @@ DECLSPEC_HIDDEN struct cpu cpu_x86_64 = {
x86_64_map_dwarf_register,
x86_64_fetch_context_reg,
x86_64_fetch_regname,
x86_64_fetch_minidump_thread,
x86_64_fetch_minidump_module,
};

View file

@ -151,9 +151,9 @@ const char* wine_dbgstr_addr(const ADDRESS64* addr)
}
}
extern struct cpu cpu_i386, cpu_x86_64, cpu_ppc, cpu_sparc, cpu_arm;
extern struct cpu cpu_i386, cpu_x86_64, cpu_ppc, cpu_arm, cpu_arm64;
static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, &cpu_ppc, &cpu_sparc, &cpu_arm, NULL};
static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, &cpu_ppc, &cpu_arm, &cpu_arm64, NULL};
struct cpu* dbghelp_current_cpu =
#if defined(__i386__)
&cpu_i386
@ -161,10 +161,10 @@ struct cpu* dbghelp_current_cpu =
&cpu_x86_64
#elif defined(__powerpc__)
&cpu_ppc
#elif defined(__sparc__)
&cpu_sparc
#elif defined(__arm__)
&cpu_arm
#elif defined(__aarch64__)
&cpu_arm64
#else
#error define support for your CPU
#endif

View file

@ -361,8 +361,6 @@ struct module
{
struct process* process;
IMAGEHLP_MODULEW64 module;
/* ANSI copy of module.ModuleName for efficiency */
char module_name[MAX_PATH];
struct module* next;
enum module_type type : 16;
unsigned short is_virtual : 1;
@ -469,6 +467,55 @@ struct cpu_stack_walk
} u;
};
struct dump_memory
{
ULONG64 base;
ULONG size;
ULONG rva;
};
struct dump_module
{
unsigned is_elf;
ULONG64 base;
ULONG size;
DWORD timestamp;
DWORD checksum;
WCHAR name[MAX_PATH];
};
struct dump_thread
{
ULONG tid;
ULONG prio_class;
ULONG curr_prio;
};
struct dump_context
{
/* process & thread information */
HANDLE hProcess;
DWORD pid;
unsigned flags_out;
/* thread information */
struct dump_thread* threads;
unsigned num_threads;
/* module information */
struct dump_module* modules;
unsigned num_modules;
unsigned alloc_modules;
/* exception information */
/* output information */
MINIDUMP_TYPE type;
HANDLE hFile;
RVA rva;
struct dump_memory* mem;
unsigned num_mem;
unsigned alloc_mem;
/* callback information */
MINIDUMP_CALLBACK_INFORMATION* cb;
};
enum cpu_addr {cpu_addr_pc, cpu_addr_stack, cpu_addr_frame};
struct cpu
{
@ -492,6 +539,10 @@ struct cpu
/* context related manipulation */
void* (*fetch_context_reg)(CONTEXT* context, unsigned regno, unsigned* size);
const char* (*fetch_regname)(unsigned regno);
/* minidump per CPU extension */
BOOL (*fetch_minidump_thread)(struct dump_context* dc, unsigned index, unsigned flags, const CONTEXT* ctx);
BOOL (*fetch_minidump_module)(struct dump_context* dc, unsigned index, unsigned flags);
};
extern struct cpu* dbghelp_current_cpu DECLSPEC_HIDDEN;
@ -533,13 +584,16 @@ extern struct module*
extern BOOL macho_read_wine_loader_dbg_info(struct process* pcs) DECLSPEC_HIDDEN;
extern BOOL macho_synchronize_module_list(struct process* pcs) DECLSPEC_HIDDEN;
/* minidump.c */
void minidump_add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva);
/* module.c */
extern const WCHAR S_ElfW[] DECLSPEC_HIDDEN;
extern const WCHAR S_WineLoaderW[] DECLSPEC_HIDDEN;
extern const WCHAR S_SlashW[] DECLSPEC_HIDDEN;
extern struct module*
module_find_by_addr(const struct process* pcs, unsigned long addr,
module_find_by_addr(const struct process* pcs, DWORD64 addr,
enum module_type type) DECLSPEC_HIDDEN;
extern struct module*
module_find_by_nameW(const struct process* pcs,
@ -628,6 +682,7 @@ extern DWORD64 sw_module_base(struct cpu_stack_walk* csw, DWORD64 addr) DEC
/* symbol.c */
extern const char* symt_get_name(const struct symt* sym) DECLSPEC_HIDDEN;
extern WCHAR* symt_get_nameW(const struct symt* sym) DECLSPEC_HIDDEN;
extern BOOL symt_get_address(const struct symt* type, ULONG64* addr) DECLSPEC_HIDDEN;
extern int symt_cmp_addr(const void* p1, const void* p2) DECLSPEC_HIDDEN;
extern void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si) DECLSPEC_HIDDEN;

View file

@ -40,9 +40,14 @@
#endif
//#include <stdio.h>
#include <assert.h>
//#include <stdarg.h>
#include <stdarg.h>
#ifdef HAVE_ZLIB
#include <zlib.h>
#endif
//#include "windef.h"
#include <winternl.h>
//#include "winbase.h"
//#include "winuser.h"
//#include "ole2.h"
@ -157,6 +162,7 @@ typedef struct dwarf2_debug_info_s
typedef struct dwarf2_section_s
{
BOOL compressed;
const unsigned char* address;
unsigned size;
DWORD_PTR rva;
@ -2188,7 +2194,7 @@ static BOOL dwarf2_parse_line_numbers(const dwarf2_section_t* sections,
vector_init(&files, sizeof(unsigned), 16);
while (*traverse.data)
{
unsigned int dir_index, mod_time, length;
unsigned int dir_index, mod_time;
const char* name;
const char* dir;
unsigned* psrc;
@ -2199,7 +2205,7 @@ static BOOL dwarf2_parse_line_numbers(const dwarf2_section_t* sections,
mod_time = dwarf2_leb128_as_unsigned(&traverse);
length = dwarf2_leb128_as_unsigned(&traverse);
dir = *(const char**)vector_at(&dirs, dir_index);
TRACE("Got file %s/%s (%u,%u)\n", dir, name, mod_time, length);
TRACE("Got file %s/%s (%u,%lu)\n", dir, name, mod_time, length);
psrc = vector_add(&files, &ctx->pool);
*psrc = source_new(ctx->module, dir, name);
}
@ -2270,15 +2276,19 @@ static BOOL dwarf2_parse_line_numbers(const dwarf2_section_t* sections,
address = ctx->load_offset + dwarf2_parse_addr(&traverse);
break;
case DW_LNE_define_file:
FIXME("not handled %s\n", traverse.data);
FIXME("not handled define file %s\n", traverse.data);
traverse.data += strlen((const char *)traverse.data) + 1;
dwarf2_leb128_as_unsigned(&traverse);
dwarf2_leb128_as_unsigned(&traverse);
dwarf2_leb128_as_unsigned(&traverse);
break;
case DW_LNE_set_discriminator:
WARN("not handled %s\n", traverse.data);
dwarf2_leb128_as_unsigned(&traverse);
{
unsigned descr;
descr = dwarf2_leb128_as_unsigned(&traverse);
WARN("not handled discriminator %x\n", descr);
}
break;
default:
FIXME("Unsupported extended opcode %x\n", extopcode);
@ -2632,6 +2642,15 @@ static BOOL dwarf2_get_cie(unsigned long addr, struct module* module, DWORD_PTR
const BYTE* start_data = fde_ctx->data;
cie_id = in_eh_frame ? 0 : DW_CIE_ID;
/* skip 0-padding at beginning of section (alignment) */
while (fde_ctx->data + 2 * 4 < fde_ctx->end_data)
{
if (dwarf2_parse_u4(fde_ctx))
{
fde_ctx->data -= 4;
break;
}
}
for (; fde_ctx->data + 2 * 4 < fde_ctx->end_data; fde_ctx->data = ptr_blk)
{
/* find the FDE for address addr (skip CIE) */
@ -2659,7 +2678,9 @@ static BOOL dwarf2_get_cie(unsigned long addr, struct module* module, DWORD_PTR
cie_ctx->end_data = cie_ptr + 4 + dwarf2_parse_u4(cie_ctx);
if (dwarf2_parse_u4(cie_ctx) != cie_id)
{
FIXME("wrong CIE pointer\n");
FIXME("wrong CIE pointer at %x from FDE %x\n",
(unsigned)(cie_ptr - start_data),
(unsigned)(fde_ctx->data - start_data));
return FALSE;
}
if (!parse_cie_details(cie_ctx, info)) return FALSE;
@ -2840,7 +2861,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx,
ULONG_PTR offset = (op == DW_CFA_def_cfa) ? dwarf2_leb128_as_unsigned(ctx)
: dwarf2_leb128_as_signed(ctx) * info->data_align;
if (!valid_reg(reg)) break;
TRACE("%lx: DW_CFA_def_cfa %s, %lu\n",
TRACE("%lx: DW_CFA_def_cfa %s, %ld\n",
info->ip,
dbghelp_current_cpu->fetch_regname(dbghelp_current_cpu->map_dwarf_register(reg)),
offset);
@ -2865,7 +2886,7 @@ static void execute_cfa_instructions(dwarf2_traverse_context_t* ctx,
{
ULONG_PTR offset = (op == DW_CFA_def_cfa_offset) ? dwarf2_leb128_as_unsigned(ctx)
: dwarf2_leb128_as_signed(ctx) * info->data_align;
TRACE("%lx: DW_CFA_def_cfa_offset %lu\n", info->ip, offset);
TRACE("%lx: DW_CFA_def_cfa_offset %ld\n", info->ip, offset);
info->state.cfa_offset = offset;
info->state.cfa_rule = RULE_CFA_OFFSET;
break;
@ -3267,29 +3288,134 @@ static void dwarf2_location_compute(struct process* pcs,
}
}
static void dwarf2_module_remove(struct process* pcs, struct module_format* modfmt)
#ifdef HAVE_ZLIB
static void *zalloc(void *priv, uInt items, uInt sz)
{
HeapFree(GetProcessHeap(), 0, modfmt);
return HeapAlloc(GetProcessHeap(), 0, items * sz);
}
static void zfree(void *priv, void *addr)
{
HeapFree(GetProcessHeap(), 0, addr);
}
static inline BOOL dwarf2_init_zsection(dwarf2_section_t* section,
const char* zsectname,
struct image_section_map* ism)
{
z_stream z;
LARGE_INTEGER li;
int res;
BOOL ret = FALSE;
BYTE *addr, *sect = (BYTE *)image_map_section(ism);
size_t sz = image_get_map_size(ism);
if (sz <= 12 || memcmp(sect, "ZLIB", 4))
{
ERR("invalid compressed section %s\n", zsectname);
goto out;
}
#ifdef WORDS_BIGENDIAN
li.u.HighPart = *(DWORD*)&sect[4];
li.u.LowPart = *(DWORD*)&sect[8];
#else
li.u.HighPart = RtlUlongByteSwap(*(DWORD*)&sect[4]);
li.u.LowPart = RtlUlongByteSwap(*(DWORD*)&sect[8]);
#endif
addr = HeapAlloc(GetProcessHeap(), 0, li.QuadPart);
if (!addr)
goto out;
z.next_in = &sect[12];
z.avail_in = sz - 12;
z.opaque = NULL;
z.zalloc = zalloc;
z.zfree = zfree;
res = inflateInit(&z);
if (res != Z_OK)
{
FIXME("inflateInit failed with %i / %s\n", res, z.msg);
goto out_free;
}
do {
z.next_out = addr + z.total_out;
z.avail_out = li.QuadPart - z.total_out;
res = inflate(&z, Z_FINISH);
} while (z.avail_in && res == Z_STREAM_END);
if (res != Z_STREAM_END)
{
FIXME("Decompression failed with %i / %s\n", res, z.msg);
goto out_end;
}
ret = TRUE;
section->compressed = TRUE;
section->address = addr;
section->rva = image_get_map_rva(ism);
section->size = z.total_out;
out_end:
inflateEnd(&z);
out_free:
if (!ret)
HeapFree(GetProcessHeap(), 0, addr);
out:
image_unmap_section(ism);
return ret;
}
#endif
static inline BOOL dwarf2_init_section(dwarf2_section_t* section, struct image_file_map* fmap,
const char* sectname, struct image_section_map* ism)
const char* sectname, const char* zsectname,
struct image_section_map* ism)
{
struct image_section_map local_ism;
if (!ism) ism = &local_ism;
if (!image_find_section(fmap, sectname, ism))
section->compressed = FALSE;
if (image_find_section(fmap, sectname, ism))
{
section->address = NULL;
section->size = 0;
section->rva = 0;
return FALSE;
section->address = (const BYTE*)image_map_section(ism);
section->size = image_get_map_size(ism);
section->rva = image_get_map_rva(ism);
return TRUE;
}
section->address = (const BYTE*)image_map_section(ism);
section->size = image_get_map_size(ism);
section->rva = image_get_map_rva(ism);
return TRUE;
section->address = NULL;
section->size = 0;
section->rva = 0;
if (zsectname && image_find_section(fmap, zsectname, ism))
{
#ifdef HAVE_ZLIB
return dwarf2_init_zsection(section, zsectname, ism);
#else
FIXME("dbghelp not built with zlib, but compressed section found\n" );
#endif
}
return FALSE;
}
static inline void dwarf2_fini_section(dwarf2_section_t* section)
{
if (section->compressed)
HeapFree(GetProcessHeap(), 0, (void*)section->address);
}
static void dwarf2_module_remove(struct process* pcs, struct module_format* modfmt)
{
dwarf2_fini_section(&modfmt->u.dwarf2_info->debug_loc);
dwarf2_fini_section(&modfmt->u.dwarf2_info->debug_frame);
HeapFree(GetProcessHeap(), 0, modfmt);
}
BOOL dwarf2_parse(struct module* module, unsigned long load_offset,
@ -3303,12 +3429,12 @@ BOOL dwarf2_parse(struct module* module, unsigned long load_offset,
BOOL ret = TRUE;
struct module_format* dwarf2_modfmt;
dwarf2_init_section(&eh_frame, fmap, ".eh_frame", &eh_frame_sect);
dwarf2_init_section(&section[section_debug], fmap, ".debug_info", &debug_sect);
dwarf2_init_section(&section[section_abbrev], fmap, ".debug_abbrev", &debug_abbrev_sect);
dwarf2_init_section(&section[section_string], fmap, ".debug_str", &debug_str_sect);
dwarf2_init_section(&section[section_line], fmap, ".debug_line", &debug_line_sect);
dwarf2_init_section(&section[section_ranges], fmap, ".debug_ranges", &debug_ranges_sect);
dwarf2_init_section(&eh_frame, fmap, ".eh_frame", NULL, &eh_frame_sect);
dwarf2_init_section(&section[section_debug], fmap, ".debug_info", ".zdebug_info", &debug_sect);
dwarf2_init_section(&section[section_abbrev], fmap, ".debug_abbrev", ".zdebug_abbrev", &debug_abbrev_sect);
dwarf2_init_section(&section[section_string], fmap, ".debug_str", ".zdebug_str", &debug_str_sect);
dwarf2_init_section(&section[section_line], fmap, ".debug_line", ".zdebug_line", &debug_line_sect);
dwarf2_init_section(&section[section_ranges], fmap, ".debug_ranges", ".zdebug_ranges", &debug_ranges_sect);
/* to do anything useful we need either .eh_frame or .debug_info */
if ((!eh_frame.address || eh_frame.address == IMAGE_NO_MAP) &&
@ -3350,8 +3476,8 @@ BOOL dwarf2_parse(struct module* module, unsigned long load_offset,
/* As we'll need later some sections' content, we won't unmap these
* sections upon existing this function
*/
dwarf2_init_section(&dwarf2_modfmt->u.dwarf2_info->debug_loc, fmap, ".debug_loc", NULL);
dwarf2_init_section(&dwarf2_modfmt->u.dwarf2_info->debug_frame, fmap, ".debug_frame", NULL);
dwarf2_init_section(&dwarf2_modfmt->u.dwarf2_info->debug_loc, fmap, ".debug_loc", ".zdebug_loc", NULL);
dwarf2_init_section(&dwarf2_modfmt->u.dwarf2_info->debug_frame, fmap, ".debug_frame", ".zdebug_frame", NULL);
dwarf2_modfmt->u.dwarf2_info->eh_frame = eh_frame;
while (mod_ctx.data < mod_ctx.end_data)
@ -3366,7 +3492,16 @@ BOOL dwarf2_parse(struct module* module, unsigned long load_offset,
dwarf2_modfmt->module->module.SourceIndexed = TRUE;
dwarf2_modfmt->module->module.Publics = TRUE;
/* set the word_size for eh_frame parsing */
dwarf2_modfmt->u.dwarf2_info->word_size = fmap->addr_size / 8;
leave:
dwarf2_fini_section(&section[section_debug]);
dwarf2_fini_section(&section[section_abbrev]);
dwarf2_fini_section(&section[section_string]);
dwarf2_fini_section(&section[section_line]);
dwarf2_fini_section(&section[section_ranges]);
image_unmap_section(&debug_sect);
image_unmap_section(&debug_abbrev_sect);
image_unmap_section(&debug_str_sect);

View file

@ -56,6 +56,10 @@
#define ELF_INFO_MODULE 0x0002
#define ELF_INFO_NAME 0x0004
#ifndef NT_GNU_BUILD_ID
#define NT_GNU_BUILD_ID 3
#endif
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
struct elf_info
@ -98,9 +102,7 @@ struct elf_module_info
const char* elf_map_section(struct image_section_map* ism)
{
struct elf_file_map* fmap = &ism->fmap->u.elf;
unsigned long pgsz = getpagesize();
unsigned long ofst, size;
size_t ofst, size, pgsz = sysconf( _SC_PAGESIZE );
assert(ism->fmap->modtype == DMT_ELF);
if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.elf.elfhdr.e_shnum ||
@ -170,12 +172,10 @@ void elf_unmap_section(struct image_section_map* ism)
if (ism->sidx >= 0 && ism->sidx < fmap->elfhdr.e_shnum && !fmap->target_copy &&
fmap->sect[ism->sidx].mapped != IMAGE_NO_MAP)
{
unsigned long pgsz = getpagesize();
unsigned long ofst, size;
ofst = fmap->sect[ism->sidx].shdr.sh_offset & ~(pgsz - 1);
size = ((fmap->sect[ism->sidx].shdr.sh_offset +
fmap->sect[ism->sidx].shdr.sh_size + pgsz - 1) & ~(pgsz - 1)) - ofst;
size_t pgsz = sysconf( _SC_PAGESIZE );
size_t ofst = fmap->sect[ism->sidx].shdr.sh_offset & ~(pgsz - 1);
size_t size = ((fmap->sect[ism->sidx].shdr.sh_offset +
fmap->sect[ism->sidx].shdr.sh_size + pgsz - 1) & ~(pgsz - 1)) - ofst;
if (munmap((char*)fmap->sect[ism->sidx].mapped, size) < 0)
WARN("Couldn't unmap the section\n");
fmap->sect[ism->sidx].mapped = IMAGE_NO_MAP;
@ -273,9 +273,9 @@ static BOOL elf_map_file(struct elf_map_file_data* emfd, struct image_file_map*
{
static const BYTE elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
struct stat statbuf;
int i;
unsigned int i;
Elf_Phdr phdr;
unsigned long tmp, page_mask = getpagesize() - 1;
size_t tmp, page_mask = sysconf( _SC_PAGESIZE ) - 1;
char* filename;
unsigned len;
BOOL ret = FALSE;
@ -324,6 +324,7 @@ static BOOL elf_map_file(struct elf_map_file_data* emfd, struct image_file_map*
#else
if (fmap->u.elf.elfhdr.e_ident[EI_CLASS] != ELFCLASS32) goto done;
#endif
fmap->addr_size = fmap->u.elf.elfhdr.e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
fmap->u.elf.sect = HeapAlloc(GetProcessHeap(), 0,
fmap->u.elf.elfhdr.e_shnum * sizeof(fmap->u.elf.sect[0]));
if (!fmap->u.elf.sect) goto done;
@ -673,11 +674,11 @@ static void elf_finish_stabs_info(struct module* module, const struct hash_table
((struct symt_data*)sym)->container);
if (symp)
{
if (((struct symt_data*)sym)->u.var.offset != elf_info->elf_addr &&
((struct symt_data*)sym)->u.var.offset != elf_info->elf_addr + symp->st_value)
FIXME("Changing address for %p/%s!%s from %08lx to %08lx\n",
sym, debugstr_w(module->module.ModuleName), sym->hash_elt.name,
((struct symt_function*)sym)->address, elf_info->elf_addr + symp->st_value);
if (((struct symt_data*)sym)->u.var.offset != elf_info->elf_addr &&
((struct symt_data*)sym)->u.var.offset != elf_info->elf_addr + symp->st_value)
FIXME("Changing address for %p/%s!%s from %08lx to %08lx\n",
sym, debugstr_w(module->module.ModuleName), sym->hash_elt.name,
((struct symt_function*)sym)->address, elf_info->elf_addr + symp->st_value);
((struct symt_data*)sym)->u.var.offset = elf_info->elf_addr + symp->st_value;
((struct symt_data*)sym)->kind = (ELF32_ST_BIND(symp->st_info) == STB_LOCAL) ?
DataIsFileStatic : DataIsGlobal;
@ -889,25 +890,140 @@ found:
}
/******************************************************************
* elf_debuglink_parse
* elf_locate_build_id_target
*
* Parses a .gnu_debuglink section and loads the debug info from
* the external file specified there.
* Try to find the .so file containing the debug info out of the build-id note information
*/
static BOOL elf_debuglink_parse(struct image_file_map* fmap, const struct module* module,
const BYTE* debuglink)
static BOOL elf_locate_build_id_target(struct image_file_map* fmap, const BYTE* id, unsigned idlen)
{
/* The content of a debug link section is:
* 1/ a NULL terminated string, containing the file name for the
* debug info
* 2/ padding on 4 byte boundary
* 3/ CRC of the linked ELF file
*/
const char* dbg_link = (const char*)debuglink;
DWORD crc;
static const WCHAR globalDebugDirW[] = {'/','u','s','r','/','l','i','b','/','d','e','b','u','g','/'};
static const WCHAR buildidW[] = {'.','b','u','i','l','d','-','i','d','/'};
static const WCHAR dotDebug0W[] = {'.','d','e','b','u','g',0};
struct image_file_map* fmap_link = NULL;
WCHAR* p;
WCHAR* z;
const BYTE* idend = id + idlen;
struct elf_map_file_data emfd;
crc = *(const DWORD*)(dbg_link + ((DWORD_PTR)(strlen(dbg_link) + 4) & ~3));
return elf_locate_debug_link(fmap, dbg_link, module->module.LoadedImageName, crc);
fmap_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*fmap_link));
if (!fmap_link) return FALSE;
p = HeapAlloc(GetProcessHeap(), 0,
sizeof(globalDebugDirW) + sizeof(buildidW) +
(idlen * 2 + 1) * sizeof(WCHAR) + sizeof(dotDebug0W));
z = p;
memcpy(z, globalDebugDirW, sizeof(globalDebugDirW));
z += sizeof(globalDebugDirW) / sizeof(WCHAR);
memcpy(z, buildidW, sizeof(buildidW));
z += sizeof(buildidW) / sizeof(WCHAR);
if (id < idend)
{
*z++ = "0123456789abcdef"[*id >> 4 ];
*z++ = "0123456789abcdef"[*id & 0x0F];
id++;
}
if (id < idend)
*z++ = '/';
while (id < idend)
{
*z++ = "0123456789abcdef"[*id >> 4 ];
*z++ = "0123456789abcdef"[*id & 0x0F];
id++;
}
memcpy(z, dotDebug0W, sizeof(dotDebug0W));
TRACE("checking %s\n", wine_dbgstr_w(p));
emfd.kind = from_file;
emfd.u.file.filename = p;
if (elf_map_file(&emfd, fmap_link))
{
struct image_section_map buildid_sect;
if (elf_find_section(fmap_link, ".note.gnu.build-id", SHT_NULL, &buildid_sect))
{
const uint32_t* note;
note = (const uint32_t*)image_map_section(&buildid_sect);
if (note != IMAGE_NO_MAP)
{
/* the usual ELF note structure: name-size desc-size type <name> <desc> */
if (note[2] == NT_GNU_BUILD_ID)
{
if (note[1] == idlen &&
!memcmp(note + 3 + ((note[0] + 3) >> 2), idend - idlen, idlen))
{
TRACE("Located debug information file at %s\n", debugstr_w(p));
HeapFree(GetProcessHeap(), 0, p);
fmap->u.elf.alternate = fmap_link;
return TRUE;
}
WARN("mismatch in buildid information for %s\n", wine_dbgstr_w(p));
}
}
image_unmap_section(&buildid_sect);
}
elf_unmap_file(fmap_link);
}
TRACE("not found\n");
HeapFree(GetProcessHeap(), 0, p);
HeapFree(GetProcessHeap(), 0, fmap_link);
return FALSE;
}
/******************************************************************
* elf_check_alternate
*
* Load alternate files for a given ELF file, looking at either .note.gnu_build-id
* or .gnu_debuglink sections.
*/
static BOOL elf_check_alternate(struct image_file_map* fmap, const struct module* module)
{
BOOL ret = FALSE;
BOOL found = FALSE;
struct image_section_map buildid_sect, debuglink_sect;
/* if present, add the .gnu_debuglink file as an alternate to current one */
if (elf_find_section(fmap, ".note.gnu.build-id", SHT_NULL, &buildid_sect))
{
const uint32_t* note;
found = TRUE;
note = (const uint32_t*)image_map_section(&buildid_sect);
if (note != IMAGE_NO_MAP)
{
/* the usual ELF note structure: name-size desc-size type <name> <desc> */
if (note[2] == NT_GNU_BUILD_ID)
{
ret = elf_locate_build_id_target(fmap, (const BYTE*)(note + 3 + ((note[0] + 3) >> 2)), note[1]);
}
}
image_unmap_section(&buildid_sect);
}
/* if present, add the .gnu_debuglink file as an alternate to current one */
if (!ret && elf_find_section(fmap, ".gnu_debuglink", SHT_NULL, &debuglink_sect))
{
const char* dbg_link;
found = TRUE;
dbg_link = (const char*)image_map_section(&debuglink_sect);
if (dbg_link != IMAGE_NO_MAP)
{
/* The content of a debug link section is:
* 1/ a NULL terminated string, containing the file name for the
* debug info
* 2/ padding on 4 byte boundary
* 3/ CRC of the linked ELF file
*/
DWORD crc = *(const DWORD*)(dbg_link + ((DWORD_PTR)(strlen(dbg_link) + 4) & ~3));
ret = elf_locate_debug_link(fmap, dbg_link, module->module.LoadedImageName, crc);
if (!ret)
WARN("Couldn't load linked debug file for %s\n",
debugstr_w(module->module.ModuleName));
}
image_unmap_section(&debuglink_sect);
}
return found ? ret : TRUE;
}
/******************************************************************
@ -948,24 +1064,10 @@ static BOOL elf_load_debug_info_from_map(struct module* module,
if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
{
struct image_section_map stab_sect, stabstr_sect;
struct image_section_map debuglink_sect;
/* if present, add the .gnu_debuglink file as an alternate to current one */
if (elf_find_section(fmap, ".gnu_debuglink", SHT_NULL, &debuglink_sect))
{
const BYTE* dbg_link;
/* check if we need an alternate file (from debuglink or build-id) */
ret = elf_check_alternate(fmap, module);
dbg_link = (const BYTE*)image_map_section(&debuglink_sect);
if (dbg_link != IMAGE_NO_MAP)
{
lret = elf_debuglink_parse(fmap, module, dbg_link);
if (!lret)
WARN("Couldn't load linked debug file for %s\n",
debugstr_w(module->module.ModuleName));
ret = ret || lret;
}
image_unmap_section(&debuglink_sect);
}
if (elf_find_section(fmap, ".stab", SHT_NULL, &stab_sect) &&
elf_find_section(fmap, ".stabstr", SHT_NULL, &stabstr_sect))
{

View file

@ -74,6 +74,7 @@
struct image_file_map
{
enum module_type modtype;
unsigned addr_size; /* either 16 (not used), 32 or 64 */
union
{
struct elf_file_map

View file

@ -135,7 +135,7 @@ static void macho_calc_range(const struct macho_file_map* fmap, unsigned offset,
unsigned* out_aligned_end, unsigned* out_aligned_len,
unsigned* out_misalign)
{
unsigned pagemask = getpagesize() - 1;
unsigned pagemask = sysconf( _SC_PAGESIZE ) - 1;
unsigned file_offset, misalign;
file_offset = fmap->arch_offset + offset;
@ -383,7 +383,7 @@ static int macho_accum_segs_range(struct macho_file_map* fmap,
const struct load_command* lc, void* user)
{
const struct segment_command* sc = (const struct segment_command*)lc;
unsigned tmp, page_mask = getpagesize() - 1;
unsigned tmp, page_mask = sysconf( _SC_PAGESIZE ) - 1;
TRACE("(%p/%d, %p, %p) before: 0x%08x - 0x%08x\n", fmap, fmap->fd, lc, user,
(unsigned)fmap->segs_start, (unsigned)fmap->segs_size);

View file

@ -32,82 +32,56 @@
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
struct dump_memory
{
ULONG64 base;
ULONG size;
ULONG rva;
};
struct dump_module
{
unsigned is_elf;
ULONG64 base;
ULONG size;
DWORD timestamp;
DWORD checksum;
WCHAR name[MAX_PATH];
};
struct dump_context
{
/* process & thread information */
HANDLE hProcess;
DWORD pid;
void* pcs_buffer;
SYSTEM_PROCESS_INFORMATION* spi;
/* module information */
struct dump_module* modules;
unsigned num_modules;
unsigned alloc_modules;
/* exception information */
/* output information */
MINIDUMP_TYPE type;
HANDLE hFile;
RVA rva;
struct dump_memory* mem;
unsigned num_mem;
unsigned alloc_mem;
/* callback information */
MINIDUMP_CALLBACK_INFORMATION* cb;
};
/******************************************************************
* fetch_processes_info
* fetch_process_info
*
* reads system wide process information, and make spi point to the record
* reads system wide process information, and gather from it the threads information
* for process of id 'pid'
*/
static BOOL fetch_processes_info(struct dump_context* dc)
static BOOL fetch_process_info(struct dump_context* dc)
{
ULONG buf_size = 0x1000;
NTSTATUS nts;
void* pcs_buffer = NULL;
dc->pcs_buffer = NULL;
if (!(dc->pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size))) return FALSE;
if (!(pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size))) return FALSE;
for (;;)
{
nts = NtQuerySystemInformation(SystemProcessInformation,
dc->pcs_buffer, buf_size, NULL);
nts = NtQuerySystemInformation(SystemProcessInformation,
pcs_buffer, buf_size, NULL);
if (nts != STATUS_INFO_LENGTH_MISMATCH) break;
dc->pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, dc->pcs_buffer,
buf_size *= 2);
if (!dc->pcs_buffer) return FALSE;
pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, pcs_buffer, buf_size *= 2);
if (!pcs_buffer) return FALSE;
}
if (nts == STATUS_SUCCESS)
{
dc->spi = dc->pcs_buffer;
SYSTEM_PROCESS_INFORMATION* spi = pcs_buffer;
unsigned i;
for (;;)
{
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);
if (HandleToUlong(spi->UniqueProcessId) == dc->pid)
{
dc->num_threads = spi->dwThreadCount;
dc->threads = HeapAlloc(GetProcessHeap(), 0,
dc->num_threads * sizeof(dc->threads[0]));
if (!dc->threads) goto failed;
for (i = 0; i < dc->num_threads; i++)
{
dc->threads[i].tid = HandleToULong(spi->ti[i].ClientId.UniqueThread);
dc->threads[i].prio_class = spi->ti[i].dwBasePriority; /* FIXME */
dc->threads[i].curr_prio = spi->ti[i].dwCurrentPriority;
}
HeapFree(GetProcessHeap(), 0, pcs_buffer);
return TRUE;
}
if (!spi->NextEntryOffset) break;
spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + spi->NextEntryOffset);
}
}
HeapFree(GetProcessHeap(), 0, dc->pcs_buffer);
dc->pcs_buffer = NULL;
dc->spi = NULL;
failed:
HeapFree(GetProcessHeap(), 0, pcs_buffer);
return FALSE;
}
@ -147,7 +121,7 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
const MINIDUMP_EXCEPTION_INFORMATION* except,
MINIDUMP_THREAD* mdThd, CONTEXT* ctx)
{
DWORD tid = HandleToUlong(dc->spi->ti[thd_idx].ClientId.UniqueThread);
DWORD tid = dc->threads[thd_idx].tid;
HANDLE hThread;
THREAD_BASIC_INFORMATION tbi;
@ -161,8 +135,8 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
mdThd->Stack.Memory.Rva = 0;
mdThd->ThreadContext.DataSize = 0;
mdThd->ThreadContext.Rva = 0;
mdThd->PriorityClass = dc->spi->ti[thd_idx].dwBasePriority; /* FIXME */
mdThd->Priority = dc->spi->ti[thd_idx].dwCurrentPriority;
mdThd->PriorityClass = dc->threads[thd_idx].prio_class;
mdThd->Priority = dc->threads[thd_idx].curr_prio;
if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL)
{
@ -354,14 +328,14 @@ static void fetch_module_versioninfo(LPCWSTR filename, VS_FIXEDFILEINFO* ffi)
}
/******************************************************************
* add_memory_block
* minidump_add_memory_block
*
* Add a memory block to be dumped in a minidump
* If rva is non 0, it's the rva in the minidump where has to be stored
* also the rva of the memory block when written (this allows to reference
* also the rva of the memory block when written (this allows us to reference
* a memory block from outside the list of memory blocks).
*/
static void add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva)
void minidump_add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva)
{
if (!dc->mem)
{
@ -539,6 +513,9 @@ static unsigned dump_modules(struct dump_context* dc, BOOL dump_elf)
}
if (flags_out & ModuleWriteModule)
{
/* fetch CPU dependent module info (like UNWIND_INFO) */
dbghelp_current_cpu->fetch_minidump_module(dc, i, flags_out);
mdModule.BaseOfImage = dc->modules[i].base;
mdModule.SizeOfImage = dc->modules[i].size;
mdModule.CheckSum = dc->modules[i].checksum;
@ -615,11 +592,29 @@ static unsigned dump_system_info(struct dump_context* dc)
OSVERSIONINFOW osInfo;
DWORD written;
ULONG slen;
DWORD wine_extra = 0;
const char *(CDECL *wine_get_build_id)(void);
void (CDECL *wine_get_host_version)(const char **sysname, const char **release);
const char* build_id = NULL;
const char* sys_name = NULL;
const char* release_name = NULL;
GetSystemInfo(&sysInfo);
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
GetVersionExW(&osInfo);
wine_get_build_id = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_build_id");
wine_get_host_version = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_host_version");
if (wine_get_build_id && wine_get_host_version)
{
/* cheat minidump system information by adding specific wine information */
wine_extra = 4 + 4 * sizeof(slen);
build_id = wine_get_build_id();
wine_get_host_version(&sys_name, &release_name);
wine_extra += strlen(build_id) + 1 + strlen(sys_name) + 1 + strlen(release_name) + 1;
}
mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
@ -630,7 +625,7 @@ static unsigned dump_system_info(struct dump_context* dc)
mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
mdSysInfo.PlatformId = osInfo.dwPlatformId;
mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo);
mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo) + wine_extra;
mdSysInfo.u1.Reserved1 = 0;
mdSysInfo.u1.s.SuiteMask = VER_SUITE_TERMINAL;
@ -640,8 +635,8 @@ static unsigned dump_system_info(struct dump_context* dc)
do_x86cpuid(0, regs0);
mdSysInfo.Cpu.X86CpuInfo.VendorId[0] = regs0[1];
mdSysInfo.Cpu.X86CpuInfo.VendorId[1] = regs0[2];
mdSysInfo.Cpu.X86CpuInfo.VendorId[2] = regs0[3];
mdSysInfo.Cpu.X86CpuInfo.VendorId[1] = regs0[3];
mdSysInfo.Cpu.X86CpuInfo.VendorId[2] = regs0[2];
do_x86cpuid(1, regs1);
mdSysInfo.Cpu.X86CpuInfo.VersionInformation = regs1[0];
mdSysInfo.Cpu.X86CpuInfo.FeatureInformation = regs1[3];
@ -672,6 +667,28 @@ static unsigned dump_system_info(struct dump_context* dc)
}
append(dc, &mdSysInfo, sizeof(mdSysInfo));
/* write Wine specific system information just behind the structure, and before any string */
if (wine_extra)
{
char code[] = {'W','I','N','E'};
WriteFile(dc->hFile, code, 4, &written, NULL);
/* number of sub-info, so that we can extend structure if needed */
slen = 3;
WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
/* we store offsets from just after the WINE marker */
slen = 4 * sizeof(DWORD);
WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
slen += strlen(build_id) + 1;
WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
slen += strlen(sys_name) + 1;
WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
WriteFile(dc->hFile, build_id, strlen(build_id) + 1, &written, NULL);
WriteFile(dc->hFile, sys_name, strlen(sys_name) + 1, &written, NULL);
WriteFile(dc->hFile, release_name, strlen(release_name) + 1, &written, NULL);
dc->rva += wine_extra;
}
/* write the service pack version string after this stream. It is referenced within the
stream by its RVA in the file. */
slen = lstrlenW(osInfo.szCSDVersion) * sizeof(WCHAR);
@ -700,9 +717,9 @@ static unsigned dump_threads(struct dump_context* dc,
mdThdList.NumberOfThreads = 0;
rva_base = dc->rva;
dc->rva += sz = sizeof(mdThdList.NumberOfThreads) + dc->spi->dwThreadCount * sizeof(mdThd);
dc->rva += sz = sizeof(mdThdList.NumberOfThreads) + dc->num_threads * sizeof(mdThd);
for (i = 0; i < dc->spi->dwThreadCount; i++)
for (i = 0; i < dc->num_threads; i++)
{
fetch_thread_info(dc, i, except, &mdThd, &ctx);
@ -721,7 +738,7 @@ static unsigned dump_threads(struct dump_context* dc,
cbin.ProcessId = dc->pid;
cbin.ProcessHandle = dc->hProcess;
cbin.CallbackType = ThreadCallback;
cbin.u.Thread.ThreadId = HandleToUlong(dc->spi->ti[i].ClientId.UniqueThread);
cbin.u.Thread.ThreadId = dc->threads[i].tid;
cbin.u.Thread.ThreadHandle = 0; /* FIXME */
cbin.u.Thread.Context = ctx;
cbin.u.Thread.SizeOfContext = sizeof(CONTEXT);
@ -744,11 +761,11 @@ static unsigned dump_threads(struct dump_context* dc,
}
if (mdThd.Stack.Memory.DataSize && (flags_out & ThreadWriteStack))
{
add_memory_block(dc, mdThd.Stack.StartOfMemoryRange,
mdThd.Stack.Memory.DataSize,
rva_base + sizeof(mdThdList.NumberOfThreads) +
mdThdList.NumberOfThreads * sizeof(mdThd) +
FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva));
minidump_add_memory_block(dc, mdThd.Stack.StartOfMemoryRange,
mdThd.Stack.Memory.DataSize,
rva_base + sizeof(mdThdList.NumberOfThreads) +
mdThdList.NumberOfThreads * sizeof(mdThd) +
FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva));
}
writeat(dc,
rva_base + sizeof(mdThdList.NumberOfThreads) +
@ -756,14 +773,8 @@ static unsigned dump_threads(struct dump_context* dc,
&mdThd, sizeof(mdThd));
mdThdList.NumberOfThreads++;
}
if (ctx.ContextFlags && (flags_out & ThreadWriteInstructionWindow))
{
/* FIXME: - Native dbghelp also dumps 0x80 bytes around EIP
* - also crop values across module boundaries,
* - and don't make it i386 dependent
*/
/* add_memory_block(dc, ctx.Eip - 0x80, ctx.Eip + 0x80, 0); */
}
/* fetch CPU dependent thread info (like 256 bytes around program counter */
dbghelp_current_cpu->fetch_minidump_thread(dc, i, flags_out, &ctx);
}
writeat(dc, rva_base,
&mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads));
@ -856,6 +867,8 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
dc.modules = NULL;
dc.num_modules = 0;
dc.alloc_modules = 0;
dc.threads = NULL;
dc.num_threads = 0;
dc.cb = CallbackParam;
dc.type = DumpType;
dc.mem = NULL;
@ -863,7 +876,7 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
dc.alloc_mem = 0;
dc.rva = 0;
if (!fetch_processes_info(&dc)) return FALSE;
if (!fetch_process_info(&dc)) return FALSE;
fetch_modules_info(&dc);
/* 1) init */
@ -967,9 +980,9 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
for (i = idx_stream; i < nStreams; i++)
writeat(&dc, mdHead.StreamDirectoryRva + i * sizeof(emptyDir), &emptyDir, sizeof(emptyDir));
HeapFree(GetProcessHeap(), 0, dc.pcs_buffer);
HeapFree(GetProcessHeap(), 0, dc.mem);
HeapFree(GetProcessHeap(), 0, dc.modules);
HeapFree(GetProcessHeap(), 0, dc.threads);
return TRUE;
}

View file

@ -101,9 +101,6 @@ static void module_fill_module(const WCHAR* in, WCHAR* out, size_t size)
void module_set_module(struct module* module, const WCHAR* name)
{
module_fill_module(name, module->module.ModuleName, sizeof(module->module.ModuleName));
WideCharToMultiByte(CP_ACP, 0, module->module.ModuleName, -1,
module->module_name, sizeof(module->module_name),
NULL, NULL);
}
const WCHAR *get_wine_loader_name(void)
@ -209,7 +206,7 @@ struct module* module_new(struct process* pcs, const WCHAR* name,
module->reloc_delta = 0;
module->type = type;
module->is_virtual = virtual ? TRUE : FALSE;
module->is_virtual = virtual;
for (i = 0; i < DFI_LAST; i++) module->format_info[i] = NULL;
module->sortlist_valid = FALSE;
module->sorttab_size = 0;
@ -388,7 +385,7 @@ BOOL module_get_debug(struct module_pair* pair)
* either the addr where module is loaded, or any address inside the
* module
*/
struct module* module_find_by_addr(const struct process* pcs, unsigned long addr,
struct module* module_find_by_addr(const struct process* pcs, DWORD64 addr,
enum module_type type)
{
struct module* module;
@ -659,8 +656,8 @@ DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageNam
DWORD64 WINAPI SymLoadModule64(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll)
{
if (!validate_addr64(BaseOfDll)) return FALSE;
return SymLoadModule(hProcess, hFile, ImageName, ModuleName, (DWORD)BaseOfDll, SizeOfDll);
return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll, SizeOfDll,
NULL, 0);
}
/******************************************************************
@ -730,7 +727,7 @@ BOOL WINAPI SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll)
pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
if (!validate_addr64(BaseOfDll)) return FALSE;
module = module_find_by_addr(pcs, (DWORD)BaseOfDll, DMT_UNKNOWN);
module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
if (!module) return FALSE;
return module_remove(pcs, module);
}

View file

@ -935,6 +935,18 @@ static int codeview_add_type_struct_field_list(struct codeview_type_parse* ctp,
}
break;
case LF_INDEX_V1:
if (!codeview_add_type_struct_field_list(ctp, symt, type->index_v1.ref))
return FALSE;
ptr += 2 + 2;
break;
case LF_INDEX_V2:
if (!codeview_add_type_struct_field_list(ctp, symt, type->index_v2.ref))
return FALSE;
ptr += 2 + 2 + 4;
break;
default:
FIXME("Unsupported type %04x in STRUCT field list\n", type->generic.id);
return FALSE;
@ -1358,7 +1370,8 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B
{
const BYTE* ptr = linetab;
int nfile, nseg;
int i, j, k;
int i, j;
unsigned int k;
const unsigned int* filetab;
const unsigned int* lt_ptr;
const unsigned short* linenos;
@ -1551,7 +1564,6 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root
int i, length;
struct symt_block* block = NULL;
struct symt* symt;
const char* name;
struct symt_compiland* compiland = NULL;
struct location loc;
@ -1947,9 +1959,13 @@ static int codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root
case S_PROCREF_V1:
case S_DATAREF_V1:
case S_LPROCREF_V1:
name = (const char*)sym + length;
length += (*name + 1 + 3) & ~3;
break;
{
const char* name;
name = (const char*)sym + length;
length += (*name + 1 + 3) & ~3;
break;
}
case S_MSTOOL_V3: /* just to silence a few warnings */
case S_MSTOOLINFO_V3:

View file

@ -78,8 +78,8 @@ HANDLE WINAPI FindDebugInfoFileEx(PCSTR FileName, PCSTR SymbolPath,
PFIND_DEBUG_FILE_CALLBACK Callback,
PVOID CallerData)
{
FIXME("(%s %s %p %p %p): stub\n",
debugstr_a(FileName), debugstr_a(SymbolPath), debugstr_a(DebugFilePath), Callback, CallerData);
FIXME("(%s %s %s %p %p): stub\n", debugstr_a(FileName), debugstr_a(SymbolPath),
debugstr_a(DebugFilePath), Callback, CallerData);
return NULL;
}
@ -479,7 +479,6 @@ static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user)
{
HANDLE hFile, hMap;
void* mapping;
DWORD timestamp;
timestamp = ~mf->dw1;
size = ~mf->dw2;

View file

@ -224,6 +224,12 @@ static BOOL pe_map_file(HANDLE file, struct image_file_map* fmap, enum module_ty
if (!(nthdr = RtlImageNtHeader(mapping))) goto error;
memcpy(&fmap->u.pe.ntheader, nthdr, sizeof(fmap->u.pe.ntheader));
switch (nthdr->OptionalHeader.Magic)
{
case 0x10b: fmap->addr_size = 32; break;
case 0x20b: fmap->addr_size = 64; break;
default: return FALSE;
}
section = (IMAGE_SECTION_HEADER*)
((char*)&nthdr->OptionalHeader + nthdr->FileHeader.SizeOfOptionalHeader);
fmap->u.pe.sect = HeapAlloc(GetProcessHeap(), 0,

File diff suppressed because it is too large Load diff

View file

@ -606,7 +606,6 @@ static inline int stabs_pts_read_method_info(struct ParseTypedefData* ptd)
if (mthd == '*')
{
long int ofs;
struct symt* dt;
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &ofs) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';');
@ -631,7 +630,7 @@ static inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd,
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &sz) == -1);
doadd = symt_set_udt_size(ptd->module, sdt, sz);
if (*ptd->ptr == '!') /* C++ inheritence */
if (*ptd->ptr == '!') /* C++ inheritance */
{
long num_classes;
@ -640,7 +639,7 @@ static inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd,
PTS_ABORTIF(ptd, *ptd->ptr++ != ',');
while (--num_classes >= 0)
{
ptd->ptr += 2; /* skip visibility and inheritence */
ptd->ptr += 2; /* skip visibility and inheritance */
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &ofs) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ',');

View file

@ -30,9 +30,6 @@
#include <limits.h>
#include <sys/types.h>
#include <assert.h>
#ifdef HAVE_REGEX_H
# include <regex.h>
#endif
#include "wine/debug.h"
#include "dbghelp_private.h"
@ -41,6 +38,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symt);
static WCHAR starW[] = {'*','\0'};
static inline int cmp_addr(ULONG64 a1, ULONG64 a2)
{
if (a1 > a2) return 1;
@ -136,155 +135,54 @@ static void symt_add_module_ht(struct module* module, struct symt_ht* ht)
}
}
#ifdef HAVE_REGEX_H
/* transforms a dbghelp's regular expression into a POSIX one
* Here are the valid dbghelp reg ex characters:
* * 0 or more characters
* ? a single character
* [] list
* # 0 or more of preceding char
* + 1 or more of preceding char
* escapes \ on #, ?, [, ], *, +. don't work on -
*/
static void compile_regex(const char* str, int numchar, regex_t* re, BOOL _case)
static WCHAR* file_regex(const char* srcfile)
{
char *mask, *p;
BOOL in_escape = FALSE;
unsigned flags = REG_NOSUB;
WCHAR* mask;
WCHAR* p;
if (numchar == -1) numchar = strlen( str );
p = mask = HeapAlloc( GetProcessHeap(), 0, 2 * numchar + 3 );
*p++ = '^';
while (*str && numchar--)
if (!srcfile || !*srcfile)
{
/* FIXME: this shouldn't be valid on '-' */
if (in_escape)
{
*p++ = '\\';
*p++ = *str;
in_escape = FALSE;
}
else switch (*str)
{
case '\\': in_escape = TRUE; break;
case '*': *p++ = '.'; *p++ = '*'; break;
case '?': *p++ = '.'; break;
case '#': *p++ = '*'; break;
/* escape some valid characters in dbghelp reg exp:s */
case '$': *p++ = '\\'; *p++ = '$'; break;
/* +, [, ], - are the same in dbghelp & POSIX, use them as any other char */
default: *p++ = *str; break;
}
str++;
if (!(p = mask = HeapAlloc(GetProcessHeap(), 0, 3 * sizeof(WCHAR)))) return NULL;
*p++ = '?';
*p++ = '#';
}
if (in_escape)
else
{
*p++ = '\\';
*p++ = '\\';
DWORD sz = MultiByteToWideChar(CP_ACP, 0, srcfile, -1, NULL, 0);
WCHAR* srcfileW;
/* FIXME: we use here the largest conversion for every char... could be optimized */
p = mask = HeapAlloc(GetProcessHeap(), 0, (5 * strlen(srcfile) + 1 + sz) * sizeof(WCHAR));
if (!mask) return NULL;
srcfileW = mask + 5 * strlen(srcfile) + 1;
MultiByteToWideChar(CP_ACP, 0, srcfile, -1, srcfileW, sz);
while (*srcfileW)
{
switch (*srcfileW)
{
case '\\':
case '/':
*p++ = '[';
*p++ = '\\';
*p++ = '\\';
*p++ = '/';
*p++ = ']';
break;
case '.':
*p++ = '?';
break;
default:
*p++ = *srcfileW;
break;
}
srcfileW++;
}
}
*p++ = '$';
*p = 0;
if (_case) flags |= REG_ICASE;
if (regcomp(re, mask, flags)) FIXME("Couldn't compile %s\n", mask);
HeapFree(GetProcessHeap(), 0, mask);
return mask;
}
static BOOL compile_file_regex(regex_t* re, const char* srcfile)
{
char *mask, *p;
BOOL ret;
if (!srcfile || !*srcfile) return regcomp(re, ".*", REG_NOSUB);
p = mask = HeapAlloc(GetProcessHeap(), 0, 5 * strlen(srcfile) + 4);
*p++ = '^';
while (*srcfile)
{
switch (*srcfile)
{
case '\\':
case '/':
*p++ = '[';
*p++ = '\\';
*p++ = '\\';
*p++ = '/';
*p++ = ']';
break;
case '.':
*p++ = '\\';
*p++ = '.';
break;
case '*':
*p++ = '.';
*p++ = '*';
break;
default:
*p++ = *srcfile;
break;
}
srcfile++;
}
*p++ = '$';
*p = 0;
ret = !regcomp(re, mask, REG_NOSUB);
HeapFree(GetProcessHeap(), 0, mask);
if (!ret)
{
FIXME("Couldn't compile %s\n", mask);
SetLastError(ERROR_INVALID_PARAMETER);
}
return ret;
}
static int match_regexp( const regex_t *re, const char *str )
{
return !regexec( re, str, 0, NULL, 0 );
}
#else /* HAVE_REGEX_H */
/* if we don't have regexp support, fall back to a simple string comparison */
typedef struct
{
char *str;
BOOL icase;
} regex_t;
static void compile_regex(const char* str, int numchar, regex_t* re, BOOL _case)
{
if (numchar == -1) numchar = strlen( str );
re->str = HeapAlloc( GetProcessHeap(), 0, numchar + 1 );
memcpy( re->str, str, numchar );
re->str[numchar] = 0;
re->icase = _case;
}
static BOOL compile_file_regex(regex_t* re, const char* srcfile)
{
if (!srcfile || !*srcfile) re->str = NULL;
else compile_regex( srcfile, -1, re, FALSE );
return TRUE;
}
static int match_regexp( const regex_t *re, const char *str )
{
if (!re->str) return 1;
if (re->icase) return !lstrcmpiA( re->str, str );
return !strcmp( re->str, str );
}
static void regfree( regex_t *re )
{
HeapFree( GetProcessHeap(), 0, re->str );
}
#endif /* HAVE_REGEX_H */
struct symt_compiland* symt_new_compiland(struct module* module,
unsigned long address, unsigned src_idx)
{
@ -832,24 +730,29 @@ static BOOL send_symbol(const struct sym_enum* se, struct module_pair* pair,
return !se->cb(se->sym_info, se->sym_info->Size, se->user);
}
static BOOL symt_enum_module(struct module_pair* pair, const regex_t* regex,
static BOOL symt_enum_module(struct module_pair* pair, const WCHAR* match,
const struct sym_enum* se)
{
void* ptr;
struct symt_ht* sym = NULL;
struct hash_table_iter hti;
WCHAR* nameW;
BOOL ret;
hash_table_iter_init(&pair->effective->ht_symbols, &hti, NULL);
while ((ptr = hash_table_iter_up(&hti)))
{
sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
if (sym->hash_elt.name && match_regexp(regex, sym->hash_elt.name))
nameW = symt_get_nameW(&sym->symt);
ret = SymMatchStringW(nameW, match, FALSE);
HeapFree(GetProcessHeap(), 0, nameW);
if (ret)
{
se->sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO);
if (send_symbol(se, pair, NULL, &sym->symt)) return TRUE;
}
}
}
return FALSE;
}
@ -1004,12 +907,14 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr)
}
static BOOL symt_enum_locals_helper(struct module_pair* pair,
regex_t* preg, const struct sym_enum* se,
const WCHAR* match, const struct sym_enum* se,
struct symt_function* func, const struct vector* v)
{
struct symt* lsym = NULL;
DWORD pc = pair->pcs->ctx_frame.InstructionOffset;
unsigned int i;
WCHAR* nameW;
BOOL ret;
for (i=0; i<vector_length(v); i++)
{
@ -1021,12 +926,16 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair,
struct symt_block* block = (struct symt_block*)lsym;
if (pc < block->address || block->address + block->size <= pc)
continue;
if (!symt_enum_locals_helper(pair, preg, se, func, &block->vchildren))
if (!symt_enum_locals_helper(pair, match, se, func, &block->vchildren))
return FALSE;
}
break;
case SymTagData:
if (match_regexp(preg, symt_get_name(lsym)))
nameW = symt_get_nameW(lsym);
ret = SymMatchStringW(nameW, match,
!(dbghelp_options & SYMOPT_CASE_INSENSITIVE));
HeapFree(GetProcessHeap(), 0, nameW);
if (ret)
{
if (send_symbol(se, pair, func, lsym)) return FALSE;
}
@ -1044,7 +953,7 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair,
return TRUE;
}
static BOOL symt_enum_locals(struct process* pcs, const char* mask,
static BOOL symt_enum_locals(struct process* pcs, const WCHAR* mask,
const struct sym_enum* se)
{
struct module_pair pair;
@ -1061,15 +970,8 @@ static BOOL symt_enum_locals(struct process* pcs, const char* mask,
if (sym->symt.tag == SymTagFunction)
{
BOOL ret;
regex_t preg;
compile_regex(mask ? mask : "*", -1, &preg,
dbghelp_options & SYMOPT_CASE_INSENSITIVE);
ret = symt_enum_locals_helper(&pair, &preg, se, (struct symt_function*)sym,
&((struct symt_function*)sym)->vchildren);
regfree(&preg);
return ret;
return symt_enum_locals_helper(&pair, mask ? mask : starW, se, (struct symt_function*)sym,
&((struct symt_function*)sym)->vchildren);
}
return FALSE;
}
@ -1105,33 +1007,34 @@ void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si)
*
* Core routine for most of the enumeration of symbols
*/
static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
const struct sym_enum* se)
{
struct module_pair pair;
const char* bang;
regex_t mod_regex, sym_regex;
const WCHAR* bang;
WCHAR* mod;
pair.pcs = process_find_by_handle(hProcess);
if (!pair.pcs) return FALSE;
if (BaseOfDll == 0)
{
/* do local variables ? */
if (!Mask || !(bang = strchr(Mask, '!')))
if (!Mask || !(bang = strchrW(Mask, '!')))
return symt_enum_locals(pair.pcs, Mask, se);
if (bang == Mask) return FALSE;
compile_regex(Mask, bang - Mask, &mod_regex, TRUE);
compile_regex(bang + 1, -1, &sym_regex,
dbghelp_options & SYMOPT_CASE_INSENSITIVE);
mod = HeapAlloc(GetProcessHeap(), 0, (bang - Mask + 1) * sizeof(WCHAR));
if (!mod) return FALSE;
memcpy(mod, Mask, (bang - Mask) * sizeof(WCHAR));
mod[bang - Mask] = 0;
for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next)
{
if (pair.requested->type == DMT_PE && module_get_debug(&pair))
{
if (match_regexp(&mod_regex, pair.requested->module_name) &&
symt_enum_module(&pair, &sym_regex, se))
if (SymMatchStringW(pair.requested->module.ModuleName, mod, FALSE) &&
symt_enum_module(&pair, bang + 1, se))
break;
}
}
@ -1145,14 +1048,13 @@ static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
!module_get_containee(pair.pcs, pair.requested) &&
module_get_debug(&pair))
{
if (match_regexp(&mod_regex, pair.requested->module_name) &&
symt_enum_module(&pair, &sym_regex, se))
if (SymMatchStringW(pair.requested->module.ModuleName, mod, FALSE) &&
symt_enum_module(&pair, bang + 1, se))
break;
}
}
}
regfree(&mod_regex);
regfree(&sym_regex);
HeapFree(GetProcessHeap(), 0, mod);
return TRUE;
}
pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN);
@ -1160,20 +1062,33 @@ static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
return FALSE;
/* we always ignore module name from Mask when BaseOfDll is defined */
if (Mask && (bang = strchr(Mask, '!')))
if (Mask && (bang = strchrW(Mask, '!')))
{
if (bang == Mask) return FALSE;
Mask = bang + 1;
}
compile_regex(Mask ? Mask : "*", -1, &sym_regex,
dbghelp_options & SYMOPT_CASE_INSENSITIVE);
symt_enum_module(&pair, &sym_regex, se);
regfree(&sym_regex);
symt_enum_module(&pair, Mask ? Mask : starW, se);
return TRUE;
}
static inline BOOL doSymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
PVOID UserContext)
{
struct sym_enum se;
se.cb = EnumSymbolsCallback;
se.user = UserContext;
se.index = 0;
se.tag = 0;
se.addr = 0;
se.sym_info = (PSYMBOL_INFO)se.buffer;
return sym_enum(hProcess, BaseOfDll, Mask, &se);
}
/******************************************************************
* SymEnumSymbols (DBGHELP.@)
*
@ -1189,20 +1104,23 @@ BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask,
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
PVOID UserContext)
{
struct sym_enum se;
BOOL ret;
PWSTR maskW = NULL;
TRACE("(%p %s %s %p %p)\n",
TRACE("(%p %s %s %p %p)\n",
hProcess, wine_dbgstr_longlong(BaseOfDll), debugstr_a(Mask),
EnumSymbolsCallback, UserContext);
se.cb = EnumSymbolsCallback;
se.user = UserContext;
se.index = 0;
se.tag = 0;
se.addr = 0;
se.sym_info = (PSYMBOL_INFO)se.buffer;
return sym_enum(hProcess, BaseOfDll, Mask, &se);
if (Mask)
{
DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
return FALSE;
MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
}
ret = doSymEnumSymbols(hProcess, BaseOfDll, maskW, EnumSymbolsCallback, UserContext);
HeapFree(GetProcessHeap(), 0, maskW);
return ret;
}
struct sym_enumW
@ -1232,24 +1150,12 @@ BOOL WINAPI SymEnumSymbolsW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask,
PVOID UserContext)
{
struct sym_enumW sew;
BOOL ret = FALSE;
char* maskA = NULL;
sew.ctx = UserContext;
sew.cb = EnumSymbolsCallback;
sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
if (Mask)
{
unsigned len = WideCharToMultiByte(CP_ACP, 0, Mask, -1, NULL, 0, NULL, NULL);
maskA = HeapAlloc(GetProcessHeap(), 0, len);
if (!maskA) return FALSE;
WideCharToMultiByte(CP_ACP, 0, Mask, -1, maskA, len, NULL, NULL);
}
ret = SymEnumSymbols(hProcess, BaseOfDll, maskA, sym_enumW, &sew);
HeapFree(GetProcessHeap(), 0, maskA);
return ret;
return doSymEnumSymbols(hProcess, BaseOfDll, Mask, sym_enumW, &sew);
}
struct sym_enumerate
@ -1853,7 +1759,7 @@ DWORD WINAPI UnDecorateSymbolName(PCSTR DecoratedName, PSTR UnDecoratedName,
DWORD UndecoratedLength, DWORD Flags)
{
/* undocumented from msvcrt */
static char* (* CDECL p_undname)(char*, const char*, int, void* (* CDECL)(size_t), void (* CDECL)(void*), unsigned short);
static char* (CDECL *p_undname)(char*, const char*, int, void* (CDECL*)(size_t), void (CDECL*)(void*), unsigned short);
static const WCHAR szMsvcrt[] = {'m','s','v','c','r','t','.','d','l','l',0};
TRACE("(%s, %p, %d, 0x%08x)\n",
@ -1873,67 +1779,187 @@ DWORD WINAPI UnDecorateSymbolName(PCSTR DecoratedName, PSTR UnDecoratedName,
return strlen(UnDecoratedName);
}
#define WILDCHAR(x) (-(x))
static int re_fetch_char(const WCHAR** re)
{
switch (**re)
{
case '\\': (*re)++; return *(*re)++;
case '*': case '[': case '?': case '+': case '#': case ']': return WILDCHAR(*(*re)++);
default: return *(*re)++;
}
}
static inline int re_match_char(WCHAR ch1, WCHAR ch2, BOOL _case)
{
return _case ? ch1 - ch2 : toupperW(ch1) - toupperW(ch2);
}
static const WCHAR* re_match_one(const WCHAR* string, const WCHAR* elt, BOOL _case)
{
int ch1, prev = 0;
unsigned state = 0;
switch (ch1 = re_fetch_char(&elt))
{
default:
return (ch1 >= 0 && re_match_char(*string, ch1, _case) == 0) ? ++string : NULL;
case WILDCHAR('?'): return *string ? ++string : NULL;
case WILDCHAR('*'): assert(0);
case WILDCHAR('['): break;
}
for (;;)
{
ch1 = re_fetch_char(&elt);
if (ch1 == WILDCHAR(']')) return NULL;
if (state == 1 && ch1 == '-') state = 2;
else
{
if (re_match_char(*string, ch1, _case) == 0) return ++string;
switch (state)
{
case 0:
state = 1;
prev = ch1;
break;
case 1:
state = 0;
break;
case 2:
if (prev >= 0 && ch1 >= 0 && re_match_char(prev, *string, _case) <= 0 &&
re_match_char(*string, ch1, _case) <= 0)
return ++string;
state = 0;
break;
}
}
}
}
/******************************************************************
* re_match_multi
*
* match a substring of *pstring according to *pre regular expression
* pstring and pre are only updated in case of successful match
*/
static BOOL re_match_multi(const WCHAR** pstring, const WCHAR** pre, BOOL _case)
{
const WCHAR* re_end = *pre;
const WCHAR* string_end = *pstring;
const WCHAR* re_beg;
const WCHAR* string_beg;
const WCHAR* next;
int ch;
while (*re_end && *string_end)
{
string_beg = string_end;
re_beg = re_end;
switch (ch = re_fetch_char(&re_end))
{
case WILDCHAR(']'): case WILDCHAR('+'): case WILDCHAR('#'): return FALSE;
case WILDCHAR('*'):
/* transform '*' into '?#' */
{static const WCHAR qmW[] = {'?',0}; re_beg = qmW;}
goto closure;
case WILDCHAR('['):
do
{
if (!(ch = re_fetch_char(&re_end))) return FALSE;
} while (ch != WILDCHAR(']'));
/* fall through */
case WILDCHAR('?'):
default:
break;
}
switch (*re_end)
{
case '+':
if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
string_beg++;
/* fall through */
case '#':
re_end++;
closure:
while ((next = re_match_one(string_end, re_beg, _case))) string_end = next;
for ( ; string_end >= string_beg; string_end--)
{
if (re_match_multi(&string_end, &re_end, _case)) goto found;
}
return FALSE;
default:
if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE;
string_end = next;
}
re_beg = re_end;
}
if (*re_end || *string_end) return FALSE;
found:
*pre = re_end;
*pstring = string_end;
return TRUE;
}
/******************************************************************
* SymMatchStringA (DBGHELP.@)
*
*/
BOOL WINAPI SymMatchStringA(PCSTR string, PCSTR re, BOOL _case)
{
regex_t preg;
BOOL ret;
WCHAR* strW;
WCHAR* reW;
BOOL ret = FALSE;
DWORD sz;
if (!string || !re)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N');
compile_regex(re, -1, &preg, _case);
ret = match_regexp(&preg, string);
regfree(&preg);
sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0);
if ((strW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
MultiByteToWideChar(CP_ACP, 0, string, -1, strW, sz);
sz = MultiByteToWideChar(CP_ACP, 0, re, -1, NULL, 0);
if ((reW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
MultiByteToWideChar(CP_ACP, 0, re, -1, reW, sz);
if (strW && reW)
ret = SymMatchStringW(strW, reW, _case);
HeapFree(GetProcessHeap(), 0, strW);
HeapFree(GetProcessHeap(), 0, reW);
return ret;
}
/******************************************************************
* SymMatchStringW (DBGHELP.@)
*
* FIXME: SymMatchStringA should convert and pass the strings to SymMatchStringW,
* but that needs a unicode RE library.
*/
BOOL WINAPI SymMatchStringW(PCWSTR string, PCWSTR re, BOOL _case)
{
BOOL ret;
LPSTR s, r;
DWORD len;
TRACE("%s %s %c\n", debugstr_w(string), debugstr_w(re), _case ? 'Y' : 'N');
len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL );
s = HeapAlloc( GetProcessHeap(), 0, len );
WideCharToMultiByte( CP_ACP, 0, string, -1, s, len, NULL, NULL );
len = WideCharToMultiByte( CP_ACP, 0, re, -1, NULL, 0, NULL, NULL );
r = HeapAlloc( GetProcessHeap(), 0, len );
WideCharToMultiByte( CP_ACP, 0, re, -1, r, len, NULL, NULL );
ret = SymMatchStringA(s, r, _case);
HeapFree( GetProcessHeap(), 0, r );
HeapFree( GetProcessHeap(), 0, s );
return ret;
if (!string || !re)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
return re_match_multi(&string, &re, _case);
}
/******************************************************************
* SymSearch (DBGHELP.@)
*/
BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
DWORD SymTag, PCSTR Mask, DWORD64 Address,
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
PVOID UserContext, DWORD Options)
static inline BOOL doSymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
DWORD SymTag, PCWSTR Mask, DWORD64 Address,
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
PVOID UserContext, DWORD Options)
{
struct sym_enum se;
TRACE("(%p %s %u %u %s %s %p %p %x)\n",
hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, Mask,
wine_dbgstr_longlong(Address), EnumSymbolsCallback,
UserContext, Options);
if (Options != SYMSEARCH_GLOBALSONLY)
{
FIXME("Unsupported searching with options (%x)\n", Options);
@ -1951,6 +1977,36 @@ BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
return sym_enum(hProcess, BaseOfDll, Mask, &se);
}
/******************************************************************
* SymSearch (DBGHELP.@)
*/
BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
DWORD SymTag, PCSTR Mask, DWORD64 Address,
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
PVOID UserContext, DWORD Options)
{
LPWSTR maskW = NULL;
BOOLEAN ret;
TRACE("(%p %s %u %u %s %s %p %p %x)\n",
hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, Mask,
wine_dbgstr_longlong(Address), EnumSymbolsCallback,
UserContext, Options);
if (Mask)
{
DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0);
if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
return FALSE;
MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz);
}
ret = doSymSearch(hProcess, BaseOfDll, Index, SymTag, maskW, Address,
EnumSymbolsCallback, UserContext, Options);
HeapFree(GetProcessHeap(), 0, maskW);
return ret;
}
/******************************************************************
* SymSearchW (DBGHELP.@)
*/
@ -1960,8 +2016,6 @@ BOOL WINAPI SymSearchW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
PVOID UserContext, DWORD Options)
{
struct sym_enumW sew;
BOOL ret = FALSE;
char* maskA = NULL;
TRACE("(%p %s %u %u %s %s %p %p %x)\n",
hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, debugstr_w(Mask),
@ -1972,18 +2026,8 @@ BOOL WINAPI SymSearchW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index,
sew.cb = EnumSymbolsCallback;
sew.sym_info = (PSYMBOL_INFOW)sew.buffer;
if (Mask)
{
unsigned len = WideCharToMultiByte(CP_ACP, 0, Mask, -1, NULL, 0, NULL, NULL);
maskA = HeapAlloc(GetProcessHeap(), 0, len);
if (!maskA) return FALSE;
WideCharToMultiByte(CP_ACP, 0, Mask, -1, maskA, len, NULL, NULL);
}
ret = SymSearch(hProcess, BaseOfDll, Index, SymTag, maskA, Address,
sym_enumW, &sew, Options);
HeapFree(GetProcessHeap(), 0, maskA);
return ret;
return doSymSearch(hProcess, BaseOfDll, Index, SymTag, Mask, Address,
sym_enumW, &sew, Options);
}
/******************************************************************
@ -2042,7 +2086,7 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
struct module_pair pair;
struct hash_table_iter hti;
struct symt_ht* sym;
regex_t re;
WCHAR* srcmask;
struct line_info* dli;
void* ptr;
SRCCODEINFO sci;
@ -2056,7 +2100,7 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
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_file_regex(&re, srcfile)) return FALSE;
if (!(srcmask = file_regex(srcfile))) return FALSE;
sci.SizeOfStruct = sizeof(sci);
sci.ModBase = base;
@ -2076,8 +2120,20 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
if (dli->is_source_file)
{
file = source_get(pair.effective, dli->u.source_file);
if (!match_regexp(&re, file)) sci.FileName[0] = '\0';
else strcpy(sci.FileName, file);
if (!file) sci.FileName[0] = '\0';
else
{
DWORD sz = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0);
WCHAR* fileW;
if ((fileW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, sz);
if (SymMatchStringW(fileW, srcmask, FALSE))
strcpy(sci.FileName, file);
else
sci.FileName[0] = '\0';
HeapFree(GetProcessHeap(), 0, fileW);
}
}
else if (sci.FileName[0])
{
@ -2089,7 +2145,7 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
}
}
}
regfree(&re);
HeapFree(GetProcessHeap(), 0, srcmask);
return TRUE;
}

View file

@ -102,6 +102,19 @@ const char* symt_get_name(const struct symt* sym)
}
}
WCHAR* symt_get_nameW(const struct symt* sym)
{
const char* name = symt_get_name(sym);
WCHAR* nameW;
DWORD sz;
if (!name) return NULL;
sz = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
if ((nameW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR))))
MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, sz);
return nameW;
}
BOOL symt_get_address(const struct symt* type, ULONG64* addr)
{
switch (type->tag)

View file

@ -2,6 +2,7 @@
* File cvconst.h - MS debug information
*
* Copyright (C) 2004, Eric Pouech
* Copyright (C) 2012, André Hentschel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -132,6 +133,9 @@ enum CV_HREG_e
CV_ALLREG_HANDLE = 30007,
CV_ALLREG_PARAMS = 30008,
CV_ALLREG_LOCALS = 30009,
CV_ALLREG_TID = 30010,
CV_ALLREG_ENV = 30011,
CV_ALLREG_CMDLN = 30012,
/* Intel x86 CPU */
CV_REG_NONE = 0,
@ -224,6 +228,33 @@ enum CV_HREG_e
CV_REG_MM70 = 250,
CV_REG_MM71 = 251,
CV_REG_YMM0 = 252, /* this includes YMM1 to YMM7 */
CV_REG_YMM0H = 260, /* this includes YMM1H to YMM7H */
CV_REG_YMM0I0 = 268, /* this includes YMM0I1 to YMM0I3 */
CV_REG_YMM1I0 = 272, /* this includes YMM1I1 to YMM1I3 */
CV_REG_YMM2I0 = 276, /* this includes YMM2I1 to YMM2I3 */
CV_REG_YMM3I0 = 280, /* this includes YMM3I1 to YMM3I3 */
CV_REG_YMM4I0 = 284, /* this includes YMM4I1 to YMM4I3 */
CV_REG_YMM5I0 = 288, /* this includes YMM5I1 to YMM5I3 */
CV_REG_YMM6I0 = 292, /* this includes YMM6I1 to YMM6I3 */
CV_REG_YMM7I0 = 296, /* this includes YMM7I1 to YMM7I3 */
CV_REG_YMM0F0 = 300, /* this includes YMM0F1 to YMM0F7 */
CV_REG_YMM1F0 = 308, /* this includes YMM1F1 to YMM1F7 */
CV_REG_YMM2F0 = 316, /* this includes YMM2F1 to YMM2F7 */
CV_REG_YMM3F0 = 324, /* this includes YMM3F1 to YMM3F7 */
CV_REG_YMM4F0 = 332, /* this includes YMM4F1 to YMM4F7 */
CV_REG_YMM5F0 = 340, /* this includes YMM5F1 to YMM5F7 */
CV_REG_YMM6F0 = 348, /* this includes YMM6F1 to YMM6F7 */
CV_REG_YMM7F0 = 356, /* this includes YMM7F1 to YMM7F7 */
CV_REG_YMM0D0 = 364, /* this includes YMM0D1 to YMM0D3 */
CV_REG_YMM1D0 = 368, /* this includes YMM1D1 to YMM1D3 */
CV_REG_YMM2D0 = 372, /* this includes YMM2D1 to YMM2D3 */
CV_REG_YMM3D0 = 376, /* this includes YMM3D1 to YMM3D3 */
CV_REG_YMM4D0 = 380, /* this includes YMM4D1 to YMM4D3 */
CV_REG_YMM5D0 = 384, /* this includes YMM5D1 to YMM5D3 */
CV_REG_YMM6D0 = 388, /* this includes YMM6D1 to YMM6D3 */
CV_REG_YMM7D0 = 392, /* this includes YMM7D1 to YMM7D3 */
/* Motorola 68K CPU */
CV_R68_D0 = 0, /* this includes D1 to D7 too */
CV_R68_A0 = 8, /* this includes A1 to A7 too */
@ -287,7 +318,7 @@ enum CV_HREG_e
CV_M4_Psr = 51,
CV_M4_FltF0 = 60, /* this includes FltF1 to Flt31 */
CV_M4_FltFsr = 92,
/* Alpha AXP CPU */
CV_ALPHA_NOREG = CV_REG_NONE,
CV_ALPHA_FltF0 = 10, /* this includes FltF1 to FltF31 */
@ -311,7 +342,7 @@ enum CV_HREG_e
CV_ALPHA_Psr = 76,
CV_ALPHA_FltFsr = 77,
CV_ALPHA_SoftFpcr = 78,
/* Motorola & IBM PowerPC CPU */
CV_PPC_GPR0 = 1, /* this includes GPR1 to GPR31 */
CV_PPC_CR = 33,
@ -321,7 +352,53 @@ enum CV_HREG_e
CV_PPC_FPSCR = 74,
CV_PPC_MSR = 75,
CV_PPC_SR0 = 76, /* this includes SR1 to SR15 */
/* some PPC registers missing */
CV_PPC_PC = 99,
CV_PPC_MQ = 100,
CV_PPC_XER = 101,
CV_PPC_RTCU = 104,
CV_PPC_RTCL = 105,
CV_PPC_LR = 108,
CV_PPC_CTR = 109,
CV_PPC_COMPARE = 110,
CV_PPC_COUNT = 111,
CV_PPC_DSISR = 118,
CV_PPC_DAR = 119,
CV_PPC_DEC = 122,
CV_PPC_SDR1 = 125,
CV_PPC_SRR0 = 126,
CV_PPC_SRR1 = 127,
CV_PPC_SPRG0 = 372, /* this includes SPRG1 to SPRG3 */
CV_PPC_ASR = 280,
CV_PPC_EAR = 382,
CV_PPC_PVR = 287,
CV_PPC_BAT0U = 628,
CV_PPC_BAT0L = 629,
CV_PPC_BAT1U = 630,
CV_PPC_BAT1L = 631,
CV_PPC_BAT2U = 632,
CV_PPC_BAT2L = 633,
CV_PPC_BAT3U = 634,
CV_PPC_BAT3L = 635,
CV_PPC_DBAT0U = 636,
CV_PPC_DBAT0L = 637,
CV_PPC_DBAT1U = 638,
CV_PPC_DBAT1L = 639,
CV_PPC_DBAT2U = 640,
CV_PPC_DBAT2L = 641,
CV_PPC_DBAT3U = 642,
CV_PPC_DBAT3L = 643,
CV_PPC_PMR0 = 1044, /* this includes PMR1 to PMR15 */
CV_PPC_DMISS = 1076,
CV_PPC_DCMP = 1077,
CV_PPC_HASH1 = 1078,
CV_PPC_HASH2 = 1079,
CV_PPC_IMISS = 1080,
CV_PPC_ICMP = 1081,
CV_PPC_RPA = 1082,
CV_PPC_HID0 = 1108, /* this includes HID1 to HID15 */
/* Java */
CV_JAVA_PC = 1,
/* Hitachi SH3 CPU */
CV_SH3_NOREG = CV_REG_NONE,
@ -357,7 +434,29 @@ enum CV_HREG_e
CV_ARM_LR = 24,
CV_ARM_PC = 25,
CV_ARM_CPSR = 26,
CV_ARM_ACC0 = 27,
CV_ARM_FPSCR = 40,
CV_ARM_FPEXC = 41,
CV_ARM_FS0 = 50, /* this includes FS1 to FS31 */
CV_ARM_FPEXTRA0 = 90, /* this includes FPEXTRA1 to FPEXTRA7 */
CV_ARM_WR0 = 128, /* this includes WR1 to WR15 */
CV_ARM_WCID = 144,
CV_ARM_WCON = 145,
CV_ARM_WCSSF = 146,
CV_ARM_WCASF = 147,
CV_ARM_WC4 = 148,
CV_ARM_WC5 = 149,
CV_ARM_WC6 = 150,
CV_ARM_WC7 = 151,
CV_ARM_WCGR0 = 152, /* this includes WCGR1 to WCGR3 */
CV_ARM_WC12 = 156,
CV_ARM_WC13 = 157,
CV_ARM_WC14 = 158,
CV_ARM_WC15 = 159,
CV_ARM_FS32 = 200, /* this includes FS33 to FS63 */
CV_ARM_ND0 = 300, /* this includes ND1 to ND31 */
CV_ARM_NQ0 = 400, /* this includes NQ1 to NQ15 */
/* Intel IA64 CPU */
CV_IA64_NOREG = CV_REG_NONE,
CV_IA64_Br0 = 512, /* this includes Br1 to Br7 */
@ -395,7 +494,31 @@ enum CV_HREG_e
CV_TRI_EA10 = 55,
CV_TRI_EA12 = 56,
CV_TRI_EA14 = 57,
/* some TriCode registers missing */
CV_TRI_PSW = 58,
CV_TRI_PCXI = 59,
CV_TRI_PC = 60,
CV_TRI_FCX = 61,
CV_TRI_LCX = 62,
CV_TRI_ISP = 63,
CV_TRI_ICR = 64,
CV_TRI_BIV = 65,
CV_TRI_BTV = 66,
CV_TRI_SYSCON = 67,
CV_TRI_DPRx_0 = 68, /* includes DPRx_1 to DPRx_3 */
CV_TRI_CPRx_0 = 68, /* includes CPRx_1 to CPRx_3 */
CV_TRI_DPMx_0 = 68, /* includes DPMx_1 to DPMx_3 */
CV_TRI_CPMx_0 = 68, /* includes CPMx_1 to CPMx_3 */
CV_TRI_DBGSSR = 72,
CV_TRI_EXEVT = 73,
CV_TRI_SWEVT = 74,
CV_TRI_CREVT = 75,
CV_TRI_TRnEVT = 76,
CV_TRI_MMUCON = 77,
CV_TRI_ASI = 78,
CV_TRI_TVA = 79,
CV_TRI_TPA = 80,
CV_TRI_TPX = 81,
CV_TRI_TFA = 82,
/* AM33 (and the likes) CPU */
CV_AM33_NOREG = CV_REG_NONE,
@ -403,6 +526,17 @@ enum CV_HREG_e
CV_AM33_A0 = 20, /* this includes A1 to A3 */
CV_AM33_D0 = 30, /* this includes D1 to D3 */
CV_AM33_FS0 = 40, /* this includes FS1 to FS31 */
CV_AM33_SP = 80,
CV_AM33_PC = 81,
CV_AM33_MDR = 82,
CV_AM33_MDRQ = 83,
CV_AM33_MCRH = 84,
CV_AM33_MCRL = 85,
CV_AM33_MCVF = 86,
CV_AM33_EPSW = 87,
CV_AM33_FPCR = 88,
CV_AM33_LIR = 89,
CV_AM33_LAR = 90,
/* Mitsubishi M32R CPU */
CV_M32R_NOREG = CV_REG_NONE,
@ -532,17 +666,11 @@ enum CV_HREG_e
CV_AMD64_R15 = 343,
/* Wine extension */
CV_SPARC_NOREG = CV_REG_NONE,
CV_SPARC_G0 = 10, /* includes g0 to g7 */
CV_SPARC_O0 = 18, /* includes o0 to o7 */
CV_SPARC_L0 = 26, /* includes l0 to l7 */
CV_SPARC_I0 = 34, /* includes i0 to i7 */
CV_SPARC_PSR = 42,
CV_SPARC_PC = 43,
CV_SPARC_NPC = 44,
CV_SPARC_Y = 45,
CV_SPARC_WIM = 46,
CV_SPARC_TBR = 47,
CV_ARM64_NOREG = CV_REG_NONE,
CV_ARM64_X0 = 10, /* this includes X0 to X30 */
CV_ARM64_SP = 41,
CV_ARM64_PC = 42,
CV_ARM64_PSTATE = 43,
};
typedef enum

View file

@ -1667,7 +1667,7 @@ typedef enum {
#define IMAGE_FILE_MACHINE_AM33 0x1d3
#define IMAGE_FILE_MACHINE_AMD64 0x8664
#define IMAGE_FILE_MACHINE_ARM 0x1c0
#define IMAGE_FILE_MACHINE_ARMV7 0x1c4
#define IMAGE_FILE_MACHINE_ARMNT 0x1c4
#define IMAGE_FILE_MACHINE_EBC 0xebc
#define IMAGE_FILE_MACHINE_I386 0x14c
#define IMAGE_FILE_MACHINE_IA64 0x200
@ -1694,6 +1694,9 @@ typedef enum {
#define IMAGE_FILE_MACHINE_TRICORE 0x0520
#define IMAGE_FILE_MACHINE_CEF 0x0CEF
/* Wine extension */
#define IMAGE_FILE_MACHINE_ARM64 0x1c5
#define IMAGE_FILE_EXPORT_DIRECTORY 0
#define IMAGE_FILE_IMPORT_DIRECTORY 1
#define IMAGE_FILE_RESOURCE_DIRECTORY 2

View file

@ -723,6 +723,18 @@ union codeview_fieldtype
struct p_string p_name;
} membermodify_v2;
struct
{
short int id;
short int ref;
} index_v1;
struct
{
short int id;
short int unk;
unsigned int ref;
} index_v2;
};

View file

@ -58,7 +58,7 @@ reactos/dll/win32/cryptdlg # Synced to Wine-1.5.26
reactos/dll/win32/cryptdll # Synced to Wine-1.5.26
reactos/dll/win32/cryptnet # Synced to Wine-1.5.26
reactos/dll/win32/cryptui # Synced to Wine-1.5.26
reactos/dll/win32/dbghelp # Synced to Wine-1.3.37
reactos/dll/win32/dbghelp # Synced to Wine-1.5.26
reactos/dll/win32/dciman32 # Synced to Wine-1.5.19
reactos/dll/win32/dwmapi # Synced to Wine-1.5.19
reactos/dll/win32/faultrep # Synced to Wine-1.5.4