- all symbol information storage is now module relative, so we can

unload a module (and it's debugging information), and a process
  without pain
- portabiblity to another CPU should be easier now (CPU dependent backend)
- speed up memory allocation
- stabs related fixes:
      + now correctly handling symbol's size
      + blocks {} in functions are now correctly recognized and stored
        (also applies to local variables scoping)
      + better basic types management (less wild guesses in the code)
      + full support of inline functions (source stepping now shows the
        code in .h files for example)
- removal of external debugger (attaching with gdb is just fine to
  debug winedbg)
- fixed a couple of issues for symbol address handling (address
  lookup, incorrect type binding)
- winedbg now has a man page
This commit is contained in:
Eric Pouech 2004-06-04 00:59:16 +00:00 committed by Alexandre Julliard
parent 9f33a4b109
commit deca2502d6
31 changed files with 7837 additions and 14141 deletions

File diff suppressed because it is too large Load Diff

View File

@ -220,14 +220,22 @@ HANDLE32 WINAPI YourFunc(LPCSTR s)
</sect1>
<sect1 id="dbg-control">
<title>Controlling the debugging output</title>
<sect1 id="dbg-control">
<title>Controlling the debugging output</title>
<para>
It is possible to turn on and off debugging output from
within the debugger using the set command. Please see the
WineDbg Command Reference section for how to do this.
</para>
<para>
It is possible to turn on and off debugging output from
within the debugger using the set command. Please see the
WineDbg Command Reference section
(<xref linkend="winedbg-dbg-chan">) for how to do this.
</para>
<para>
You can do the same using the task manager
(<command>taskmgr</command>) and selecting your application in
the application list. Right clicking on the application, and
selecting the debug option in the popup menu, will let you
select the modifications you want on the debug channels.
</para>
<para>
Another way to conditionally log debug output (e.g. in case of

View File

@ -4,26 +4,21 @@ SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = winedbg.exe
APPMODE = -mconsole
IMPORTS = advapi32 kernel32 ntdll
IMPORTS = dbghelp advapi32 kernel32 ntdll
DELAYIMPORTS = user32
C_SRCS = \
be_i386.c \
be_ppc.c \
break.c \
db_disasm.c \
display.c \
elf.c \
expr.c \
ext_debugger.c \
gdbproxy.c \
hash.c \
info.c \
memory.c \
module.c \
msc.c \
pe.c \
registers.c \
source.c \
stabs.c \
symbol.c \
stack.c \
types.c \
winedbg.c
@ -45,4 +40,11 @@ y.tab.o: y.tab.h
@LEX_OUTPUT_ROOT@.o: y.tab.h
install::
$(MKINSTALLDIRS) $(mandir)/man$(prog_manext)
$(INSTALL_DATA) $(SRCDIR)/winedbg.man $(mandir)/man$(prog_manext)/winedbg.$(prog_manext)
uninstall::
$(RM) $(mandir)/man$(prog_manext)/winedbg.$(prog_manext)
### Dependencies:

116
programs/winedbg/be_cpu.h Normal file
View File

@ -0,0 +1,116 @@
/*
* Debugger CPU backend definitions
*
* Copyright 2004 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
enum be_cpu_addr {be_cpu_addr_pc, be_cpu_addr_stack, be_cpu_addr_frame};
enum be_xpoint_type {be_xpoint_break, be_xpoint_watch_exec, be_xpoint_watch_read,
be_xpoint_watch_write};
struct backend_cpu
{
/* ------------------------------------------------------------------------------
* address manipulation
* ------------------------------------------------------------------------------ */
/* Linearizes an address. Only CPUs with segmented address model need this.
* Otherwise, implementation is straigthforward (be_cpu_linearize will do)
*/
void* (*linearize)(HANDLE hThread, const ADDRESS*);
/* Fills in an ADDRESS structure from a segment & an offset. CPUs without
* segment address model should use 0 as seg. Required method to fill
* in an ADDRESS (except an linear one).
* Non segmented CPU shall use be_cpu_build_addr
*/
unsigned (*build_addr)(HANDLE hThread, const CONTEXT* ctx,
ADDRESS* addr, unsigned seg,
unsigned long offset);
/* Retrieves in addr an address related to the context (program counter, stack
* pointer, frame pointer)
*/
unsigned (*get_addr)(HANDLE hThread, const CONTEXT* ctx,
enum be_cpu_addr, ADDRESS* addr);
/* -------------------------------------------------------------------------------
* context manipulation
* ------------------------------------------------------------------------------- */
/* Enables/disables CPU single step mode (depending on enable) */
void (*single_step)(CONTEXT* ctx, unsigned enable);
/* Dumps out the content of the context */
void (*print_context)(HANDLE hThread, const CONTEXT* ctx);
/* Prints information about segments. Non segmented CPU should leave this
* function empty
*/
void (*print_segment_info)(HANDLE hThread, const CONTEXT* ctx);
/* Do the initialization so that the debugger has internal variables linked
* to the context's registers
*/
const struct dbg_internal_var*
(*init_registers)(CONTEXT* ctx);
/* -------------------------------------------------------------------------------
* code inspection
* -------------------------------------------------------------------------------*/
/* Check whether the instruction at addr is an insn to step over
* (like function call, interruption...)
*/
unsigned (*is_step_over_insn)(const void* addr);
/* Check whether instruction at 'addr' is the return from a function call */
unsigned (*is_function_return)(const void* addr);
/* Check whether instruction at 'addr' is the CPU break instruction. On i386,
* it's INT3 (0xCC)
*/
unsigned (*is_break_insn)(const void*);
/* Check whether instruciton at 'addr' is a function call */
unsigned (*is_function_call)(const void* insn, ADDRESS* callee);
/* Ask for dissasembling one instruction. If display is true, assembly code
* will be printed. In all cases, 'addr' is advanced at next instruction
*/
void (*disasm_one_insn)(ADDRESS* addr, int display);
/* -------------------------------------------------------------------------------
* break points / watchpoints handling
* -------------------------------------------------------------------------------*/
/* Inserts an Xpoint in the CPU context and/or debuggee address space */
unsigned (*insert_Xpoint)(HANDLE hProcess, CONTEXT* ctx,
enum be_xpoint_type type, void* addr,
unsigned long* val, unsigned size);
/* Removes an Xpoint in the CPU context and/or debuggee address space */
unsigned (*remove_Xpoint)(HANDLE hProcess, CONTEXT* ctx,
enum be_xpoint_type type, void* addr,
unsigned long val, unsigned size);
/* Checks whether a given watchpoint has been triggered */
unsigned (*is_watchpoint_set)(const CONTEXT* ctx, unsigned idx);
/* Clears the watchpoint indicator */
void (*clear_watchpoint)(CONTEXT* ctx, unsigned idx);
/* After a break instruction is executed, in the corresponding exception handler,
* some CPUs report the address of the insn after the break insn, some others
* report the address of the break insn itself.
* This function lets adjust the context PC to reflect this behavior.
*/
int (*adjust_pc_for_break)(CONTEXT* ctx, BOOL way);
/* -------------------------------------------------------------------------------
* basic type read/write
* -------------------------------------------------------------------------------*/
/* Reads an integer from memory and stores it inside a long long int */
int (*fetch_integer)(const struct dbg_lvalue* lvalue, unsigned size, unsigned is_signed, long long int*);
/* Reads a real from memory and stores it inside a long double */
int (*fetch_float)(const struct dbg_lvalue* lvalue, unsigned size, long double*);
};
extern struct backend_cpu* be_cpu;
/* some handy functions for non segmented CPUs */
void* be_cpu_linearize(HANDLE hThread, const ADDRESS*);
unsigned be_cpu_build_addr(HANDLE hThread, const CONTEXT* ctx, ADDRESS* addr,
unsigned seg, unsigned long offset);

549
programs/winedbg/be_i386.c Normal file
View File

@ -0,0 +1,549 @@
/*
* Debugger i386 specific functions
*
* Copyright 2004 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "debugger.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
#ifdef __i386__
/* debugger/db_disasm.c */
extern void be_i386_disasm_one_insn(ADDRESS* addr, int display);
#define STEP_FLAG 0x00000100 /* single step flag */
#define V86_FLAG 0x00020000
#define IS_VM86_MODE(ctx) (ctx->EFlags & V86_FLAG)
static ADDRESS_MODE get_selector_type(HANDLE hThread, const CONTEXT* ctx, WORD sel)
{
LDT_ENTRY le;
if (IS_VM86_MODE(ctx)) return AddrModeReal;
/* null or system selector */
if (!(sel & 4) || ((sel >> 3) < 17)) return AddrModeFlat;
if (GetThreadSelectorEntry(hThread, sel, &le))
return le.HighWord.Bits.Default_Big ? AddrMode1632 : AddrMode1616;
/* selector doesn't exist */
return -1;
}
static void* be_i386_linearize(HANDLE hThread, const ADDRESS* addr)
{
LDT_ENTRY le;
switch (addr->Mode)
{
case AddrModeReal:
return (void*)((DWORD)(LOWORD(addr->Segment) << 4) + addr->Offset);
case AddrMode1632:
if (!(addr->Segment & 4) || ((addr->Segment >> 3) < 17))
return (void*)addr->Offset;
/* fall through */
case AddrMode1616:
if (!GetThreadSelectorEntry(hThread, addr->Segment, &le)) return NULL;
return (void*)((le.HighWord.Bits.BaseHi << 24) +
(le.HighWord.Bits.BaseMid << 16) + le.BaseLow + addr->Offset);
break;
case AddrModeFlat:
return (void*)addr->Offset;
}
return NULL;
}
static unsigned be_i386_build_addr(HANDLE hThread, const CONTEXT* ctx, ADDRESS* addr,
unsigned seg, unsigned long offset)
{
addr->Mode = AddrModeFlat;
addr->Segment = seg;
addr->Offset = offset;
if (seg)
{
addr->Mode = get_selector_type(hThread, ctx, seg);
switch (addr->Mode)
{
case AddrModeReal:
case AddrMode1616:
addr->Offset &= 0xffff;
break;
case AddrModeFlat:
case AddrMode1632:
break;
default:
addr->Mode = -1;
return FALSE;
}
}
return TRUE;
}
static unsigned be_i386_get_addr(HANDLE hThread, const CONTEXT* ctx,
enum be_cpu_addr bca, ADDRESS* addr)
{
switch (bca)
{
case be_cpu_addr_pc:
return be_i386_build_addr(hThread, ctx, addr, ctx->SegCs, ctx->Eip);
case be_cpu_addr_stack:
return be_i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Esp);
case be_cpu_addr_frame:
return be_i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Ebp);
}
return FALSE;
}
static void be_i386_single_step(CONTEXT* ctx, unsigned enable)
{
if (enable) ctx->EFlags |= STEP_FLAG;
else ctx->EFlags &= ~STEP_FLAG;
}
static void be_i386_print_context(HANDLE hThread, const CONTEXT* ctx)
{
char buf[33];
char* pt;
dbg_printf("Register dump:\n");
/* First get the segment registers out of the way */
dbg_printf(" CS:%04x SS:%04x DS:%04x ES:%04x FS:%04x GS:%04x",
(WORD)ctx->SegCs, (WORD)ctx->SegSs,
(WORD)ctx->SegDs, (WORD)ctx->SegEs,
(WORD)ctx->SegFs, (WORD)ctx->SegGs);
strcpy(buf, " - 00 - - - ");
pt = buf + strlen(buf) - 1;
if (ctx->EFlags & 0x00000001) *pt-- = 'C'; /* Carry Flag */
if (ctx->EFlags & 0x00000002) *pt-- = '1';
if (ctx->EFlags & 0x00000004) *pt-- = 'P'; /* Parity Flag */
if (ctx->EFlags & 0x00000008) *pt-- = '-';
if (ctx->EFlags & 0x00000010) *pt-- = 'A'; /* Auxiliary Carry Flag */
if (ctx->EFlags & 0x00000020) *pt-- = '-';
if (ctx->EFlags & 0x00000040) *pt-- = 'Z'; /* Zero Flag */
if (ctx->EFlags & 0x00000080) *pt-- = 'S'; /* Sign Flag */
if (ctx->EFlags & 0x00000100) *pt-- = 'T'; /* Trap/Trace Flag */
if (ctx->EFlags & 0x00000200) *pt-- = 'I'; /* Interupt Enable Flag */
if (ctx->EFlags & 0x00000400) *pt-- = 'D'; /* Direction Indicator */
if (ctx->EFlags & 0x00000800) *pt-- = 'O'; /* Overflow flags */
if (ctx->EFlags & 0x00001000) *pt-- = '1'; /* I/O Privilege Level */
if (ctx->EFlags & 0x00002000) *pt-- = '1'; /* I/O Privilege Level */
if (ctx->EFlags & 0x00004000) *pt-- = 'N'; /* Nested Task Flag */
if (ctx->EFlags & 0x00008000) *pt-- = '-';
if (ctx->EFlags & 0x00010000) *pt-- = 'R'; /* Resume Flag */
if (ctx->EFlags & 0x00020000) *pt-- = 'V'; /* Vritual Mode Flag */
if (ctx->EFlags & 0x00040000) *pt-- = 'a'; /* Alignment Check Flag */
switch (get_selector_type(hThread, ctx, ctx->SegCs))
{
case AddrMode1616:
case AddrModeReal:
dbg_printf("\n IP:%04x SP:%04x BP:%04x FLAGS:%04x(%s)\n",
LOWORD(ctx->Eip), LOWORD(ctx->Esp),
LOWORD(ctx->Ebp), LOWORD(ctx->EFlags), buf);
dbg_printf(" AX:%04x BX:%04x CX:%04x DX:%04x SI:%04x DI:%04x\n",
LOWORD(ctx->Eax), LOWORD(ctx->Ebx),
LOWORD(ctx->Ecx), LOWORD(ctx->Edx),
LOWORD(ctx->Esi), LOWORD(ctx->Edi));
break;
case AddrModeFlat:
case AddrMode1632:
dbg_printf("\n EIP:%08lx ESP:%08lx EBP:%08lx EFLAGS:%08lx(%s)\n",
ctx->Eip, ctx->Esp, ctx->Ebp, ctx->EFlags, buf);
dbg_printf(" EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n",
ctx->Eax, ctx->Ebx, ctx->Ecx, ctx->Edx);
dbg_printf(" ESI:%08lx EDI:%08lx\n",
ctx->Esi, ctx->Edi);
break;
}
}
static void be_i386_print_segment_info(HANDLE hThread, const CONTEXT* ctx)
{
if (get_selector_type(hThread, ctx, ctx->SegCs) == AddrMode1616)
{
info_win32_segments(ctx->SegDs >> 3, 1);
if (ctx->SegEs != ctx->SegDs) info_win32_segments(ctx->SegEs >> 3, 1);
}
info_win32_segments(ctx->SegFs >> 3, 1);
}
static struct dbg_internal_var be_i386_ctx[] =
{
{CV_REG_AL, "AL", (DWORD*)FIELD_OFFSET(CONTEXT, Eax), dbg_itype_unsigned_char_int},
{CV_REG_CL, "CL", (DWORD*)FIELD_OFFSET(CONTEXT, Ecx), dbg_itype_unsigned_char_int},
{CV_REG_DL, "DL", (DWORD*)FIELD_OFFSET(CONTEXT, Edx), dbg_itype_unsigned_char_int},
{CV_REG_BL, "BL", (DWORD*)FIELD_OFFSET(CONTEXT, Ebx), dbg_itype_unsigned_char_int},
{CV_REG_AH, "AH", (DWORD*)(FIELD_OFFSET(CONTEXT, Eax)+1), dbg_itype_unsigned_char_int},
{CV_REG_CH, "CH", (DWORD*)(FIELD_OFFSET(CONTEXT, Ecx)+1), dbg_itype_unsigned_char_int},
{CV_REG_DH, "DH", (DWORD*)(FIELD_OFFSET(CONTEXT, Edx)+1), dbg_itype_unsigned_char_int},
{CV_REG_BH, "BH", (DWORD*)(FIELD_OFFSET(CONTEXT, Ebx)+1), dbg_itype_unsigned_char_int},
{CV_REG_AX, "AX", (DWORD*)FIELD_OFFSET(CONTEXT, Eax), dbg_itype_unsigned_short_int},
{CV_REG_CX, "CX", (DWORD*)FIELD_OFFSET(CONTEXT, Ecx), dbg_itype_unsigned_short_int},
{CV_REG_DX, "DX", (DWORD*)FIELD_OFFSET(CONTEXT, Edx), dbg_itype_unsigned_short_int},
{CV_REG_BX, "BX", (DWORD*)FIELD_OFFSET(CONTEXT, Ebx), dbg_itype_unsigned_short_int},
{CV_REG_SP, "SP", (DWORD*)FIELD_OFFSET(CONTEXT, Esp), dbg_itype_unsigned_short_int},
{CV_REG_BP, "BP", (DWORD*)FIELD_OFFSET(CONTEXT, Ebp), dbg_itype_unsigned_short_int},
{CV_REG_SI, "SI", (DWORD*)FIELD_OFFSET(CONTEXT, Esi), dbg_itype_unsigned_short_int},
{CV_REG_DI, "DI", (DWORD*)FIELD_OFFSET(CONTEXT, Edi), dbg_itype_unsigned_short_int},
{CV_REG_EAX, "EAX", (DWORD*)FIELD_OFFSET(CONTEXT, Eax), dbg_itype_unsigned_int},
{CV_REG_ECX, "ECX", (DWORD*)FIELD_OFFSET(CONTEXT, Ecx), dbg_itype_unsigned_int},
{CV_REG_EDX, "EDX", (DWORD*)FIELD_OFFSET(CONTEXT, Edx), dbg_itype_unsigned_int},
{CV_REG_EBX, "EBX", (DWORD*)FIELD_OFFSET(CONTEXT, Ebx), dbg_itype_unsigned_int},
{CV_REG_ESP, "ESP", (DWORD*)FIELD_OFFSET(CONTEXT, Esp), dbg_itype_unsigned_int},
{CV_REG_EBP, "EBP", (DWORD*)FIELD_OFFSET(CONTEXT, Ebp), dbg_itype_unsigned_int},
{CV_REG_ESI, "ESI", (DWORD*)FIELD_OFFSET(CONTEXT, Esi), dbg_itype_unsigned_int},
{CV_REG_EDI, "EDI", (DWORD*)FIELD_OFFSET(CONTEXT, Edi), dbg_itype_unsigned_int},
{CV_REG_ES, "ES", (DWORD*)FIELD_OFFSET(CONTEXT, SegEs), dbg_itype_unsigned_short_int},
{CV_REG_CS, "CS", (DWORD*)FIELD_OFFSET(CONTEXT, SegCs), dbg_itype_unsigned_short_int},
{CV_REG_SS, "SS", (DWORD*)FIELD_OFFSET(CONTEXT, SegSs), dbg_itype_unsigned_short_int},
{CV_REG_DS, "DS", (DWORD*)FIELD_OFFSET(CONTEXT, SegDs), dbg_itype_unsigned_short_int},
{CV_REG_FS, "FS", (DWORD*)FIELD_OFFSET(CONTEXT, SegFs), dbg_itype_unsigned_short_int},
{CV_REG_GS, "GS", (DWORD*)FIELD_OFFSET(CONTEXT, SegGs), dbg_itype_unsigned_short_int},
{CV_REG_IP, "IP", (DWORD*)FIELD_OFFSET(CONTEXT, Eip), dbg_itype_unsigned_short_int},
{CV_REG_FLAGS, "FLAGS", (DWORD*)FIELD_OFFSET(CONTEXT, EFlags), dbg_itype_unsigned_short_int},
{CV_REG_EIP, "EIP", (DWORD*)FIELD_OFFSET(CONTEXT, Eip), dbg_itype_unsigned_int},
{CV_REG_EFLAGS, "EFLAGS", (DWORD*)FIELD_OFFSET(CONTEXT, EFlags), dbg_itype_unsigned_int},
{0, NULL, 0, dbg_itype_none}
};
static const struct dbg_internal_var* be_i386_init_registers(CONTEXT* ctx)
{
struct dbg_internal_var* div;
for (div = be_i386_ctx; div->name; div++)
div->pval = (DWORD*)((char*)ctx + (DWORD)div->pval);
return be_i386_ctx;
}
static unsigned be_i386_is_step_over_insn(const void* insn)
{
BYTE ch;
for (;;)
{
if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
switch (ch)
{
/* Skip all prefixes */
case 0x2e: /* cs: */
case 0x36: /* ss: */
case 0x3e: /* ds: */
case 0x26: /* es: */
case 0x64: /* fs: */
case 0x65: /* gs: */
case 0x66: /* opcode size prefix */
case 0x67: /* addr size prefix */
case 0xf0: /* lock */
case 0xf2: /* repne */
case 0xf3: /* repe */
insn = (const char*)insn + 1;
continue;
/* Handle call instructions */
case 0xcd: /* int <intno> */
case 0xe8: /* call <offset> */
case 0x9a: /* lcall <seg>:<off> */
return TRUE;
case 0xff: /* call <regmodrm> */
if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
return FALSE;
return (((ch & 0x38) == 0x10) || ((ch & 0x38) == 0x18));
/* Handle string instructions */
case 0x6c: /* insb */
case 0x6d: /* insw */
case 0x6e: /* outsb */
case 0x6f: /* outsw */
case 0xa4: /* movsb */
case 0xa5: /* movsw */
case 0xa6: /* cmpsb */
case 0xa7: /* cmpsw */
case 0xaa: /* stosb */
case 0xab: /* stosw */
case 0xac: /* lodsb */
case 0xad: /* lodsw */
case 0xae: /* scasb */
case 0xaf: /* scasw */
return TRUE;
default:
return FALSE;
}
}
}
static unsigned be_i386_is_function_return(const void* insn)
{
BYTE ch;
if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
return (ch == 0xC2) || (ch == 0xC3);
}
static unsigned be_i386_is_break_insn(const void* insn)
{
BYTE c;
if (!dbg_read_memory(insn, &c, 1)) return FALSE;
return c == 0xCC;
}
static unsigned be_i386_is_func_call(const void* insn, ADDRESS* callee)
{
BYTE ch;
int delta;
dbg_read_memory(insn, &ch, sizeof(ch));
if (ch == 0xe8)
{
dbg_read_memory((const char*)insn + 1, &delta, sizeof(delta));
callee->Mode = AddrModeFlat;
callee->Offset = (DWORD)insn;
be_i386_disasm_one_insn(callee, FALSE);
callee->Offset += delta;
return TRUE;
}
return FALSE;
}
#define DR7_CONTROL_SHIFT 16
#define DR7_CONTROL_SIZE 4
#define DR7_RW_EXECUTE (0x0)
#define DR7_RW_WRITE (0x1)
#define DR7_RW_READ (0x3)
#define DR7_LEN_1 (0x0)
#define DR7_LEN_2 (0x4)
#define DR7_LEN_4 (0xC)
#define DR7_LOCAL_ENABLE_SHIFT 0
#define DR7_GLOBAL_ENABLE_SHIFT 1
#define DR7_ENABLE_SIZE 2
#define DR7_LOCAL_ENABLE_MASK (0x55)
#define DR7_GLOBAL_ENABLE_MASK (0xAA)
#define DR7_CONTROL_RESERVED (0xFC00)
#define DR7_LOCAL_SLOWDOWN (0x100)
#define DR7_GLOBAL_SLOWDOWN (0x200)
#define DR7_ENABLE_MASK(dr) (1<<(DR7_LOCAL_ENABLE_SHIFT+DR7_ENABLE_SIZE*(dr)))
#define IS_DR7_SET(ctrl,dr) ((ctrl)&DR7_ENABLE_MASK(dr))
static inline int be_i386_get_unused_DR(CONTEXT* ctx, unsigned long** r)
{
if (!IS_DR7_SET(ctx->Dr7, 0))
{
*r = &ctx->Dr0;
return 0;
}
if (!IS_DR7_SET(ctx->Dr7, 1))
{
*r = &ctx->Dr1;
return 1;
}
if (!IS_DR7_SET(ctx->Dr7, 2))
{
*r = &ctx->Dr2;
return 2;
}
if (!IS_DR7_SET(ctx->Dr7, 3))
{
*r = &ctx->Dr3;
return 3;
}
dbg_printf("All hardware registers have been used\n");
return -1;
}
static unsigned be_i386_insert_Xpoint(HANDLE hProcess, CONTEXT* ctx,
enum be_xpoint_type type, void* addr,
unsigned long* val, unsigned size)
{
unsigned char ch;
unsigned long sz;
unsigned long* pr;
int reg;
unsigned long bits;
switch (type)
{
case be_xpoint_break:
if (size != 0) return 0;
if (!ReadProcessMemory(hProcess, addr, &ch, 1, &sz) || sz != 1) return 0;
*val = ch;
ch = 0xcc;
if (!WriteProcessMemory(hProcess, addr, &ch, 1, &sz) || sz != 1) return 0;
break;
case be_xpoint_watch_exec:
bits = DR7_RW_EXECUTE;
goto hw_bp;
case be_xpoint_watch_read:
bits = DR7_RW_READ;
goto hw_bp;
case be_xpoint_watch_write:
bits = DR7_RW_WRITE;
hw_bp:
if ((reg = be_i386_get_unused_DR(ctx, &pr)) == -1) return 0;
*pr = (unsigned long)addr;
if (type != be_xpoint_watch_exec) switch (size)
{
case 4: bits |= DR7_LEN_4; break;
case 2: bits |= DR7_LEN_2; break;
case 1: bits |= DR7_LEN_1; break;
default: return 0;
}
*val = reg;
/* clear old values */
ctx->Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg));
/* set the correct ones */
ctx->Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg);
ctx->Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN;
break;
default:
dbg_printf("Unknown bp type %c\n", type);
return 0;
}
return 1;
}
static unsigned be_i386_remove_Xpoint(HANDLE hProcess, CONTEXT* ctx,
enum be_xpoint_type type, void* addr,
unsigned long val, unsigned size)
{
unsigned long sz;
unsigned char ch;
switch (type)
{
case be_xpoint_break:
if (size != 0) return 0;
if (!ReadProcessMemory(hProcess, addr, &ch, 1, &sz) || sz != 1) return 0;
if (ch != (unsigned char)0xCC)
WINE_FIXME("Cannot get back %02x instead of 0xCC at %08lx\n",
ch, (unsigned long)addr);
ch = (unsigned char)val;
if (!WriteProcessMemory(hProcess, addr, &ch, 1, &sz) || sz != 1) return 0;
break;
case be_xpoint_watch_exec:
case be_xpoint_watch_read:
case be_xpoint_watch_write:
/* simply disable the entry */
ctx->Dr7 &= ~DR7_ENABLE_MASK(val);
break;
default:
dbg_printf("Unknown bp type %c\n", type);
return 0;
}
return 1;
}
static unsigned be_i386_is_watchpoint_set(const CONTEXT* ctx, unsigned idx)
{
return ctx->Dr6 & (1 << idx);
}
static void be_i386_clear_watchpoint(CONTEXT* ctx, unsigned idx)
{
ctx->Dr6 &= ~(1 << idx);
}
static int be_i386_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
{
if (way)
{
ctx->Eip--;
return -1;
}
ctx->Eip++;
return 1;
}
static int be_i386_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
unsigned ext_sign, long long int* ret)
{
if (size != 1 && size != 2 && size != 4 && size != 8) return FALSE;
memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
/* FIXME: this assumes that debuggee and debugger use the same
* integral representation
*/
if (!memory_read_value(lvalue, size, ret)) return FALSE;
/* propagate sign information */
if (ext_sign && size < 8 && (*ret >> (size * 8 - 1)) != 0)
{
long long unsigned int neg = -1;
*ret |= neg << (size * 8);
}
return TRUE;
}
static int be_i386_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
long double* ret)
{
char tmp[12];
/* FIXME: this assumes that debuggee and debugger use the same
* representation for reals
*/
if (!memory_read_value(lvalue, size, tmp)) return FALSE;
/* float & double types have to be promoted to a long double */
switch (size)
{
case sizeof(float): *ret = *(float*)tmp; break;
case sizeof(double): *ret = *(double*)tmp; break;
case sizeof(long double): *ret = *(long double*)tmp; break;
default: return FALSE;
}
return TRUE;
}
struct backend_cpu be_i386 =
{
be_i386_linearize,
be_i386_build_addr,
be_i386_get_addr,
be_i386_single_step,
be_i386_print_context,
be_i386_print_segment_info,
be_i386_init_registers,
be_i386_is_step_over_insn,
be_i386_is_function_return,
be_i386_is_break_insn,
be_i386_is_func_call,
be_i386_disasm_one_insn,
be_i386_insert_Xpoint,
be_i386_remove_Xpoint,
be_i386_is_watchpoint_set,
be_i386_clear_watchpoint,
be_i386_adjust_pc_for_break,
be_i386_fetch_integer,
be_i386_fetch_float,
};
#endif

192
programs/winedbg/be_ppc.c Normal file
View File

@ -0,0 +1,192 @@
/*
* Debugger Power PC specific functions
*
* Copyright 2000-2003 Marcus Meissner
* 2004 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "debugger.h"
#if defined(__powerpc__)
static unsigned be_ppc_get_addr(HANDLE hThread, const CONTEXT* ctx,
enum be_cpu_addr bca, ADDRESS* addr)
{
switch (bca)
{
case be_cpu_addr_pc:
return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->Iar);
default:
case be_cpu_addr_stack:
case be_cpu_addr_frame:
dbg_printf("not done\n");
}
return FALSE;
}
static void be_ppc_single_step(CONTEXT* ctx, unsigned enable)
{
#ifndef MSR_SE
# define MSR_SE (1<<10)
#endif
if (enable) ctx->Msr |= MSR_SE;
else ctx->Msr &= MSR_SE;
}
static void be_ppc_print_context(HANDLE hThread, const CONTEXT* ctx)
{
dbg_printf("Context printing for PPC not done yet\n");
}
static void be_ppc_print_segment_info(HANDLE hThread, const CONTEXT* ctx)
{
}
static struct dbg_internal_var be_ppc_ctx[] =
{
{0, NULL, 0, dbg_itype_none}
};
static const struct dbg_internal_var* be_ppc_init_registers(CONTEXT* ctx)
{
dbg_printf("not done\n");
return be_ppc_ctx;
}
static unsigned be_ppc_is_step_over_insn(void* insn)
{
dbg_printf("not done\n");
return FALSE;
}
static unsigned be_ppc_is_function_return(void* insn)
{
dbg_printf("not done\n");
return FALSE;
}
static unsigned be_ppc_is_break_insn(void* insn)
{
dbg_printf("not done\n");
return FALSE;
}
static unsigned be_ppc_is_func_call(void* insn, void** insn_callee)
{
return FALSE;
}
static void be_ppc_disasm_one_insn(ADDRESS* addr, int display)
{
dbg_printf("Disasm NIY\n");
}
static unsigned be_ppc_insert_Xpoint(HANDLE hProcess, CONTEXT* ctx,
enum be_xpoint_type type, void* addr,
unsigned long* val, unsigned size)
{
unsigned long xbp;
unsigned long sz;
switch (type)
{
case be_xpoint_break:
if (!size) return 0;
if (!ReadProcessMemory(hProcess, addr, val, 4, &sz) || sz != 4) return 0;
xbp = 0x7d821008; /* 7d 82 10 08 ... in big endian */
if (!WriteProcessMemory(hProcess, addr, &xbp, 4, &sz) || sz != 4) return 0;
break;
default:
dbg_printf("Unknown/unsupported bp type %c\n", type);
return 0;
}
return 1;
}
static unsigned be_ppc_remove_Xpoint(HANDLE hProcess, CONTEXT* ctx,
enum be_xpoint_type type, void* addr,
unsigned long val, unsigned size)
{
unsigned long sz;
switch (type)
{
case be_xpoint_break:
if (!size) return 0;
if (!WriteProcessMemory(hProcess, addr, &val, 4, &sz) || sz != 4) return 0;
break;
default:
dbg_printf("Unknown/unsupported bp type %c\n", type);
return 0;
}
return 1;
}
static unsigned be_ppc_is_watchpoint_set(const CONTEXT* ctx, unsigned idx)
{
dbg_printf("not done\n");
return FALSE;
}
static void be_ppc_clear_watchpoint(CONTEXT* ctx, unsigned idx)
{
dbg_printf("not done\n");
}
static int be_ppc_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
{
dbg_printf("not done\n");
return 0;
}
static int be_ppc_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
unsigned ext_sign, long long int* ret)
{
dbg_printf("not done\n");
return FALSE;
}
static int be_ppc_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
long double* ret)
{
dbg_printf("not done\n");
return FALSE;
}
struct backend_cpu be_ppc =
{
be_cpu_linearize,
be_cpu_build_addr,
be_ppc_get_addr,
be_ppc_single_step,
be_ppc_print_context,
be_ppc_print_segment_info,
be_ppc_init_registers,
be_ppc_is_step_over_insn,
be_ppc_is_function_return,
be_ppc_is_break_insn,
be_ppc_is_func_call,
be_ppc_disasm_one_insn,
be_ppc_insert_Xpoint,
be_ppc_remove_Xpoint,
be_ppc_is_watchpoint_set,
be_ppc_clear_watchpoint,
be_ppc_adjust_pc_for_break,
be_ppc_fetch_integer,
be_ppc_fetch_float,
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -220,8 +220,8 @@ static const char * const db_Grp12[] = {
};
static const struct inst db_inst_0f0x[] = {
/*00*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp6 },
/*01*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp7 },
/*00*/ { "", TRUE, NONE, op1(Ew), (const char *)db_Grp6 },
/*01*/ { "", TRUE, NONE, op1(Ew), (const char *)db_Grp7 },
/*02*/ { "lar", TRUE, LONG, op2(E,R), 0 },
/*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 },
/*04*/ { "", FALSE, NONE, 0, 0 },
@ -341,9 +341,9 @@ static const struct inst db_inst_0f6x[] = {
static const struct inst db_inst_0f7x[] = {
/*70*/ { "pshufw", TRUE, NONE, op2(MX, EMX), 0 },
/*71*/ { "(grp10)", TRUE, BYTE, op2(EMX, I), (char*)db_Grp10 },
/*72*/ { "(grp11)", TRUE, BYTE, op2(EMX, I), (char*)db_Grp11 },
/*73*/ { "(grp12)", TRUE, BYTE, op2(EMX, I), (char*)db_Grp12 },
/*71*/ { "(grp10)", TRUE, BYTE, op2(EMX, I), (const char*)db_Grp10 },
/*72*/ { "(grp11)", TRUE, BYTE, op2(EMX, I), (const char*)db_Grp11 },
/*73*/ { "(grp12)", TRUE, BYTE, op2(EMX, I), (const char*)db_Grp12 },
/*74*/ { "pcmpeqb", TRUE, NONE, op2(E, MX), 0 },
/*75*/ { "pcmpeqw", TRUE, NONE, op2(E, MX), 0 },
/*76*/ { "pcmpeqd", TRUE, NONE, op2(E, MX), 0 },
@ -431,7 +431,7 @@ static const struct inst db_inst_0fbx[] = {
/*b8*/ { "", FALSE, NONE, 0, 0 },
/*b9*/ { "", FALSE, NONE, 0, 0 },
/*ba*/ { "", TRUE, LONG, op2(Ib, E), (char *)db_Grp8 },
/*ba*/ { "", TRUE, LONG, op2(Ib, E), (const char *)db_Grp8 },
/*bb*/ { "btc", TRUE, LONG, op2(R, E), 0 },
/*bc*/ { "bsf", TRUE, LONG, op2(E, R), 0 },
/*bd*/ { "bsr", TRUE, LONG, op2(E, R), 0 },
@ -584,12 +584,12 @@ static const struct finst db_Esc8[] = {
static const struct finst db_Esc9[] = {
/*0*/ { "fld", SNGL, op1(STI), 0 },
/*1*/ { "", NONE, op1(STI), "fxch" },
/*2*/ { "fst", SNGL, op1(X), (char *)db_Esc92 },
/*3*/ { "fstp", SNGL, op1(X), (char *)db_Esc93 },
/*4*/ { "fldenv", NONE, op1(X), (char *)db_Esc94 },
/*5*/ { "fldcw", NONE, op1(X), (char *)db_Esc95 },
/*6*/ { "fnstenv",NONE, op1(X), (char *)db_Esc96 },
/*7*/ { "fnstcw", NONE, op1(X), (char *)db_Esc97 },
/*2*/ { "fst", SNGL, op1(X), (const char *)db_Esc92 },
/*3*/ { "fstp", SNGL, op1(X), (const char *)db_Esc93 },
/*4*/ { "fldenv", NONE, op1(X), (const char *)db_Esc94 },
/*5*/ { "fldcw", NONE, op1(X), (const char *)db_Esc95 },
/*6*/ { "fnstenv",NONE, op1(X), (const char *)db_Esc96 },
/*7*/ { "fnstcw", NONE, op1(X), (const char *)db_Esc97 },
};
static const struct finst db_Esca[] = {
@ -597,7 +597,7 @@ static const struct finst db_Esca[] = {
/*1*/ { "fimul", WORD, 0, 0 },
/*2*/ { "ficom", WORD, 0, 0 },
/*3*/ { "ficomp", WORD, 0, 0 },
/*4*/ { "fisub", WORD, op1(X), (char *)db_Esca4 },
/*4*/ { "fisub", WORD, op1(X), (const char *)db_Esca4 },
/*5*/ { "fisubr", WORD, 0, 0 },
/*6*/ { "fidiv", WORD, 0, 0 },
/*7*/ { "fidivr", WORD, 0, 0 }
@ -608,7 +608,7 @@ static const struct finst db_Escb[] = {
/*1*/ { "", NONE, 0, 0 },
/*2*/ { "fist", WORD, 0, 0 },
/*3*/ { "fistp", WORD, 0, 0 },
/*4*/ { "", WORD, op1(X), (char *)db_Escb4 },
/*4*/ { "", WORD, op1(X), (const char *)db_Escb4 },
/*5*/ { "fld", EXTR, 0, 0 },
/*6*/ { "", WORD, 0, 0 },
/*7*/ { "fstp", EXTR, 0, 0 },
@ -640,7 +640,7 @@ static const struct finst db_Esce[] = {
/*0*/ { "fiadd", LONG, op2(ST,STI), "faddp" },
/*1*/ { "fimul", LONG, op2(ST,STI), "fmulp" },
/*2*/ { "ficom", LONG, 0, 0 },
/*3*/ { "ficomp", LONG, op1(X), (char *)db_Esce3 },
/*3*/ { "ficomp", LONG, op1(X), (const char *)db_Esce3 },
/*4*/ { "fisub", LONG, op2(ST,STI), "fsubrp" },
/*5*/ { "fisubr", LONG, op2(ST,STI), "fsubp" },
/*6*/ { "fidiv", LONG, op2(ST,STI), "fdivrp" },
@ -652,7 +652,7 @@ static const struct finst db_Escf[] = {
/*1*/ { "", LONG, 0, 0 },
/*2*/ { "fist", LONG, 0, 0 },
/*3*/ { "fistp", LONG, 0, 0 },
/*4*/ { "fbld", NONE, op1(XA), (char *)db_Escf4 },
/*4*/ { "fbld", NONE, op1(XA), (const char *)db_Escf4 },
/*5*/ { "fld", QUAD, 0, 0 },
/*6*/ { "fbstp", NONE, 0, 0 },
/*7*/ { "fstp", QUAD, 0, 0 },
@ -864,10 +864,10 @@ static const struct inst db_inst_table[256] = {
/*7e*/ { "jle", FALSE, NONE, op1(Db), 0 },
/*7f*/ { "jnle", FALSE, NONE, op1(Db), 0 },
/*80*/ { "", TRUE, BYTE, op2(I, E), (char *)db_Grp1 },
/*81*/ { "", TRUE, LONG, op2(I, E), (char *)db_Grp1 },
/*82*/ { "", TRUE, BYTE, op2(Is,E), (char *)db_Grp1 },
/*83*/ { "", TRUE, LONG, op2(Ibs,E), (char *)db_Grp1 },
/*80*/ { "", TRUE, BYTE, op2(I, E), (const char *)db_Grp1 },
/*81*/ { "", TRUE, LONG, op2(I, E), (const char *)db_Grp1 },
/*82*/ { "", TRUE, BYTE, op2(Is,E), (const char *)db_Grp1 },
/*83*/ { "", TRUE, LONG, op2(Ibs,E), (const char *)db_Grp1 },
/*84*/ { "test", TRUE, BYTE, op2(R, E), 0 },
/*85*/ { "test", TRUE, LONG, op2(R, E), 0 },
/*86*/ { "xchg", TRUE, BYTE, op2(R, E), 0 },
@ -936,8 +936,8 @@ static const struct inst db_inst_table[256] = {
/*be*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
/*bf*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
/*c0*/ { "", TRUE, BYTE, op2(Ib, E), (char *)db_Grp2 },
/*c1*/ { "", TRUE, LONG, op2(Ib, E), (char *)db_Grp2 },
/*c0*/ { "", TRUE, BYTE, op2(Ib, E), (const char *)db_Grp2 },
/*c1*/ { "", TRUE, LONG, op2(Ib, E), (const char *)db_Grp2 },
/*c2*/ { "ret", FALSE, NONE, op1(Iw), 0 },
/*c3*/ { "ret", FALSE, NONE, 0, 0 },
/*c4*/ { "les", TRUE, LONG, op2(E, R), 0 },
@ -954,23 +954,23 @@ static const struct inst db_inst_table[256] = {
/*ce*/ { "into", FALSE, NONE, 0, 0 },
/*cf*/ { "iret", FALSE, NONE, 0, 0 },
/*d0*/ { "", TRUE, BYTE, op2(o1, E), (char *)db_Grp2 },
/*d1*/ { "", TRUE, LONG, op2(o1, E), (char *)db_Grp2 },
/*d2*/ { "", TRUE, BYTE, op2(CL, E), (char *)db_Grp2 },
/*d3*/ { "", TRUE, LONG, op2(CL, E), (char *)db_Grp2 },
/*d0*/ { "", TRUE, BYTE, op2(o1, E), (const char *)db_Grp2 },
/*d1*/ { "", TRUE, LONG, op2(o1, E), (const char *)db_Grp2 },
/*d2*/ { "", TRUE, BYTE, op2(CL, E), (const char *)db_Grp2 },
/*d3*/ { "", TRUE, LONG, op2(CL, E), (const char *)db_Grp2 },
/*d4*/ { "aam", TRUE, NONE, 0, 0 },
/*d5*/ { "aad", TRUE, NONE, 0, 0 },
/*d6*/ { "", FALSE, NONE, 0, 0 },
/*d7*/ { "xlat", FALSE, BYTE, op1(BX), 0 },
/*d8*/ { "", TRUE, NONE, 0, (char *)db_Esc8 },
/*d9*/ { "", TRUE, NONE, 0, (char *)db_Esc9 },
/*da*/ { "", TRUE, NONE, 0, (char *)db_Esca },
/*db*/ { "", TRUE, NONE, 0, (char *)db_Escb },
/*dc*/ { "", TRUE, NONE, 0, (char *)db_Escc },
/*dd*/ { "", TRUE, NONE, 0, (char *)db_Escd },
/*de*/ { "", TRUE, NONE, 0, (char *)db_Esce },
/*df*/ { "", TRUE, NONE, 0, (char *)db_Escf },
/*d8*/ { "", TRUE, NONE, 0, (const char *)db_Esc8 },
/*d9*/ { "", TRUE, NONE, 0, (const char *)db_Esc9 },
/*da*/ { "", TRUE, NONE, 0, (const char *)db_Esca },
/*db*/ { "", TRUE, NONE, 0, (const char *)db_Escb },
/*dc*/ { "", TRUE, NONE, 0, (const char *)db_Escc },
/*dd*/ { "", TRUE, NONE, 0, (const char *)db_Escd },
/*de*/ { "", TRUE, NONE, 0, (const char *)db_Esce },
/*df*/ { "", TRUE, NONE, 0, (const char *)db_Escf },
/*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 },
/*e1*/ { "loope", FALSE, NONE, op1(Db), 0 },
@ -996,8 +996,8 @@ static const struct inst db_inst_table[256] = {
/*f3*/ { "", FALSE, NONE, 0, 0 },
/*f4*/ { "hlt", FALSE, NONE, 0, 0 },
/*f5*/ { "cmc", FALSE, NONE, 0, 0 },
/*f6*/ { "", TRUE, BYTE, 0, (char *)db_Grp3 },
/*f7*/ { "", TRUE, LONG, 0, (char *)db_Grp3 },
/*f6*/ { "", TRUE, BYTE, 0, (const char *)db_Grp3 },
/*f7*/ { "", TRUE, LONG, 0, (const char *)db_Grp3 },
/*f8*/ { "clc", FALSE, NONE, 0, 0 },
/*f9*/ { "stc", FALSE, NONE, 0, 0 },
@ -1005,8 +1005,8 @@ static const struct inst db_inst_table[256] = {
/*fb*/ { "sti", FALSE, NONE, 0, 0 },
/*fc*/ { "cld", FALSE, NONE, 0, 0 },
/*fd*/ { "std", FALSE, NONE, 0, 0 },
/*fe*/ { "", TRUE, NONE, 0, (char *)db_Grp4 },
/*ff*/ { "", TRUE, NONE, 0, (char *)db_Grp5 },
/*fe*/ { "", TRUE, NONE, 0, (const char *)db_Grp4 },
/*ff*/ { "", TRUE, NONE, 0, (const char *)db_Grp5 },
};
static const struct inst db_bad_inst =
@ -1063,46 +1063,49 @@ static const int db_lengths[] = {
10, /* EXTR */
};
static unsigned int db_get_task_value( const DBG_ADDR *addr,
static unsigned int db_get_task_value( const ADDRESS* addr,
int size, int is_signed )
{
unsigned int result = 0;
char buffer[4];
if (size != 1 && size != 2 && size != 4) {
DEBUG_Printf("Illegal size specified\n");
} else {
DEBUG_READ_MEM((void*)DEBUG_ToLinear( addr ), buffer, size);
if (size != 1 && size != 2 && size != 4)
{
dbg_printf("Illegal size specified\n");
}
else
{
dbg_read_memory(memory_to_linear_addr(addr), buffer, size);
switch(size)
{
case 4:
if (is_signed) result = (unsigned int) *(int *)buffer;
else result = *(unsigned int *)buffer;
break;
case 2:
if (is_signed) result = (unsigned int) *(short int *)buffer;
else result = *(unsigned short int *)buffer;
break;
case 1:
if (is_signed) result = (unsigned int) *(char *)buffer;
else result = *(unsigned char *)buffer;
break;
}
switch (size)
{
case 4:
if (is_signed) result = (unsigned int) *(int *)buffer;
else result = *(unsigned int *)buffer;
break;
case 2:
if (is_signed) result = (unsigned int) *(short int *)buffer;
else result = *(unsigned short int *)buffer;
break;
case 1:
if (is_signed) result = (unsigned int) *(char *)buffer;
else result = *(unsigned char *)buffer;
break;
}
}
return result;
}
#define get_value_inc(result, addr, size, is_signed) \
result = db_get_task_value((addr), (size), (is_signed)); \
if (!db_disasm_16) (addr)->off += (size); \
else (addr)->off = ((addr)->off + (size)) & 0xffff;
if (!db_disasm_16) (addr)->Offset += (size); \
else (addr)->Offset = ((addr)->Offset + (size)) & 0xffff;
/*
* Read address at location and return updated location.
*/
void db_read_address( DBG_ADDR *addr, int short_addr, int regmodrm,
struct i_addr *addrp )
static void db_read_address( ADDRESS* addr, int short_addr, int regmodrm,
struct i_addr *addrp )
{
int mod, rm, sib, index, disp;
@ -1183,48 +1186,47 @@ void db_read_address( DBG_ADDR *addr, int short_addr, int regmodrm,
static void db_task_printsym(unsigned int addr, int size)
{
DBG_ADDR address;
ADDRESS a;
a.Mode = AddrModeFlat;
a.Offset = addr;
address.seg = 0;
address.off = addr;
DEBUG_PrintAddress( &address, db_disasm_16 ? MODE_16 : MODE_32, TRUE );
print_address(&a, TRUE);
}
void db_print_address(const char *seg, int size, struct i_addr *addrp, int byref)
static void db_print_address(const char *seg, int size, struct i_addr *addrp, int byref)
{
if (addrp->is_reg) {
DEBUG_Printf("%s", db_reg[size][addrp->disp]);
dbg_printf("%s", db_reg[size][addrp->disp]);
return;
}
if (seg) {
DEBUG_Printf("%s:", seg);
dbg_printf("%s:", seg);
}
if (addrp->base != 0 || addrp->index != 0) {
DEBUG_Printf("0x%x(", addrp->disp);
dbg_printf("0x%x(", addrp->disp);
if (addrp->base)
DEBUG_Printf("%s", addrp->base);
dbg_printf("%s", addrp->base);
if (addrp->index)
DEBUG_Printf(",%s,%d", addrp->index, 1<<addrp->ss);
DEBUG_Printf(")");
dbg_printf(",%s,%d", addrp->index, 1<<addrp->ss);
dbg_printf(")");
}
else {
/* try to get destination of indirect call
does not work for segmented adresses */
if (!seg && byref) {
void* a1;
void* a2;
DEBUG_Printf("0x%x -> ", addrp->disp);
if (!DEBUG_READ_MEM((void*)addrp->disp, &a1, sizeof(a1))) {
DEBUG_Printf("(invalid source)");
} else if (!DEBUG_READ_MEM(a1, &a2, sizeof(a2))) {
DEBUG_Printf("(invalid destination)");
void* a1;
void* a2;
dbg_printf("0x%x -> ", addrp->disp);
if (!dbg_read_memory((void*)addrp->disp, &a1, sizeof(a1))) {
dbg_printf("(invalid source)");
} else if (!dbg_read_memory(a1, &a2, sizeof(a2))) {
dbg_printf("(invalid destination)");
} else {
db_task_printsym((unsigned long)a1, 0);
db_task_printsym((unsigned long)a1, 0);
}
}
else
@ -1236,8 +1238,8 @@ void db_print_address(const char *seg, int size, struct i_addr *addrp, int byref
* Disassemble floating-point ("escape") instruction
* and return updated location.
*/
void db_disasm_esc( DBG_ADDR *addr, int inst, int short_addr,
int size, const char *seg )
static void db_disasm_esc( ADDRESS* addr, int inst, int short_addr,
int size, const char *seg )
{
int regmodrm;
const struct finst *fp;
@ -1259,7 +1261,7 @@ void db_disasm_esc( DBG_ADDR *addr, int inst, int short_addr,
* Normal address modes.
*/
db_read_address( addr, short_addr, regmodrm, &address);
DEBUG_Printf(fp->f_name);
dbg_printf(fp->f_name);
switch(fp->f_size) {
case SNGL: p = "s"; break;
case DBLR: p = "l"; break;
@ -1269,7 +1271,7 @@ void db_disasm_esc( DBG_ADDR *addr, int inst, int short_addr,
case QUAD: p = "q"; break;
default: p = ""; break;
}
DEBUG_Printf("%s\t", p);
dbg_printf("%s\t", p);
db_print_address(seg, BYTE, &address, 0);
}
else {
@ -1279,24 +1281,24 @@ void db_disasm_esc( DBG_ADDR *addr, int inst, int short_addr,
switch (fp->f_rrmode) {
case op2(ST,STI):
name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
DEBUG_Printf("%s\t%%st,%%st(%d)",name,f_rm(regmodrm));
dbg_printf("%s\t%%st,%%st(%d)",name,f_rm(regmodrm));
break;
case op2(STI,ST):
name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
DEBUG_Printf("%s\t%%st(%d),%%st",name, f_rm(regmodrm));
dbg_printf("%s\t%%st(%d),%%st",name, f_rm(regmodrm));
break;
case op1(STI):
name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
DEBUG_Printf("%s\t%%st(%d)",name, f_rm(regmodrm));
dbg_printf("%s\t%%st(%d)",name, f_rm(regmodrm));
break;
case op1(X):
DEBUG_Printf("%s", ((char **)fp->f_rrname)[f_rm(regmodrm)]);
dbg_printf("%s", ((char * const*)fp->f_rrname)[f_rm(regmodrm)]);
break;
case op1(XA):
DEBUG_Printf("%s\t%%ax", ((char **)fp->f_rrname)[f_rm(regmodrm)]);
dbg_printf("%s\t%%ax", ((char * const*)fp->f_rrname)[f_rm(regmodrm)]);
break;
default:
DEBUG_Printf("<bad instruction>");
dbg_printf("<bad instruction>");
break;
}
}
@ -1304,12 +1306,12 @@ void db_disasm_esc( DBG_ADDR *addr, int inst, int short_addr,
/***********************************************************************
* DEBUG_Disasm
* disasm_one_insn
*
* Disassemble instruction at 'addr'. addr is changed to point to the
* start of the next instruction.
*/
void DEBUG_Disasm( DBG_ADDR *addr, int display )
void be_i386_disasm_one_insn(ADDRESS *addr, int display)
{
int inst;
int size;
@ -1331,12 +1333,11 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
* Set this so we get can supress the printout if we need to.
*/
db_display = display;
switch (DEBUG_GetSelectorType(addr->seg))
switch (addr->Mode)
{
case MODE_VM86:
case MODE_16: db_disasm_16 = 1; break;
case MODE_32: db_disasm_16 = 0; break;
default: DEBUG_Printf("Bad selector %lx\n", addr->seg); return;
case AddrModeReal:
case AddrMode1616: db_disasm_16 = 1; break;
default: db_disasm_16 = 0; break;
}
get_value_inc( inst, addr, 1, FALSE );
@ -1386,15 +1387,15 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
break;
case 0xf0:
if( db_display )
DEBUG_Printf("lock ");
dbg_printf("lock ");
break;
case 0xf2:
if( db_display )
DEBUG_Printf("repne ");
dbg_printf("repne ");
break;
case 0xf3:
if( db_display )
DEBUG_Printf("repe "); /* XXX repe VS rep */
dbg_printf("repe "); /* XXX repe VS rep */
break;
default:
prefix = FALSE;
@ -1433,25 +1434,25 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
i_size = ip->i_size;
i_mode = ip->i_mode;
if (ip->i_extra == (char *)db_Grp1 ||
ip->i_extra == (char *)db_Grp2 ||
ip->i_extra == (char *)db_Grp6 ||
ip->i_extra == (char *)db_Grp7 ||
ip->i_extra == (char *)db_Grp8 ||
ip->i_extra == (char *)db_Grp10 ||
ip->i_extra == (char *)db_Grp11 ||
ip->i_extra == (char *)db_Grp12) {
i_name = ((char **)ip->i_extra)[f_reg(regmodrm)];
if (ip->i_extra == (const char *)db_Grp1 ||
ip->i_extra == (const char *)db_Grp2 ||
ip->i_extra == (const char *)db_Grp6 ||
ip->i_extra == (const char *)db_Grp7 ||
ip->i_extra == (const char *)db_Grp8 ||
ip->i_extra == (const char *)db_Grp10 ||
ip->i_extra == (const char *)db_Grp11 ||
ip->i_extra == (const char *)db_Grp12) {
i_name = ((const char * const*)ip->i_extra)[f_reg(regmodrm)];
}
else if (ip->i_extra == (char *)db_Grp3) {
ip = (struct inst *)ip->i_extra;
else if (ip->i_extra == (const char *)db_Grp3) {
ip = (const struct inst *)ip->i_extra;
ip = &ip[f_reg(regmodrm)];
i_name = ip->i_name;
i_mode = ip->i_mode;
}
else if (ip->i_extra == (char *)db_Grp4 ||
ip->i_extra == (char *)db_Grp5) {
ip = (struct inst *)ip->i_extra;
else if (ip->i_extra == (const char *)db_Grp4 ||
ip->i_extra == (const char *)db_Grp5) {
ip = (const struct inst *)ip->i_extra;
ip = &ip[f_reg(regmodrm)];
i_name = ip->i_name;
i_mode = ip->i_mode;
@ -1462,28 +1463,28 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
if( db_display )
{
if (size == WORD)
DEBUG_Printf(i_name);
dbg_printf(i_name);
else
DEBUG_Printf(ip->i_extra);
dbg_printf(ip->i_extra);
}
}
else {
if( db_display )
{
DEBUG_Printf(i_name);
dbg_printf(i_name);
}
if (i_size != NONE) {
if (i_size == BYTE) {
if( db_display )
{
DEBUG_Printf("b");
dbg_printf("b");
}
size = BYTE;
}
else if (i_size == WORD) {
if( db_display )
{
DEBUG_Printf("w");
dbg_printf("w");
}
size = WORD;
}
@ -1491,28 +1492,28 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
{
if( db_display )
{
DEBUG_Printf("w");
dbg_printf("w");
}
}
else
{
if( db_display )
{
DEBUG_Printf("l");
dbg_printf("l");
}
}
}
}
if( db_display )
{
DEBUG_Printf("\t");
dbg_printf("\t");
}
for (first = TRUE;
i_mode != 0;
i_mode >>= 8, first = FALSE)
{
if (!first && db_display)
DEBUG_Printf(",");
dbg_printf(",");
switch (i_mode & 0xFF) {
@ -1526,7 +1527,7 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
case Eind:
if( db_display )
{
DEBUG_Printf("*");
dbg_printf("*");
db_print_address(seg, size, &address, 1);
}
break;
@ -1548,31 +1549,31 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
case R:
if( db_display )
{
DEBUG_Printf("%s", db_reg[size][f_reg(regmodrm)]);
dbg_printf("%s", db_reg[size][f_reg(regmodrm)]);
}
break;
case MX:
if( db_display )
{
DEBUG_Printf("%%mm%d", f_reg(regmodrm));
dbg_printf("%%mm%d", f_reg(regmodrm));
}
break;
case EMX:
if( db_display )
{
DEBUG_Printf("%%mm%d", f_rm(regmodrm));
dbg_printf("%%mm%d", f_rm(regmodrm));
}
break;
case XMM:
if( db_display )
{
DEBUG_Printf("%%xmm%d", f_reg(regmodrm));
dbg_printf("%%xmm%d", f_reg(regmodrm));
}
break;
case EXMM:
if( db_display )
{
DEBUG_Printf("%%xmm%d", f_rm(regmodrm));
dbg_printf("%%xmm%d", f_rm(regmodrm));
}
break;
@ -1580,35 +1581,35 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
case Rw:
if( db_display )
{
DEBUG_Printf("%s", db_reg[WORD][f_reg(regmodrm)]);
dbg_printf("%s", db_reg[WORD][f_reg(regmodrm)]);
}
break;
case Ri:
if( db_display )
{
DEBUG_Printf("%s", db_reg[size][f_rm(inst)]);
dbg_printf("%s", db_reg[size][f_rm(inst)]);
}
break;
case S:
if( db_display )
{
DEBUG_Printf("%s", db_seg_reg[f_reg(regmodrm)]);
dbg_printf("%s", db_seg_reg[f_reg(regmodrm)]);
}
break;
case Si:
if( db_display )
{
DEBUG_Printf("%s", db_seg_reg[f_reg(inst)]);
dbg_printf("%s", db_seg_reg[f_reg(inst)]);
}
break;
case A:
if( db_display )
{
DEBUG_Printf("%s", db_reg[size][0]); /* acc */
dbg_printf("%s", db_reg[size][0]); /* acc */
}
break;
@ -1616,22 +1617,22 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
if( db_display )
{
if (seg)
DEBUG_Printf("%s:", seg);
DEBUG_Printf("(%s)", short_addr ? "%bx" : "%ebx");
dbg_printf("%s:", seg);
dbg_printf("(%s)", short_addr ? "%bx" : "%ebx");
}
break;
case CL:
if( db_display )
{
DEBUG_Printf("%%cl");
dbg_printf("%%cl");
}
break;
case DX:
if( db_display )
{
DEBUG_Printf("%%dx");
dbg_printf("%%dx");
}
break;
@ -1639,36 +1640,36 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
if( db_display )
{
if (seg)
DEBUG_Printf("%s:", seg);
DEBUG_Printf("(%s)", short_addr ? "%si" : "%esi");
dbg_printf("%s:", seg);
dbg_printf("(%s)", short_addr ? "%si" : "%esi");
}
break;
case DI:
if( db_display )
{
DEBUG_Printf("%%es:(%s)", short_addr ? "%di" : "%edi");
dbg_printf("%%es:(%s)", short_addr ? "%di" : "%edi");
}
break;
case CR:
if( db_display )
{
DEBUG_Printf("%%cr%d", f_reg(regmodrm));
dbg_printf("%%cr%d", f_reg(regmodrm));
}
break;
case DR:
if( db_display )
{
DEBUG_Printf("%%dr%d", f_reg(regmodrm));
dbg_printf("%%dr%d", f_reg(regmodrm));
}
break;
case TR:
if( db_display )
{
DEBUG_Printf("%%tr%d", f_reg(regmodrm));
dbg_printf("%%tr%d", f_reg(regmodrm));
}
break;
@ -1677,7 +1678,7 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
get_value_inc(imm, addr, len, FALSE);/* unsigned */
if( db_display )
{
DEBUG_Printf("$0x%x", imm);
dbg_printf("$0x%x", imm);
}
break;
@ -1686,7 +1687,7 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
get_value_inc(imm, addr, len, TRUE); /* signed */
if( db_display )
{
DEBUG_Printf("$%d", imm);
dbg_printf("$%d", imm);
}
break;
@ -1694,7 +1695,7 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
get_value_inc(imm, addr, 1, FALSE); /* unsigned */
if( db_display )
{
DEBUG_Printf("$0x%x", imm);
dbg_printf("$0x%x", imm);
}
break;
@ -1702,7 +1703,7 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
get_value_inc(imm, addr, 1, TRUE); /* signed */
if( db_display )
{
DEBUG_Printf("$%d", imm);
dbg_printf("$%d", imm);
}
break;
@ -1710,7 +1711,7 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
get_value_inc(imm, addr, 2, FALSE); /* unsigned */
if( db_display )
{
DEBUG_Printf("$0x%x", imm);
dbg_printf("$0x%x", imm);
}
break;
@ -1718,7 +1719,7 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
get_value_inc(imm, addr, 4, FALSE);
if( db_display )
{
DEBUG_Printf("$0x%x", imm);
dbg_printf("$0x%x", imm);
}
break;
@ -1735,7 +1736,7 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
}
if (seg)
DEBUG_Printf("%s:0x%x",seg, displ);
dbg_printf("%s:0x%x",seg, displ);
else
db_task_printsym(displ, short_addr ? WORD : LONG);
break;
@ -1749,23 +1750,23 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
if (size == WORD) {
/* offset only affects low 16 bits */
displ = (addr->off & 0xffff0000)
| ((addr->off + displ) & 0xffff);
displ = (addr->Offset & 0xffff0000)
| ((addr->Offset + displ) & 0xffff);
}
else displ += addr->off;
else displ += addr->Offset;
db_task_printsym(displ, size);
break;
case Dl:
if (size == WORD) {
get_value_inc(displ, addr, 2, TRUE);
/* offset only affects low 16 bits */
displ = (addr->off & 0xffff0000)
| ((addr->off + displ) & 0xffff);
/* Offsetset only affects low 16 bits */
displ = (addr->Offset & 0xffff0000)
| ((addr->Offset + displ) & 0xffff);
}
else {
get_value_inc(displ, addr, 4, TRUE);
displ += addr->off;
displ += addr->Offset;
}
if( !db_display )
{
@ -1777,27 +1778,29 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
case o1:
if( db_display )
{
DEBUG_Printf("$1");
dbg_printf("$1");
}
break;
case o3:
if( db_display )
{
DEBUG_Printf("$3");
dbg_printf("$3");
}
break;
case OS:
{
DBG_ADDR address;
get_value_inc( address.off, addr, /* offset */
ADDRESS address;
get_value_inc( address.Offset, addr, /* offset */
short_addr ? 2 : 4, FALSE );
get_value_inc( address.seg, addr, /* segment */
get_value_inc( address.Segment, addr, /* segment */
2, FALSE );
be_cpu->build_addr(dbg_curr_thread->handle, &dbg_context,
&address, address.Segment, address.Offset);
if( db_display )
{
DEBUG_PrintAddress( &address, short_addr ? MODE_16 : MODE_32, TRUE );
print_address( &address, TRUE );
}
}
@ -1805,11 +1808,4 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
}
}
}
#else /* __i386__ */
void DEBUG_Disasm( DBG_ADDR *addr, int display )
{
}
#endif /* __i386__ */

View File

@ -24,41 +24,36 @@
#include "config.h"
#include "wine/port.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include "wine/exception.h"
#include "debugger.h"
#include "expr.h"
#include "excpt.h"
static void mode_command(int);
int yylex(void);
int yyerror(const char *);
int yyerror(const char*);
%}
%union
{
DBG_VALUE value;
char * string;
int integer;
struct list_id listing;
struct expr * expression;
struct datatype* type;
struct dbg_lvalue lvalue;
char* string;
int integer;
IMAGEHLP_LINE listing;
struct expr* expression;
struct type_expr_t type;
}
%token tCONT tPASS tSTEP tLIST tNEXT tQUIT tHELP tBACKTRACE tINFO tWALK tUP tDOWN
%token tCONT tPASS tSTEP tLIST tNEXT tQUIT tHELP tBACKTRACE tINFO tUP tDOWN
%token tENABLE tDISABLE tBREAK tWATCH tDELETE tSET tMODE tPRINT tEXAM tABORT tVM86
%token tCLASS tMAPS tMODULE tSTACK tSEGMENTS tSYMBOL tREGS tWND tQUEUE tLOCAL tEXCEPTION
%token tCLASS tMAPS tSTACK tSEGMENTS tSYMBOL tREGS tWND tQUEUE tLOCAL tEXCEPTION
%token tPROCESS tTHREAD tMODREF tEOL tEOF
%token tFRAME tSHARE tCOND tDISPLAY tUNDISPLAY tDISASSEMBLE
%token tSTEPI tNEXTI tFINISH tSHOW tDIR tWHATIS tSOURCE
%token <string> tPATH
%token <string> tIDENTIFIER tSTRING tDEBUGSTR tINTVAR
%token <string> tPATH tIDENTIFIER tSTRING tDEBUGSTR tINTVAR
%token <integer> tNUM tFORMAT
%token tSYMBOLFILE tRUN tATTACH tDETACH tNOPROCESS tMAINTENANCE tTYPE
@ -84,225 +79,239 @@ int yyerror(const char *);
%left '.' '[' OP_DRF
%nonassoc ':'
%type <expression> expr lval lvalue
%type <type> type_expr
%type <value> expr_addr lval_addr
%type <integer> expr_value
%type <expression> expr lvalue
%type <lvalue> expr_lvalue lvalue_addr
%type <integer> expr_rvalue
%type <string> pathname identifier
%type <listing> list_arg
%type <type> type_expr
%%
input: line
input:
line
| input line
;
line: command { DEBUG_FreeExprMem(); }
line:
command tEOL { expr_free_all(); }
| tEOL
| tEOF { return 1; }
| error tEOL { yyerrok; DEBUG_FreeExprMem(); }
| error tEOL { yyerrok; expr_free_all(); }
;
command:
tQUIT tEOL { /*DEBUG_Quit();*/ return 1; }
| tHELP tEOL { DEBUG_Help(); }
| tHELP tINFO tEOL { DEBUG_HelpInfo(); }
| tPASS tEOL { DEBUG_WaitNextException(DBG_EXCEPTION_NOT_HANDLED, 0, 0); }
| tCONT tEOL { DEBUG_WaitNextException(DBG_CONTINUE, 1, EXEC_CONT); }
| tCONT tNUM tEOL { DEBUG_WaitNextException(DBG_CONTINUE, $2, EXEC_CONT); }
| tSTEP tEOL { DEBUG_WaitNextException(DBG_CONTINUE, 1, EXEC_STEP_INSTR); }
| tSTEP tNUM tEOL { DEBUG_WaitNextException(DBG_CONTINUE, $2, EXEC_STEP_INSTR); }
| tNEXT tEOL { DEBUG_WaitNextException(DBG_CONTINUE, 1, EXEC_STEP_OVER); }
| tNEXT tNUM tEOL { DEBUG_WaitNextException(DBG_CONTINUE, $2, EXEC_STEP_OVER); }
| tSTEPI tEOL { DEBUG_WaitNextException(DBG_CONTINUE, 1, EXEC_STEPI_INSTR); }
| tSTEPI tNUM tEOL { DEBUG_WaitNextException(DBG_CONTINUE, $2, EXEC_STEPI_INSTR); }
| tNEXTI tEOL { DEBUG_WaitNextException(DBG_CONTINUE, 1, EXEC_STEPI_OVER); }
| tNEXTI tNUM tEOL { DEBUG_WaitNextException(DBG_CONTINUE, $2, EXEC_STEPI_OVER); }
| tFINISH tEOL { DEBUG_WaitNextException(DBG_CONTINUE, 0, EXEC_FINISH); }
| tABORT tEOL { abort(); }
| tMODE tNUM tEOL { mode_command($2); }
| tMODE tVM86 tEOL { DEBUG_CurrThread->dbg_mode = MODE_VM86; }
| tBACKTRACE tEOL { DEBUG_BackTrace(DEBUG_CurrTid, TRUE); }
| tBACKTRACE tNUM tEOL { DEBUG_BackTrace($2, TRUE); }
| tUP tEOL { DEBUG_SetFrame( curr_frame + 1 ); }
| tUP tNUM tEOL { DEBUG_SetFrame( curr_frame + $2 ); }
| tDOWN tEOL { DEBUG_SetFrame( curr_frame - 1 ); }
| tDOWN tNUM tEOL { DEBUG_SetFrame( curr_frame - $2 ); }
| tFRAME tNUM tEOL { DEBUG_SetFrame( $2 ); }
| tSHOW tDIR tEOL { DEBUG_ShowDir(); }
| tDIR pathname tEOL { DEBUG_AddPath( $2 ); }
| tDIR tEOL { DEBUG_NukePath(); }
| tCOND tNUM tEOL { DEBUG_AddBPCondition($2, NULL); }
| tCOND tNUM expr tEOL { DEBUG_AddBPCondition($2, $3); }
| tSOURCE pathname tEOL { DEBUG_Parser($2); }
| tSYMBOLFILE pathname tEOL { DEBUG_ReadSymbolTable($2, 0); }
| tSYMBOLFILE pathname expr_value tEOL { DEBUG_ReadSymbolTable($2, $3); }
| tWHATIS expr_addr tEOL { DEBUG_PrintType(&$2); }
| tATTACH tNUM tEOL { DEBUG_Attach($2, FALSE, TRUE); }
| tDETACH tEOL { return DEBUG_Detach(); /* FIXME: we shouldn't return, but since we cannot simply clean the symbol table, exit debugger for now */ }
tQUIT { return 1; }
| tHELP { print_help(); }
| tHELP tINFO { info_help(); }
| tPASS { dbg_wait_next_exception(DBG_EXCEPTION_NOT_HANDLED, 0, 0); }
| tCONT { dbg_wait_next_exception(DBG_CONTINUE, 1, dbg_exec_cont); }
| tCONT tNUM { dbg_wait_next_exception(DBG_CONTINUE, $2, dbg_exec_cont); }
| tSTEP { dbg_wait_next_exception(DBG_CONTINUE, 1, dbg_exec_step_into_line); }
| tSTEP tNUM { dbg_wait_next_exception(DBG_CONTINUE, $2, dbg_exec_step_into_line); }
| tNEXT { dbg_wait_next_exception(DBG_CONTINUE, 1, dbg_exec_step_over_line); }
| tNEXT tNUM { dbg_wait_next_exception(DBG_CONTINUE, $2, dbg_exec_step_over_line); }
| tSTEPI { dbg_wait_next_exception(DBG_CONTINUE, 1, dbg_exec_step_into_insn); }
| tSTEPI tNUM { dbg_wait_next_exception(DBG_CONTINUE, $2, dbg_exec_step_into_insn); }
| tNEXTI { dbg_wait_next_exception(DBG_CONTINUE, 1, dbg_exec_step_over_insn); }
| tNEXTI tNUM { dbg_wait_next_exception(DBG_CONTINUE, $2, dbg_exec_step_over_insn); }
| tFINISH { dbg_wait_next_exception(DBG_CONTINUE, 0, dbg_exec_finish); }
| tABORT { abort(); }
| tBACKTRACE { stack_backtrace(dbg_curr_tid, TRUE); }
| tBACKTRACE tNUM { stack_backtrace($2, TRUE); }
| tUP { stack_set_frame(dbg_curr_frame + 1); }
| tUP tNUM { stack_set_frame(dbg_curr_frame + $2); }
| tDOWN { stack_set_frame(dbg_curr_frame - 1); }
| tDOWN tNUM { stack_set_frame(dbg_curr_frame - $2); }
| tFRAME tNUM { stack_set_frame($2); }
| tSHOW tDIR { source_show_path(); }
| tDIR pathname { source_add_path($2); }
| tDIR { source_nuke_path(); }
| tCOND tNUM { break_add_condition($2, NULL); }
| tCOND tNUM expr { break_add_condition($2, $3); }
| tSOURCE pathname { parser($2); }
| tSYMBOLFILE pathname { symbol_read_symtable($2, 0); }
| tSYMBOLFILE pathname expr_rvalue { symbol_read_symtable($2, $3); }
| tWHATIS expr_lvalue { types_print_type((DWORD)memory_to_linear_addr(&$2.addr), $2.typeid, FALSE); dbg_printf("\n"); }
| tATTACH tNUM { dbg_attach_debuggee($2, FALSE, TRUE); }
| tDETACH { dbg_detach_debuggee(); }
| run_command
| list_command
| disassemble_command
| set_command
| x_command
| print_command
| break_commands
| display_commands
| print_command
| break_command
| watch_command
| display_command
| info_command
| walk_command
| run_command
| maintenance_command
| noprocess_state
;
display_commands:
| tDISPLAY tEOL { DEBUG_InfoDisplay(); }
| tDISPLAY expr tEOL { DEBUG_AddDisplay($2, 1, 0, FALSE); }
| tDISPLAY tFORMAT expr tEOL{ DEBUG_AddDisplay($3, $2 >> 8, $2 & 0xff, FALSE); }
| tLOCAL tDISPLAY expr tEOL { DEBUG_AddDisplay($3, 1, 0, TRUE); }
| tLOCAL tDISPLAY tFORMAT expr tEOL { DEBUG_AddDisplay($4, $3 >> 8, $3 & 0xff, TRUE); }
| tENABLE tDISPLAY tNUM tEOL{ DEBUG_EnableDisplay( $3, TRUE ); }
| tDISABLE tDISPLAY tNUM tEOL { DEBUG_EnableDisplay( $3, FALSE ); }
| tDELETE tDISPLAY tNUM tEOL{ DEBUG_DelDisplay( $3 ); }
| tDELETE tDISPLAY tEOL { DEBUG_DelDisplay( -1 ); }
| tUNDISPLAY tNUM tEOL { DEBUG_DelDisplay( $2 ); }
| tUNDISPLAY tEOL { DEBUG_DelDisplay( -1 ); }
;
set_command:
tSET lval_addr '=' expr_value tEOL { DEBUG_WriteMemory(&$2, $4); }
| tSET '+' tIDENTIFIER tEOL { DEBUG_DbgChannel(TRUE, NULL, $3); }
| tSET '-' tIDENTIFIER tEOL { DEBUG_DbgChannel(FALSE, NULL, $3); }
| tSET tIDENTIFIER '+' tIDENTIFIER tEOL { DEBUG_DbgChannel(TRUE, $2, $4); }
| tSET tIDENTIFIER '-' tIDENTIFIER tEOL { DEBUG_DbgChannel(FALSE, $2, $4); }
;
pathname:
tIDENTIFIER { $$ = $1; }
identifier { $$ = $1; }
| tPATH { $$ = $1; }
;
disassemble_command:
tDISASSEMBLE tEOL { DEBUG_Disassemble( NULL, NULL, 10 ); }
| tDISASSEMBLE expr_addr tEOL { DEBUG_Disassemble( & $2, NULL, 10 ); }
| tDISASSEMBLE expr_addr ',' expr_addr tEOL { DEBUG_Disassemble( & $2, & $4, 0 ); }
;
list_command:
tLIST tEOL { DEBUG_List( NULL, NULL, 10 ); }
| tLIST '-' tEOL { DEBUG_List( NULL, NULL, -10 ); }
| tLIST list_arg tEOL { DEBUG_List( & $2, NULL, 10 ); }
| tLIST ',' list_arg tEOL { DEBUG_List( NULL, & $3, -10 ); }
| tLIST list_arg ',' list_arg tEOL { DEBUG_List( & $2, & $4, 0 ); }
identifier:
tIDENTIFIER { $$ = $1; }
| tIDENTIFIER '!' tIDENTIFIER { char* ptr = HeapAlloc(GetProcessHeap(), 0, strlen($1) + 1 + strlen($3) + 1);
sprintf(ptr, "%s!%s", $1, $3); $$ = lexeme_alloc(ptr);
HeapFree(GetProcessHeap(), 0, ptr); }
| identifier ':' ':' tIDENTIFIER { char* ptr = HeapAlloc(GetProcessHeap(), 0, strlen($1) + 2 + strlen($4) + 1);
sprintf(ptr, "%s::%s", $1, $4); $$ = lexeme_alloc(ptr);
HeapFree(GetProcessHeap(), 0, ptr); }
;
list_arg:
tNUM { $$.sourcefile = NULL; $$.line = $1; }
| pathname ':' tNUM { $$.sourcefile = $1; $$.line = $3; }
| tIDENTIFIER { DEBUG_GetFuncInfo( & $$, NULL, $1); }
| pathname ':' tIDENTIFIER { DEBUG_GetFuncInfo( & $$, $1, $3); }
| '*' expr_addr { DEBUG_FindNearestSymbol( & $2.addr, FALSE, NULL, 0, & $$ ); }
;
x_command:
tEXAM expr_addr tEOL { DEBUG_ExamineMemory( &$2, 1, 'x'); }
| tEXAM tFORMAT expr_addr tEOL { DEBUG_ExamineMemory( &$3, $2>>8, $2&0xff ); }
;
print_command:
tPRINT expr_addr tEOL { DEBUG_Print( &$2, 1, 0, 0 ); }
| tPRINT tFORMAT expr_addr tEOL { DEBUG_Print( &$3, $2 >> 8, $2 & 0xff, 0 ); }
;
break_commands:
tBREAK '*' expr_addr tEOL{ DEBUG_AddBreakpointFromValue( &$3 ); }
| tBREAK identifier tEOL { DEBUG_AddBreakpointFromId($2, -1); }
| tBREAK identifier ':' tNUM tEOL { DEBUG_AddBreakpointFromId($2, $4); }
| tBREAK tNUM tEOL { DEBUG_AddBreakpointFromLineno($2); }
| tBREAK tEOL { DEBUG_AddBreakpointFromLineno(-1); }
| tENABLE tNUM tEOL { DEBUG_EnableBreakpoint( $2, TRUE ); }
| tENABLE tBREAK tNUM tEOL { DEBUG_EnableBreakpoint( $3, TRUE ); }
| tDISABLE tNUM tEOL { DEBUG_EnableBreakpoint( $2, FALSE ); }
| tDISABLE tBREAK tNUM tEOL { DEBUG_EnableBreakpoint( $3, FALSE ); }
| tDELETE tNUM tEOL { DEBUG_DelBreakpoint( $2 ); }
| tDELETE tBREAK tNUM tEOL { DEBUG_DelBreakpoint( $3 ); }
;
watch_command:
tWATCH '*' expr_addr tEOL { DEBUG_AddWatchpoint( &$3, 1 ); }
| tWATCH identifier tEOL { DEBUG_AddWatchpointFromId($2); }
;
info_command:
tINFO tBREAK tEOL { DEBUG_InfoBreakpoints(); }
| tINFO tCLASS tSTRING tEOL { DEBUG_InfoClass( $3 ); }
| tINFO tSHARE tEOL { DEBUG_InfoShare(); }
| tINFO tMODULE expr_value tEOL { DEBUG_DumpModule( $3 ); }
| tINFO tREGS tEOL { DEBUG_InfoRegisters(&DEBUG_context); }
| tINFO tSEGMENTS expr_value tEOL { DEBUG_InfoSegments( $3, 1 ); }
| tINFO tSEGMENTS tEOL { DEBUG_InfoSegments( 0, -1 ); }
| tINFO tSTACK tEOL { DEBUG_InfoStack(); }
| tINFO tSYMBOL tSTRING tEOL{ DEBUG_InfoSymbols($3); }
| tINFO tWND expr_value tEOL{ DEBUG_InfoWindow( (HWND)$3 ); }
| tINFO tLOCAL tEOL { DEBUG_InfoLocals(); }
| tINFO tDISPLAY tEOL { DEBUG_InfoDisplay(); }
;
walk_command:
tWALK tCLASS tEOL { DEBUG_WalkClasses(); }
| tWALK tMODULE tEOL { DEBUG_WalkModules(); }
| tWALK tWND tEOL { DEBUG_WalkWindows( 0, 0 ); }
| tWALK tWND expr_value tEOL{ DEBUG_WalkWindows( (HWND)$3, 0 ); }
| tWALK tMAPS tEOL { DEBUG_InfoVirtual(0); }
| tWALK tMAPS expr_value tEOL { DEBUG_InfoVirtual($3); }
| tWALK tPROCESS tEOL { DEBUG_WalkProcess(); }
| tWALK tTHREAD tEOL { DEBUG_WalkThreads(); }
| tWALK tEXCEPTION tEOL { DEBUG_WalkExceptions(DEBUG_CurrTid); }
| tWALK tEXCEPTION expr_value tEOL{ DEBUG_WalkExceptions($3); }
tNUM { $$.FileName = NULL; $$.LineNumber = $1; }
| pathname ':' tNUM { $$.FileName = $1; $$.LineNumber = $3; }
| identifier { symbol_get_line(NULL, $1, &$$); }
| pathname ':' identifier { symbol_get_line($3, $1, &$$); }
| '*' expr_lvalue { $$.SizeOfStruct = sizeof($$);
SymGetLineFromAddr(dbg_curr_process->handle, (unsigned long)memory_to_linear_addr(& $2.addr), NULL, & $$); }
;
run_command:
tRUN tEOL { DEBUG_Run(NULL); }
| tRUN tSTRING tEOL { DEBUG_Run($2); }
tRUN { dbg_run_debuggee(NULL); }
| tRUN tSTRING { dbg_run_debuggee($2); }
;
list_command:
tLIST { source_list(NULL, NULL, 10); }
| tLIST '-' { source_list(NULL, NULL, -10); }
| tLIST list_arg { source_list(& $2, NULL, 10); }
| tLIST ',' list_arg { source_list(NULL, & $3, -10); }
| tLIST list_arg ',' list_arg { source_list(& $2, & $4, 0); }
;
disassemble_command:
tDISASSEMBLE { memory_disassemble(NULL, NULL, 10); }
| tDISASSEMBLE expr_lvalue { memory_disassemble(&$2, NULL, 10); }
| tDISASSEMBLE expr_lvalue ',' expr_lvalue { memory_disassemble(&$2, &$4, 0); }
;
set_command:
tSET lvalue_addr '=' expr_rvalue { memory_write_value(&$2, sizeof(int), &$4); }
| tSET '+' tIDENTIFIER { info_wine_dbg_channel(TRUE, NULL, $3); }
| tSET '-' tIDENTIFIER { info_wine_dbg_channel(FALSE, NULL, $3); }
| tSET tIDENTIFIER '+' tIDENTIFIER { info_wine_dbg_channel(TRUE, $2, $4); }
| tSET tIDENTIFIER '-' tIDENTIFIER { info_wine_dbg_channel(FALSE, $2, $4); }
;
x_command:
tEXAM expr_lvalue { memory_examine(&$2, 1, 'x'); }
| tEXAM tFORMAT expr_lvalue { memory_examine(&$3, $2 >> 8, $2 & 0xff); }
;
print_command:
tPRINT expr_lvalue { print_value(&$2, 0, 0); }
| tPRINT tFORMAT expr_lvalue { if (($2 >> 8) == 1) print_value(&$3, $2 & 0xff, 0); else dbg_printf("Count is meaningless in print command\n"); }
;
break_command:
tBREAK '*' expr_lvalue { break_add_break_from_lvalue(&$3); }
| tBREAK identifier { break_add_break_from_id($2, -1); }
| tBREAK identifier ':' tNUM { break_add_break_from_id($2, $4); }
| tBREAK tNUM { break_add_break_from_lineno($2); }
| tBREAK { break_add_break_from_lineno(-1); }
| tENABLE tNUM { break_enable_xpoint($2, TRUE); }
| tENABLE tBREAK tNUM { break_enable_xpoint($3, TRUE); }
| tDISABLE tNUM { break_enable_xpoint($2, FALSE); }
| tDISABLE tBREAK tNUM { break_enable_xpoint($3, FALSE); }
| tDELETE tNUM { break_delete_xpoint($2); }
| tDELETE tBREAK tNUM { break_delete_xpoint($3); }
;
watch_command:
tWATCH '*' expr_lvalue { break_add_watch(&$3, 1); }
| tWATCH identifier { break_add_watch_from_id($2); }
;
display_command:
tDISPLAY { display_info(); }
| tDISPLAY expr { display_add($2, 1, 0, FALSE); }
| tDISPLAY tFORMAT expr { display_add($3, $2 >> 8, $2 & 0xff, FALSE); }
| tLOCAL tDISPLAY expr { display_add($3, 1, 0, TRUE); }
| tLOCAL tDISPLAY tFORMAT expr { display_add($4, $3 >> 8, $3 & 0xff, TRUE); }
| tENABLE tDISPLAY tNUM { display_enable($3, TRUE); }
| tDISABLE tDISPLAY tNUM { display_enable($3, FALSE); }
| tDELETE tDISPLAY tNUM { display_delete($3); }
| tDELETE tDISPLAY { display_delete(-1); }
| tUNDISPLAY tNUM { display_delete($2); }
| tUNDISPLAY { display_delete(-1); }
;
info_command:
tINFO tBREAK { break_info(); }
| tINFO tSHARE { info_win32_module(0); }
| tINFO tSHARE expr_rvalue { info_win32_module($3); }
| tINFO tREGS { be_cpu->print_context(dbg_curr_thread->handle, &dbg_context); }
| tINFO tSEGMENTS expr_rvalue { info_win32_segments($3, 1); }
| tINFO tSEGMENTS { info_win32_segments(0, -1); }
| tINFO tSTACK { stack_info(); }
| tINFO tSYMBOL tSTRING { symbol_info($3); }
| tINFO tLOCAL { symbol_info_locals(); }
| tINFO tDISPLAY { display_info(); }
| tINFO tCLASS { info_win32_class(NULL, NULL); }
| tINFO tCLASS tSTRING { info_win32_class(NULL, $3); }
| tINFO tWND { info_win32_window(NULL, FALSE); }
| tINFO tWND expr_rvalue { info_win32_window((HWND)$3, FALSE); }
| tINFO '*' tWND { info_win32_window(NULL, TRUE); }
| tINFO '*' tWND expr_rvalue { info_win32_window((HWND)$4, TRUE); }
| tINFO tPROCESS { info_win32_processes(); }
| tINFO tTHREAD { info_win32_threads(); }
| tINFO tEXCEPTION { info_win32_exceptions(dbg_curr_tid); }
| tINFO tEXCEPTION expr_rvalue { info_win32_exceptions($3); }
| tINFO tMAPS { info_win32_virtual(dbg_curr_pid); }
| tINFO tMAPS expr_rvalue { info_win32_virtual($3); }
;
maintenance_command:
tMAINTENANCE tTYPE { DEBUG_DumpTypes(); }
tMAINTENANCE tTYPE { print_types(); }
;
noprocess_state:
tNOPROCESS tEOL {} /* <CR> shall not barf anything */
| tNOPROCESS tSTRING tEOL { DEBUG_Printf("No process loaded, cannot execute '%s'\n", $2); }
tNOPROCESS {} /* <CR> shall not barf anything */
| tNOPROCESS tSTRING { dbg_printf("No process loaded, cannot execute '%s'\n", $2); }
;
type_expr:
type_expr '*' { $$ = $1 ? DEBUG_FindOrMakePointerType($1) : NULL; }
| tINT { $$ = DEBUG_GetBasicType(DT_BASIC_INT); }
| tCHAR { $$ = DEBUG_GetBasicType(DT_BASIC_CHAR); }
| tLONG tINT { $$ = DEBUG_GetBasicType(DT_BASIC_LONGINT); }
| tUNSIGNED tINT { $$ = DEBUG_GetBasicType(DT_BASIC_UINT); }
| tLONG tUNSIGNED tINT { $$ = DEBUG_GetBasicType(DT_BASIC_ULONGINT); }
| tLONG tLONG tINT { $$ = DEBUG_GetBasicType(DT_BASIC_LONGLONGINT); }
| tLONG tLONG tUNSIGNED tINT{ $$ = DEBUG_GetBasicType(DT_BASIC_ULONGLONGINT); }
| tSHORT tINT { $$ = DEBUG_GetBasicType(DT_BASIC_SHORTINT); }
| tSHORT tUNSIGNED tINT { $$ = DEBUG_GetBasicType(DT_BASIC_USHORTINT); }
| tSIGNED tCHAR { $$ = DEBUG_GetBasicType(DT_BASIC_SCHAR); }
| tUNSIGNED tCHAR { $$ = DEBUG_GetBasicType(DT_BASIC_UCHAR); }
| tFLOAT { $$ = DEBUG_GetBasicType(DT_BASIC_FLOAT); }
| tDOUBLE { $$ = DEBUG_GetBasicType(DT_BASIC_DOUBLE); }
| tLONG tDOUBLE { $$ = DEBUG_GetBasicType(DT_BASIC_LONGDOUBLE); }
| tSTRUCT tIDENTIFIER { $$ = DEBUG_TypeCast(DT_STRUCT, $2); }
| tUNION tIDENTIFIER { $$ = DEBUG_TypeCast(DT_STRUCT, $2); }
| tENUM tIDENTIFIER { $$ = DEBUG_TypeCast(DT_ENUM, $2); }
tCHAR { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_char; }
| tINT { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_signed_int; }
| tLONG tINT { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_signed_long_int; }
| tLONG { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_signed_long_int; }
| tUNSIGNED tINT { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_unsigned_int; }
| tUNSIGNED { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_unsigned_int; }
| tLONG tUNSIGNED tINT { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_unsigned_long_int; }
| tLONG tUNSIGNED { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_unsigned_long_int; }
| tSHORT tINT { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_signed_short_int; }
| tSHORT { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_signed_short_int; }
| tSHORT tUNSIGNED tINT { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_unsigned_short_int; }
| tSHORT tUNSIGNED { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_unsigned_short_int; }
| tSIGNED tCHAR { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_signed_char_int; }
| tUNSIGNED tCHAR { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_unsigned_char_int; }
| tLONG tLONG tUNSIGNED tINT{ $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_unsigned_longlong_int; }
| tLONG tLONG tUNSIGNED { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_unsigned_longlong_int; }
| tLONG tLONG tINT { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_signed_longlong_int; }
| tLONG tLONG { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_signed_longlong_int; }
| tFLOAT { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_short_real; }
| tDOUBLE { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_real; }
| tLONG tDOUBLE { $$.type = type_expr_type_id; $$.deref_count = 0; $$.u.typeid = dbg_itype_long_real; }
| type_expr '*' { $$ = $1; $$.deref_count++; }
| tCLASS identifier { $$.type = type_expr_udt_class; $$.deref_count = 0; $$.u.name = lexeme_alloc($2); }
| tSTRUCT identifier { $$.type = type_expr_udt_struct; $$.deref_count = 0; $$.u.name = lexeme_alloc($2); }
| tUNION identifier { $$.type = type_expr_udt_union; $$.deref_count = 0; $$.u.name = lexeme_alloc($2); }
| tENUM identifier { $$.type = type_expr_enumeration; $$.deref_count = 0; $$.u.name = lexeme_alloc($2); }
;
expr_addr: expr { $$ = DEBUG_EvalExpr($1); }
expr_lvalue:
expr { $$ = expr_eval($1); }
;
expr_value: expr { DBG_VALUE value = DEBUG_EvalExpr($1);
/* expr_value is typed as an integer */
$$ = DEBUG_ReadMemory(&value); }
expr_rvalue:
expr_lvalue { $$ = types_extract_as_integer(&$1); }
;
/*
@ -312,149 +321,209 @@ expr_value: expr { DBG_VALUE value = DEBUG_EvalExpr($1);
* use in 'display' commands, and in conditional watchpoints.
*/
expr:
tNUM { $$ = DEBUG_ConstExpr($1); }
| tSTRING { $$ = DEBUG_StringExpr($1); }
| tINTVAR { $$ = DEBUG_IntVarExpr($1); }
| tIDENTIFIER { $$ = DEBUG_SymbolExpr($1); }
| expr OP_DRF tIDENTIFIER { $$ = DEBUG_StructPExpr($1, $3); }
| expr '.' tIDENTIFIER { $$ = DEBUG_StructExpr($1, $3); }
| tIDENTIFIER '(' ')' { $$ = DEBUG_CallExpr($1, 0); }
| tIDENTIFIER '(' expr ')' { $$ = DEBUG_CallExpr($1, 1, $3); }
| tIDENTIFIER '(' expr ',' expr ')' { $$ = DEBUG_CallExpr($1, 2, $3, $5); }
| tIDENTIFIER '(' expr ',' expr ',' expr ')' { $$ = DEBUG_CallExpr($1, 3, $3, $5, $7); }
| tIDENTIFIER '(' expr ',' expr ',' expr ',' expr ')' { $$ = DEBUG_CallExpr($1, 4, $3, $5, $7, $9); }
| tIDENTIFIER '(' expr ',' expr ',' expr ',' expr ',' expr ')' { $$ = DEBUG_CallExpr($1, 5, $3, $5, $7, $9, $11); }
| expr '[' expr ']' { $$ = DEBUG_BinopExpr(EXP_OP_ARR, $1, $3); }
| expr ':' expr { $$ = DEBUG_BinopExpr(EXP_OP_SEG, $1, $3); }
| expr OP_LOR expr { $$ = DEBUG_BinopExpr(EXP_OP_LOR, $1, $3); }
| expr OP_LAND expr { $$ = DEBUG_BinopExpr(EXP_OP_LAND, $1, $3); }
| expr '|' expr { $$ = DEBUG_BinopExpr(EXP_OP_OR, $1, $3); }
| expr '&' expr { $$ = DEBUG_BinopExpr(EXP_OP_AND, $1, $3); }
| expr '^' expr { $$ = DEBUG_BinopExpr(EXP_OP_XOR, $1, $3); }
| expr OP_EQ expr { $$ = DEBUG_BinopExpr(EXP_OP_EQ, $1, $3); }
| expr '>' expr { $$ = DEBUG_BinopExpr(EXP_OP_GT, $1, $3); }
| expr '<' expr { $$ = DEBUG_BinopExpr(EXP_OP_LT, $1, $3); }
| expr OP_GE expr { $$ = DEBUG_BinopExpr(EXP_OP_GE, $1, $3); }
| expr OP_LE expr { $$ = DEBUG_BinopExpr(EXP_OP_LE, $1, $3); }
| expr OP_NE expr { $$ = DEBUG_BinopExpr(EXP_OP_NE, $1, $3); }
| expr OP_SHL expr { $$ = DEBUG_BinopExpr(EXP_OP_SHL, $1, $3); }
| expr OP_SHR expr { $$ = DEBUG_BinopExpr(EXP_OP_SHR, $1, $3); }
| expr '+' expr { $$ = DEBUG_BinopExpr(EXP_OP_ADD, $1, $3); }
| expr '-' expr { $$ = DEBUG_BinopExpr(EXP_OP_SUB, $1, $3); }
| expr '*' expr { $$ = DEBUG_BinopExpr(EXP_OP_MUL, $1, $3); }
| expr '/' expr { $$ = DEBUG_BinopExpr(EXP_OP_DIV, $1, $3); }
| expr '%' expr { $$ = DEBUG_BinopExpr(EXP_OP_REM, $1, $3); }
| '-' expr %prec OP_SIGN { $$ = DEBUG_UnopExpr(EXP_OP_NEG, $2); }
tNUM { $$ = expr_alloc_sconstant($1); }
| tSTRING { $$ = expr_alloc_string($1); }
| tINTVAR { $$ = expr_alloc_internal_var($1); }
| identifier { $$ = expr_alloc_symbol($1); }
| expr OP_DRF tIDENTIFIER { $$ = expr_alloc_pstruct($1, $3); }
| expr '.' tIDENTIFIER { $$ = expr_alloc_struct($1, $3); }
| identifier '(' ')' { $$ = expr_alloc_func_call($1, 0); }
| identifier '(' expr ')' { $$ = expr_alloc_func_call($1, 1, $3); }
| identifier '(' expr ',' expr ')' { $$ = expr_alloc_func_call($1, 2, $3, $5); }
| identifier '(' expr ',' expr ',' expr ')' { $$ = expr_alloc_func_call($1, 3, $3, $5, $7); }
| identifier '(' expr ',' expr ',' expr ',' expr ')' { $$ = expr_alloc_func_call($1, 4, $3, $5, $7, $9); }
| identifier '(' expr ',' expr ',' expr ',' expr ',' expr ')' { $$ = expr_alloc_func_call($1, 5, $3, $5, $7, $9, $11); }
| expr '[' expr ']' { $$ = expr_alloc_binary_op(EXP_OP_ARR, $1, $3); }
| expr ':' expr { $$ = expr_alloc_binary_op(EXP_OP_SEG, $1, $3); }
| expr OP_LOR expr { $$ = expr_alloc_binary_op(EXP_OP_LOR, $1, $3); }
| expr OP_LAND expr { $$ = expr_alloc_binary_op(EXP_OP_LAND, $1, $3); }
| expr '|' expr { $$ = expr_alloc_binary_op(EXP_OP_OR, $1, $3); }
| expr '&' expr { $$ = expr_alloc_binary_op(EXP_OP_AND, $1, $3); }
| expr '^' expr { $$ = expr_alloc_binary_op(EXP_OP_XOR, $1, $3); }
| expr OP_EQ expr { $$ = expr_alloc_binary_op(EXP_OP_EQ, $1, $3); }
| expr '>' expr { $$ = expr_alloc_binary_op(EXP_OP_GT, $1, $3); }
| expr '<' expr { $$ = expr_alloc_binary_op(EXP_OP_LT, $1, $3); }
| expr OP_GE expr { $$ = expr_alloc_binary_op(EXP_OP_GE, $1, $3); }
| expr OP_LE expr { $$ = expr_alloc_binary_op(EXP_OP_LE, $1, $3); }
| expr OP_NE expr { $$ = expr_alloc_binary_op(EXP_OP_NE, $1, $3); }
| expr OP_SHL expr { $$ = expr_alloc_binary_op(EXP_OP_SHL, $1, $3); }
| expr OP_SHR expr { $$ = expr_alloc_binary_op(EXP_OP_SHR, $1, $3); }
| expr '+' expr { $$ = expr_alloc_binary_op(EXP_OP_ADD, $1, $3); }
| expr '-' expr { $$ = expr_alloc_binary_op(EXP_OP_SUB, $1, $3); }
| expr '*' expr { $$ = expr_alloc_binary_op(EXP_OP_MUL, $1, $3); }
| expr '/' expr { $$ = expr_alloc_binary_op(EXP_OP_DIV, $1, $3); }
| expr '%' expr { $$ = expr_alloc_binary_op(EXP_OP_REM, $1, $3); }
| '-' expr %prec OP_SIGN { $$ = expr_alloc_unary_op(EXP_OP_NEG, $2); }
| '+' expr %prec OP_SIGN { $$ = $2; }
| '!' expr { $$ = DEBUG_UnopExpr(EXP_OP_NOT, $2); }
| '~' expr { $$ = DEBUG_UnopExpr(EXP_OP_LNOT, $2); }
| '!' expr { $$ = expr_alloc_unary_op(EXP_OP_NOT, $2); }
| '~' expr { $$ = expr_alloc_unary_op(EXP_OP_LNOT, $2); }
| '(' expr ')' { $$ = $2; }
| '*' expr %prec OP_DEREF { $$ = DEBUG_UnopExpr(EXP_OP_DEREF, $2); }
| '&' expr %prec OP_DEREF { $$ = DEBUG_UnopExpr(EXP_OP_ADDR, $2); }
| '(' type_expr ')' expr %prec OP_DEREF { $$ = DEBUG_TypeCastExpr($2, $4); }
| '*' expr %prec OP_DEREF { $$ = expr_alloc_unary_op(EXP_OP_DEREF, $2); }
| '&' expr %prec OP_DEREF { $$ = expr_alloc_unary_op(EXP_OP_ADDR, $2); }
| '(' type_expr ')' expr %prec OP_DEREF { $$ = expr_alloc_typecast(&$2, $4); }
;
/*
* The lvalue rule builds an expression tree. This is a limited form
* of expression that is suitable to be used as an lvalue.
*/
lval_addr: lval { $$ = DEBUG_EvalExpr($1); }
lvalue_addr:
lvalue { $$ = expr_eval($1); }
;
lval: lvalue { $$ = $1; }
| '*' expr { $$ = DEBUG_UnopExpr(EXP_OP_FORCE_DEREF, $2); }
;
lvalue: tNUM { $$ = DEBUG_ConstExpr($1); }
| tINTVAR { $$ = DEBUG_IntVarExpr($1); }
| tIDENTIFIER { $$ = DEBUG_SymbolExpr($1); }
| lvalue OP_DRF tIDENTIFIER { $$ = DEBUG_StructPExpr($1, $3); }
| lvalue '.' tIDENTIFIER { $$ = DEBUG_StructExpr($1, $3); }
| lvalue '[' expr ']' { $$ = DEBUG_BinopExpr(EXP_OP_ARR, $1, $3); }
;
identifier: tIDENTIFIER { $$ = $1; }
| identifier '.' tIDENTIFIER { char* ptr = DBG_alloc(strlen($1) + 1 + strlen($3)+ 1);
sprintf(ptr, "%s.%s", $1, $3); $$ = DEBUG_MakeSymbol(ptr);
DBG_free(ptr); }
| identifier ':' ':' tIDENTIFIER { char* ptr = DBG_alloc(strlen($1) + 2 + strlen($4) + 1);
sprintf(ptr, "%s::%s", $1, $4); $$ = DEBUG_MakeSymbol(ptr);
DBG_free(ptr); }
lvalue: tNUM { $$ = expr_alloc_sconstant($1); }
| tINTVAR { $$ = expr_alloc_internal_var($1); }
| identifier { $$ = expr_alloc_symbol($1); }
| lvalue OP_DRF tIDENTIFIER { $$ = expr_alloc_pstruct($1, $3); }
| lvalue '.' tIDENTIFIER { $$ = expr_alloc_struct($1, $3); }
| lvalue '[' expr ']' { $$ = expr_alloc_binary_op(EXP_OP_ARR, $1, $3); }
| '*' expr { $$ = expr_alloc_unary_op(EXP_OP_FORCE_DEREF, $2); }
;
%%
static void mode_command(int newmode)
{
switch(newmode)
{
case 16: DEBUG_CurrThread->dbg_mode = MODE_16; break;
case 32: DEBUG_CurrThread->dbg_mode = MODE_32; break;
default: DEBUG_Printf("Invalid mode (use 16, 32 or vm86)\n");
}
}
void DEBUG_Exit(DWORD ec)
{
ExitProcess(ec);
}
static WINE_EXCEPTION_FILTER(wine_dbg_cmd)
{
if (DBG_IVAR(ExtDbgOnInternalException))
DEBUG_ExternalDebugger();
DEBUG_Printf("\nwine_dbg_cmd: ");
switch (GetExceptionCode()) {
switch (GetExceptionCode())
{
case DEBUG_STATUS_INTERNAL_ERROR:
DEBUG_Printf("WineDbg internal error\n");
if (DBG_IVAR(ExtDbgOnInternalException))
DEBUG_ExternalDebugger();
dbg_printf("\nWineDbg internal error\n");
break;
case DEBUG_STATUS_NO_SYMBOL:
DEBUG_Printf("Undefined symbol\n");
dbg_printf("\nUndefined symbol\n");
break;
case DEBUG_STATUS_DIV_BY_ZERO:
DEBUG_Printf("Division by zero\n");
dbg_printf("\nDivision by zero\n");
break;
case DEBUG_STATUS_BAD_TYPE:
DEBUG_Printf("No type or type mismatch\n");
dbg_printf("\nNo type or type mismatch\n");
break;
case DEBUG_STATUS_NO_FIELD:
DEBUG_Printf("No such field in structure or union\n");
dbg_printf("\nNo such field in structure or union\n");
break;
case DEBUG_STATUS_CANT_DEREF:
dbg_printf("\nDereference failed (not a pointer, or out of array bounds)\n");
break;
case DEBUG_STATUS_ABORT:
break;
case DEBUG_STATUS_NOT_AN_INTEGER:
dbg_printf("\nNeeding an integral value\n");
break;
case CONTROL_C_EXIT:
/* this is generally sent by a ctrl-c when we run winedbg outside of wineconsole */
DEBUG_Printf("Ctrl-C\n");
/* stop the debuggee, and continue debugger execution, we will be reintered by the
dbg_printf("\nCtrl-C\n");
/* stop the debuggee, and continue debugger execution, we will be reentered by the
* debug events generated by stopping
*/
DEBUG_InterruptDebuggee();
dbg_interrupt_debuggee();
return EXCEPTION_CONTINUE_EXECUTION;
default:
DEBUG_Printf("Exception %lx\n", GetExceptionCode());
DEBUG_ExternalDebugger();
dbg_printf("\nException %lx\n", GetExceptionCode());
break;
}
return EXCEPTION_EXECUTE_HANDLER;
}
static void set_default_channels(void)
#ifndef whitespace
#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
#endif
/* Strip whitespace from the start and end of STRING. */
static void stripwhite(char *string)
{
DEBUG_hParserOutput = GetStdHandle(STD_OUTPUT_HANDLE);
DEBUG_hParserInput = GetStdHandle(STD_INPUT_HANDLE);
int i, last;
for (i = 0; whitespace(string[i]); i++);
if (i) strcpy(string, string + i);
last = i = strlen(string) - 1;
if (string[last] == '\n') i--;
while (i > 0 && whitespace(string[i])) i--;
if (string[last] == '\n')
string[++i] = '\n';
string[++i] = '\0';
}
static HANDLE dbg_parser_input;
static HANDLE dbg_parser_output;
int input_fetch_entire_line(const char* pfx, char** line, size_t* alloc, BOOL check_nl)
{
char buf_line[256];
DWORD nread;
size_t len;
/* as of today, console handles can be file handles... so better use file APIs rather than
* console's
*/
WriteFile(dbg_parser_output, pfx, strlen(pfx), NULL, NULL);
len = 0;
do
{
if (!ReadFile(dbg_parser_input, buf_line, sizeof(buf_line) - 1, &nread, NULL) || nread == 0)
break;
buf_line[nread] = '\0';
if (check_nl && len == 0 && nread == 1 && buf_line[0] == '\n')
return 0;
/* store stuff at the end of last_line */
if (len + nread + 1 > *alloc)
{
while (len + nread + 1 > *alloc) *alloc *= 2;
*line = dbg_heap_realloc(*line, *alloc);
}
strcpy(*line + len, buf_line);
len += nread;
} while (nread == 0 || buf_line[nread - 1] != '\n');
if (!len)
{
*line = HeapReAlloc(GetProcessHeap(), 0, *line, *alloc = 1);
**line = '\0';
}
/* Remove leading and trailing whitespace from the line */
stripwhite(*line);
return 1;
}
int input_read_line(const char* pfx, char* buf, int size)
{
char* line = NULL;
size_t len = 0;
/* first alloc of our current buffer */
line = HeapAlloc(GetProcessHeap(), 0, len = 2);
assert(line);
line[0] = '\n';
line[1] = '\0';
input_fetch_entire_line(pfx, &line, &len, FALSE);
len = strlen(line);
/* remove trailing \n */
if (len > 0 && line[len - 1] == '\n') len--;
len = min(size - 1, len);
memcpy(buf, line, len);
buf[len] = '\0';
HeapFree(GetProcessHeap(), 0, line);
return 1;
}
/***********************************************************************
* DEBUG_Parser
* parser
*
* Debugger command line parser
*/
void DEBUG_Parser(LPCSTR filename)
void parser(const char* filename)
{
BOOL ret_ok;
HANDLE in_copy = dbg_parser_input;
HANDLE out_copy = dbg_parser_output;
#ifdef YYDEBUG
yydebug = 0;
#endif
@ -463,16 +532,16 @@ void DEBUG_Parser(LPCSTR filename)
if (filename)
{
DEBUG_hParserOutput = 0;
DEBUG_hParserInput = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0L, 0);
if (DEBUG_hParserInput == INVALID_HANDLE_VALUE)
{
set_default_channels();
return;
}
HANDLE h = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0L, 0);
if (h == INVALID_HANDLE_VALUE) return;
dbg_parser_output = 0;
dbg_parser_input = h;
}
else
set_default_channels();
{
dbg_parser_output = GetStdHandle(STD_OUTPUT_HANDLE);
dbg_parser_input = GetStdHandle(STD_INPUT_HANDLE);
}
do
{
@ -486,16 +555,16 @@ void DEBUG_Parser(LPCSTR filename)
ret_ok = FALSE;
}
__ENDTRY;
DEBUG_FlushSymbols();
lexeme_flush();
} while (!ret_ok);
if (filename)
CloseHandle(DEBUG_hParserInput);
set_default_channels();
if (filename) CloseHandle(dbg_parser_input);
dbg_parser_input = in_copy;
dbg_parser_output = out_copy;
}
int yyerror(const char* s)
{
DEBUG_Printf("%s\n", s);
return 0;
dbg_printf("%s\n", s);
return 0;
}

View File

@ -24,22 +24,46 @@
#include <string.h>
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "wincon.h"
#include "debugger.h"
#include "y.tab.h"
#undef YY_INPUT
HANDLE DEBUG_hParserInput;
HANDLE DEBUG_hParserOutput;
static int read_input(const char* pfx, char* buf, int size)
{
size_t len;
static char* last_line = NULL;
static size_t last_line_size = 0;
static size_t last_line_idx = 0;
static int DEBUG_FetchFromLine(const char* pfx, char* buf, int size);
/* first alloc of our current buffer */
if (!last_line)
{
last_line = HeapAlloc(GetProcessHeap(), 0, last_line_size = 2);
assert(last_line);
last_line[0] = '\n';
last_line[1] = '\0';
}
/* try first to fetch the remaining of an existing line */
if (last_line_idx == 0)
{
/* no remaining chars to be read from last line, grab a brand new line up to '\n' */
lexeme_flush();
input_fetch_entire_line(pfx, &last_line, &last_line_size, TRUE);
}
len = min(strlen(last_line + last_line_idx), size - 1);
memcpy(buf, last_line + last_line_idx, len);
buf[len] = '\0';
if ((last_line_idx += len) >= strlen(last_line))
last_line_idx = 0;
return len;
}
#define YY_INPUT(buf,result,max_size) \
if ( (result = DEBUG_FetchFromLine("Wine-dbg>", buf, max_size)) < 0 ) \
YY_FATAL_ERROR( "FetchFromLine() in flex scanner failed" );
if ((result = read_input("Wine-dbg>", buf, max_size)) < 0) \
YY_FATAL_ERROR("read_input in flex scanner failed");
#define YY_NO_UNPUT
@ -59,7 +83,6 @@ STRING \"[^\n"]+\"
%s HELP_CMD
%s BD_CMD
%s LOCAL_CMD
%s WALK_CMD
%s SHOW_CMD
%s MODE_CMD
%s MAINT_CMD
@ -69,7 +92,7 @@ STRING \"[^\n"]+\"
%x NOPROCESS
%%
/* set to special state when no process is loaded. */
if (!DEBUG_CurrProcess && YYSTATE == INITIAL) {BEGIN(NOPROCESS);}
if (!dbg_curr_process && YYSTATE == INITIAL) {BEGIN(NOPROCESS);}
<<EOF>> { return tEOF; }
<*>\n { BEGIN(INITIAL); syntax_error = 0; return tEOL; }
@ -92,17 +115,17 @@ STRING \"[^\n"]+\"
{DIGIT}+ { sscanf(yytext, "%d", &yylval.integer); return tNUM; }
<FORMAT_EXPECTED>"/"{DIGIT}+{FORMAT} { char* last;
yylval.integer = strtol( yytext+1, &last, 0 ) << 8;
yylval.integer = strtol(yytext+1, &last, 0) << 8;
yylval.integer |= *last;
return tFORMAT; }
<FORMAT_EXPECTED>"/"{FORMAT} { yylval.integer = (1 << 8) | yytext[1]; return tFORMAT; }
{STRING} { yylval.string = DEBUG_MakeSymbol(yytext); return tSTRING; }
{STRING} { yylval.string = lexeme_alloc(yytext); return tSTRING; }
<ASTRING_EXPECTED>[^\n]+ { char* p = yytext; while (*p == ' ' || *p == '\t') p++;
yylval.string = DEBUG_MakeSymbol(p); return tSTRING; }
yylval.string = lexeme_alloc(p); return tSTRING; }
<INITIAL>info|inf|in { BEGIN(INFO_CMD); return tINFO; }
<INITIAL,NOPROCESS>info|inf|in { BEGIN(INFO_CMD); return tINFO; }
<INITIAL>up { BEGIN(NOCMD); return tUP; }
<INITIAL>down|dow|do { BEGIN(NOCMD); return tDOWN; }
<INITIAL>frame|fram|fra|fr { BEGIN(NOCMD); return tFRAME; }
@ -117,9 +140,8 @@ STRING \"[^\n"]+\"
<INITIAL>delete|delet|dele|del { BEGIN(BD_CMD); return tDELETE; }
<INITIAL,NOPROCESS>quit|qui|qu|q { BEGIN(NOCMD); return tQUIT; }
<INITIAL>set|se { BEGIN(NOCMD); return tSET; }
<INITIAL,NOPROCESS>walk|w { BEGIN(WALK_CMD); return tWALK; }
<INITIAL>x { BEGIN(FORMAT_EXPECTED); return tEXAM; }
<INITIAL,NOPROCESS>help|hel|he|"?" { BEGIN(HELP_CMD); return tHELP; }
<INITIAL,NOPROCESS>help|hel|he|"?" { BEGIN(HELP_CMD); return tHELP; }
<INITIAL>backtrace|backtrac|backtra|backt|back|bac|ba|bt { BEGIN(NOCMD); return tBACKTRACE; }
<INITIAL>where|wher|whe { BEGIN(NOCMD); return tBACKTRACE; }
@ -150,17 +172,16 @@ STRING \"[^\n"]+\"
<NOPROCESS>attach|attac|atta|att { BEGIN(NOCMD); return tATTACH; }
<INFO_CMD>share|shar|sha { return tSHARE; }
<INFO_CMD>locals|local|loca|loc { return tLOCAL; }
<INFO_CMD,WALK_CMD>class|clas|cla { return tCLASS; }
<INFO_CMD,WALK_CMD>module|modul|modu|mod { return tMODULE; }
<INFO_CMD,WALK_CMD>process|proces|proce|proc { return tPROCESS; }
<INFO_CMD,WALK_CMD>threads|thread|threa|thre|thr|th { return tTHREAD; }
<WALK_CMD>exception|except|exc|ex { return tEXCEPTION; }
<INFO_CMD>class|clas|cla { return tCLASS; }
<INFO_CMD>process|proces|proce|proc { return tPROCESS; }
<INFO_CMD>threads|thread|threa|thre|thr|th { return tTHREAD; }
<INFO_CMD>exception|except|exc|ex { return tEXCEPTION; }
<INFO_CMD>registers|regs|reg|re { return tREGS; }
<INFO_CMD>segments|segment|segm|seg|se { return tSEGMENTS; }
<INFO_CMD>stack|stac|sta|st { return tSTACK; }
<INFO_CMD>symbol|symbo|symb|sym { BEGIN(ASTRING_EXPECTED); return tSYMBOL; }
<WALK_CMD>maps|map { return tMAPS; }
<INFO_CMD,WALK_CMD>window|windo|wind|win|wnd { return tWND; }
<INFO_CMD>maps|map { return tMAPS; }
<INFO_CMD>window|windo|wind|win|wnd { return tWND; }
<HELP_CMD>info|inf|in { return tINFO; }
<MODE_CMD>vm86 { return tVM86; }
<MAINT_CMD>type { return tTYPE; }
@ -180,167 +201,39 @@ struct { return tSTRUCT; }
union { return tUNION; }
enum { return tENUM; }
{IDENTIFIER} { yylval.string = DEBUG_MakeSymbol(yytext); return tIDENTIFIER; }
"$"{IDENTIFIER} { yylval.string = DEBUG_MakeSymbol(yytext+1); return tINTVAR; }
{IDENTIFIER} { yylval.string = lexeme_alloc(yytext); return tIDENTIFIER; }
"$"{IDENTIFIER} { yylval.string = lexeme_alloc(yytext+1); return tINTVAR; }
<PATH_EXPECTED>{PATHNAME} { yylval.string = DEBUG_MakeSymbol(yytext); return tPATH; }
<PATH_EXPECTED>{PATHNAME} { yylval.string = lexeme_alloc(yytext); return tPATH; }
<*>[ \t]+ /* Eat up whitespace */
<NOPROCESS>. { BEGIN(ASTRING_EXPECTED); yyless(0); return tNOPROCESS;}
<*>. { if (syntax_error == 0) {
syntax_error++;
DEBUG_Printf("Syntax Error (%s)\n", yytext); }
}
<*>. { if (syntax_error == 0) { syntax_error++; dbg_printf("Syntax Error (%s)\n", yytext); } }
%%
#ifndef yywrap
int yywrap(void) { return 1; }
#endif
#ifndef whitespace
#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
#endif
static char** local_lexemes /* = NULL */;
static int next_lexeme /* = 0 */;
static int alloc_lexeme /* = 0 */;
/* Strip whitespace from the start and end of STRING. */
static void stripwhite(char *string)
char* lexeme_alloc(const char* lexeme)
{
int i, last;
for (i = 0; whitespace(string[i]); i++);
if (i) strcpy(string, string + i);
last = i = strlen(string) - 1;
if (string[last] == '\n') i--;
while (i > 0 && whitespace(string[i])) i--;
if (string[last] == '\n')
string[++i] = '\n';
string[++i] = '\0';
}
static int DEBUG_FetchEntireLine(const char* pfx, char** line, size_t* alloc, BOOL check_nl)
{
char buf_line[256];
DWORD nread;
size_t len;
/* as of today, console handles can be file handles... so better use file APIs rather than
* consoles
*/
WriteFile(DEBUG_hParserOutput, pfx, strlen(pfx), NULL, NULL);
len = 0;
do
assert(0 <= next_lexeme && next_lexeme < alloc_lexeme + 1);
if (next_lexeme >= alloc_lexeme)
{
if (!ReadFile(DEBUG_hParserInput, buf_line, sizeof(buf_line) - 1, &nread, NULL) || nread == 0)
break;
buf_line[nread] = '\0';
if (check_nl && len == 0 && nread == 1 && buf_line[0] == '\n')
return 0;
/* store stuff at the end of last_line */
if (len + nread + 1 > *alloc)
{
if (*line)
*line = HeapReAlloc(GetProcessHeap(), 0, *line, *alloc += nread + 1);
else
*line = HeapAlloc(GetProcessHeap(), 0, *alloc += nread + 1);
}
strcpy(*line + len, buf_line);
len += nread;
} while (nread == 0 || buf_line[nread - 1] != '\n');
if (!len)
{
*line = HeapReAlloc(GetProcessHeap(), 0, *line, *alloc = 1);
**line = '\0';
alloc_lexeme += 32;
local_lexemes = dbg_heap_realloc(local_lexemes, alloc_lexeme * sizeof(local_lexemes[0]));
assert(local_lexemes);
}
/* Remove leading and trailing whitespace from the line */
stripwhite(*line);
return 1;
return local_lexemes[next_lexeme++] = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(lexeme) + 1), lexeme);
}
static int DEBUG_FetchFromLine(const char* pfx, char* buf, int size)
void lexeme_flush(void)
{
size_t len;
static char* last_line = NULL;
static size_t last_line_size = 0;
static size_t last_line_idx = 0;
/* first alloc of our current buffer */
if (!last_line)
{
last_line = HeapAlloc(GetProcessHeap(), 0, last_line_size = 2);
assert(last_line);
last_line[0] = '\n';
last_line[1] = '\0';
}
/* try first to fetch the remaining of an existing line */
if (last_line_idx == 0)
{
/* no remaining chars to be read from last line, grab a brand new line up to '\n' */
DEBUG_FlushSymbols();
DEBUG_FetchEntireLine(pfx, &last_line, &last_line_size, TRUE);
}
len = min(strlen(last_line + last_line_idx), size - 1);
memcpy(buf, last_line + last_line_idx, len);
buf[len] = '\0';
if ((last_line_idx += len) >= strlen(last_line))
last_line_idx = 0;
return len;
}
int DEBUG_ReadLine(const char* pfx, char* buf, int size)
{
char* line = NULL;
size_t len = 0;
/* first alloc of our current buffer */
line = HeapAlloc(GetProcessHeap(), 0, len = 2);
assert(line);
line[0] = '\n';
line[1] = '\0';
DEBUG_FetchEntireLine(pfx, &line, &len, FALSE);
len = strlen(line);
/* remove trailing \n */
if (len > 0 && line[len - 1] == '\n') len--;
len = min(size - 1, len);
memcpy(buf, line, len);
buf[len] = '\0';
HeapFree(GetProcessHeap(), 0, line);
return 1;
}
static char** local_symbols /* = NULL */;
static int next_symbol /* = 0 */;
static int alloc_symbol /* = 0 */;
char* DEBUG_MakeSymbol(const char* symbol)
{
assert(0 <= next_symbol && next_symbol < alloc_symbol + 1);
if (next_symbol >= alloc_symbol)
{
if (!local_symbols)
local_symbols = HeapAlloc(GetProcessHeap(), 0,
(alloc_symbol += 32) * sizeof(local_symbols[0]));
else
local_symbols = HeapReAlloc(GetProcessHeap(), 0, local_symbols,
(alloc_symbol += 32) * sizeof(local_symbols[0]));
assert(local_symbols);
}
return local_symbols[next_symbol++] = DBG_strdup(symbol);
}
void DEBUG_FlushSymbols(void)
{
while(--next_symbol >= 0) DBG_free(local_symbols[next_symbol]);
next_symbol = 0;
while (--next_lexeme >= 0) HeapFree(GetProcessHeap(), 0, local_lexemes[next_lexeme]);
next_lexeme = 0;
}

View File

@ -24,162 +24,107 @@
#include <assert.h>
#include <stdarg.h>
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#define WIN32_LEAN_AND_MEAN
#include "windef.h"
#include "winbase.h"
#include "ntstatus.h"
#include "winver.h"
#include "dbghelp.h"
#include "cvconst.h"
#include "oaidl.h"
#ifdef __i386__
#define STEP_FLAG 0x00000100 /* single step flag */
#define V86_FLAG 0x00020000
#endif
#define SYM_FUNC 0x0
#define SYM_DATA 0x1
#define SYM_WIN32 0x2
#define SYM_WINE 0x4
#define SYM_INVALID 0x8
#define SYM_TRAMPOLINE 0x10
#define SYM_STEP_THROUGH 0x20
enum debug_type {DT_BASIC, DT_POINTER, DT_ARRAY, DT_STRUCT, DT_ENUM,
DT_FUNC, DT_BITFIELD};
enum debug_type_basic {DT_BASIC_INT = 1, DT_BASIC_CHAR, DT_BASIC_LONGINT, DT_BASIC_UINT,
DT_BASIC_ULONGINT, DT_BASIC_LONGLONGINT, DT_BASIC_ULONGLONGINT,
DT_BASIC_SHORTINT, DT_BASIC_USHORTINT, DT_BASIC_SCHAR, DT_BASIC_UCHAR,
DT_BASIC_FLOAT, DT_BASIC_LONGDOUBLE, DT_BASIC_DOUBLE,
DT_BASIC_CMPLX_INT, DT_BASIC_CMPLX_FLOAT, DT_BASIC_CMPLX_DOUBLE,
DT_BASIC_CMPLX_LONGDOUBLE, DT_BASIC_VOID,
/* modifier on size isn't possible on current types definitions
* so we need to add more types... */
DT_BASIC_BOOL1, DT_BASIC_BOOL2, DT_BASIC_BOOL4,
/* this is not really a basic type... */
DT_BASIC_STRING,
/* this is for historical reasons... should take care of it RSN */
DT_BASIC_CONST_INT,
/* not so basic, but handy */
DT_BASIC_CONTEXT,
/* to be kept as last... sentinel entry... do not use */
DT_BASIC_LAST};
/* the debugger uses these exceptions for it's internal use */
#define DEBUG_STATUS_OFFSET 0x80003000
#define DEBUG_STATUS_INTERNAL_ERROR (DEBUG_STATUS_OFFSET+0) /* something went wrong */
#define DEBUG_STATUS_NO_SYMBOL (DEBUG_STATUS_OFFSET+1) /* no symbol found in lookup */
#define DEBUG_STATUS_DIV_BY_ZERO (DEBUG_STATUS_OFFSET+2)
#define DEBUG_STATUS_BAD_TYPE (DEBUG_STATUS_OFFSET+3) /* no type found, when type was expected */
#define DEBUG_STATUS_NO_FIELD (DEBUG_STATUS_OFFSET+4) /* when dereferencing a struct, the field was not found */
#define DEBUG_STATUS_ABORT (DEBUG_STATUS_OFFSET+5) /* user aborted on going action */
#define DEBUG_STATUS_CANT_DEREF (DEBUG_STATUS_OFFSET+6) /* either not deref:able, or index out of bounds */
#define DEBUG_STATUS_NOT_AN_INTEGER (DEBUG_STATUS_OFFSET+7) /* requiring an integral value */
/*
* Return values for DEBUG_CheckLinenoStatus. Used to determine
* Return values for symbol_get_function_line_status. Used to determine
* what to do when the 'step' command is given.
*/
#define FUNC_HAS_NO_LINES (0)
#define NOT_ON_LINENUMBER (1)
#define AT_LINENUMBER (2)
#define FUNC_IS_TRAMPOLINE (3)
typedef struct
enum dbg_line_status
{
DWORD seg; /* 0xffffffff means current default segment (cs or ds) */
DWORD off;
} DBG_ADDR;
dbg_no_line_info,
dbg_not_on_a_line_number,
dbg_on_a_line_number,
dbg_in_a_thunk,
};
typedef struct
enum dbg_internal_types
{
struct datatype* type;
int cookie; /* DV_??? */
/* DV_TARGET references an address in debugger's address space, whereas DV_HOST
* references the debuggee address space
dbg_itype_first = 0xffffff00,
dbg_itype_unsigned_int,
dbg_itype_signed_int,
dbg_itype_signed_char_int,
dbg_itype_unsigned_char_int,
dbg_itype_unsigned_short_int,
dbg_itype_signed_short_int,
dbg_itype_unsigned_long_int,
dbg_itype_signed_long_int,
dbg_itype_unsigned_longlong_int,
dbg_itype_signed_longlong_int,
dbg_itype_char,
dbg_itype_wchar,
dbg_itype_short_real, /* aka float */
dbg_itype_real, /* aka double */
dbg_itype_long_real, /* aka long double */
dbg_itype_astring,
dbg_itype_ustring,
dbg_itype_none = 0xffffffff
};
struct dbg_lvalue /* structure to hold left-values... */
{
int cookie; /* DLV_??? */
/* DLV_TARGET references an address in debuggee's address space, whereas DLV_HOST
* references the winedbg's address space
*/
# define DV_TARGET 0xF00D
# define DV_HOST 0x50DA
# define DV_INVALID 0x0000
# define DLV_TARGET 0xF00D
# define DLV_HOST 0x50DA
ADDRESS addr;
unsigned long typeid;
};
DBG_ADDR addr;
} DBG_VALUE;
struct list_id
enum dbg_exec_mode
{
char * sourcefile;
int line;
};
struct wine_lines {
unsigned long line_number;
DBG_ADDR pc_offset;
};
struct symbol_info
{
struct name_hash * sym;
struct list_id list;
};
typedef struct wine_lines WineLineNo;
/*
* This structure holds information about stack variables, function
* parameters, and register variables, which are all local to this
* function.
*/
struct wine_locals {
unsigned int regno:8; /* For register symbols */
signed int offset:24; /* offset from esp/ebp to symbol */
unsigned int pc_start; /* For RBRAC/LBRAC */
unsigned int pc_end; /* For RBRAC/LBRAC */
char * name; /* Name of symbol */
struct datatype * type; /* Datatype of symbol */
};
typedef struct wine_locals WineLocals;
enum exec_mode
{
EXEC_CONT, /* Continuous execution */
EXEC_STEP_OVER, /* Stepping over a call to next source line */
EXEC_STEP_INSTR, /* Step to next source line, stepping in if needed */
EXEC_STEPI_OVER, /* Stepping over a call */
EXEC_STEPI_INSTR, /* Single-stepping an instruction */
EXEC_FINISH, /* Step until we exit current frame */
EXEC_STEP_OVER_TRAMPOLINE, /* Step over trampoline. Requires that
* we dig the real return value off the stack
* and set breakpoint there - not at the
* instr just after the call.
dbg_exec_cont, /* Continue execution */
dbg_exec_step_over_line, /* Stepping over a call to next source line */
dbg_exec_step_into_line, /* Step to next source line, stepping in if needed */
dbg_exec_step_over_insn, /* Stepping over a call */
dbg_exec_step_into_insn, /* Single-stepping an instruction */
dbg_exec_finish, /* Single-step until we exit current frame */
#if 0
EXEC_STEP_OVER_TRAMPOLINE, /* Step over trampoline. Requires that we dig the real
* return value off the stack and set breakpoint there -
* not at the instr just after the call.
*/
#endif
};
enum dbg_mode
struct dbg_breakpoint
{
MODE_INVALID, MODE_16, MODE_32, MODE_VM86
ADDRESS addr;
unsigned long enabled : 1,
xpoint_type : 2,
refcount : 13,
skipcount : 16;
DWORD info;
struct /* only used for watchpoints */
{
BYTE len : 2;
DWORD oldval;
} w;
struct expr* condition;
};
enum exit_mode /* of exception handling */
{
EXIT_CONTINUE, /* continue execution */
EXIT_PASS, /* pass exception back to app (1st chance) */
EXIT_DETACH, /* detach debugger */
EXIT_QUIT, /* exit debugger and kill debuggee */
};
#define DBG_BREAK 0
#define DBG_WATCH 1
typedef struct
{
DBG_ADDR addr;
WORD enabled : 1,
type : 1,
is32 : 1,
refcount : 13;
WORD skipcount;
union {
struct {
BYTE opcode;
BOOL (*func)(void);
} b;
struct {
BYTE rw : 1,
len : 2;
BYTE reg;
DWORD oldval;
} w;
} u;
struct expr * condition;
} DBG_BREAKPOINT;
/* Wine extension; Windows doesn't have a name for this code. This is an
undocumented exception understood by MS VC debugger, allowing the program
to name a particular thread. Search google.com or deja.com for "0x406d1388"
@ -195,403 +140,279 @@ typedef struct tagTHREADNAME_INFO
DWORD dwFlags; /* Reserved for future use. Must be zero. */
} THREADNAME_INFO;
typedef struct tagDBG_THREAD {
struct tagDBG_PROCESS* process;
struct dbg_thread
{
struct dbg_process* process;
HANDLE handle;
DWORD tid;
LPVOID start;
LPVOID teb;
void* teb;
int wait_for_first_exception;
enum exec_mode exec_mode; /* mode the thread is run (step/run...) */
enum dbg_exec_mode exec_mode; /* mode the thread is run (step/run...) */
int exec_count; /* count of mode operations */
enum dbg_mode dbg_mode; /* mode (VM86, 32bit, 16bit) */
DBG_BREAKPOINT stepOverBP;
ADDRESS_MODE addr_mode; /* mode */
struct dbg_breakpoint step_over_bp;
char name[9];
struct tagDBG_THREAD* next;
struct tagDBG_THREAD* prev;
} DBG_THREAD;
struct dbg_thread* next;
struct dbg_thread* prev;
};
typedef struct tagDBG_DELAYED_BP {
struct dbg_delayed_bp
{
BOOL is_symbol;
union {
struct {
union
{
struct
{
int lineno;
char* name;
} symbol;
DBG_VALUE value;
ADDRESS addr;
} u;
} DBG_DELAYED_BP;
};
typedef struct tagDBG_PROCESS {
#define MAX_BREAKPOINTS 100
struct dbg_process
{
HANDLE handle;
DWORD pid;
const char* imageName;
DBG_THREAD* threads;
int num_threads;
struct dbg_thread* threads;
unsigned continue_on_first_exception;
struct tagDBG_MODULE** modules;
int num_modules;
unsigned long dbg_hdr_addr;
DBG_DELAYED_BP* delayed_bp;
struct dbg_breakpoint bp[MAX_BREAKPOINTS];
unsigned next_bp;
struct dbg_delayed_bp* delayed_bp;
int num_delayed_bp;
/*
* This is an index we use to keep track of the debug information
* when we have multiple sources. We use the same database to also
* allow us to do an 'info shared' type of deal, and we use the index
* to eliminate duplicates.
*/
int next_index;
struct tagDBG_PROCESS* next;
struct tagDBG_PROCESS* prev;
} DBG_PROCESS;
extern DBG_PROCESS* DEBUG_CurrProcess;
extern DBG_THREAD* DEBUG_CurrThread;
extern DWORD DEBUG_CurrTid;
extern DWORD DEBUG_CurrPid;
extern CONTEXT DEBUG_context;
extern BOOL DEBUG_InteractiveP;
extern enum exit_mode DEBUG_ExitMode;
extern HANDLE DEBUG_hParserInput;
extern HANDLE DEBUG_hParserOutput;
#define DEBUG_READ_MEM(addr, buf, len) \
(ReadProcessMemory(DEBUG_CurrProcess->handle, (addr), (buf), (len), NULL))
#define DEBUG_WRITE_MEM(addr, buf, len) \
(WriteProcessMemory(DEBUG_CurrProcess->handle, (addr), (buf), (len), NULL))
#define DEBUG_READ_MEM_VERBOSE(addr, buf, len) \
(DEBUG_READ_MEM((addr), (buf), (len)) || (DEBUG_InvalLinAddr( addr ),0))
#define DEBUG_WRITE_MEM_VERBOSE(addr, buf, len) \
(DEBUG_WRITE_MEM((addr), (buf), (len)) || (DEBUG_InvalLinAddr( addr ),0))
enum DbgInfoLoad {DIL_DEFERRED, DIL_LOADED, DIL_NOINFO, DIL_NOT_SUPPORTED, DIL_ERROR};
enum DbgModuleType {DMT_UNKNOWN, DMT_ELF, DMT_NE, DMT_PE};
typedef struct tagDBG_MODULE {
void* load_addr;
unsigned long size;
const char* module_name;
enum DbgInfoLoad dil;
enum DbgModuleType type;
unsigned short main : 1;
short int dbg_index;
HMODULE handle;
struct tagMSC_DBG_INFO* msc_dbg_info;
struct tagELF_DBG_INFO* elf_dbg_info;
} DBG_MODULE;
typedef struct {
DWORD val;
const char* name;
LPDWORD pval;
struct datatype* type;
} DBG_INTVAR;
#define OFFSET_OF(__c,__f) ((int)(((char*)&(((__c*)0)->__f))-((char*)0)))
enum get_sym_val {gsv_found, gsv_unknown, gsv_aborted};
/* from winelib.so */
extern void DEBUG_ExternalDebugger(void);
/* debugger/break.c */
extern void DEBUG_SetBreakpoints( BOOL set );
extern BOOL DEBUG_AddBreakpoint( const DBG_VALUE *addr, BOOL (*func)(void), BOOL verbose );
extern BOOL DEBUG_AddBreakpointFromValue( const DBG_VALUE *addr );
extern void DEBUG_AddBreakpointFromId( const char *name, int lineno );
extern void DEBUG_AddBreakpointFromLineno( int lineno );
extern void DEBUG_AddWatchpoint( const DBG_VALUE *addr, int is_write );
extern void DEBUG_AddWatchpointFromId( const char *name );
extern void DEBUG_CheckDelayedBP( void );
extern void DEBUG_DelBreakpoint( int num );
extern void DEBUG_EnableBreakpoint( int num, BOOL enable );
extern void DEBUG_InfoBreakpoints(void);
extern BOOL DEBUG_HandleTrap(void);
extern BOOL DEBUG_ShouldContinue( DBG_ADDR* addr, DWORD code, int* count );
extern void DEBUG_SuspendExecution( void );
extern void DEBUG_RestartExecution( int count );
extern BOOL DEBUG_IsFctReturn(void);
extern int DEBUG_AddBPCondition(int bpnum, struct expr * exp);
/* debugger/db_disasm.c */
extern void DEBUG_Disasm( DBG_ADDR *addr, int display );
/* debugger/dbg.y */
extern void DEBUG_Parser(LPCSTR);
extern void DEBUG_Exit(DWORD);
/* debugger/debug.l */
extern void DEBUG_FlushSymbols(void);
extern char*DEBUG_MakeSymbol(const char*);
extern int DEBUG_ReadLine(const char* pfx, char* buffer, int size);
/* debugger/display.c */
extern int DEBUG_DoDisplay(void);
extern int DEBUG_AddDisplay(struct expr * exp, int count, char format, int local_frame);
extern int DEBUG_DelDisplay(int displaynum);
extern int DEBUG_InfoDisplay(void);
extern int DEBUG_EnableDisplay(int displaynum, int enable);
/* debugger/elf.c */
#define ELF_INFO_PATH 0x0001
#define ELF_INFO_DEBUG_HEADER 0x0002
#define ELF_INFO_SEGMENTS 0x0004
#define ELF_INFO_MODULE 0x0008
struct elf_info
{
unsigned flags;
char* elf_path; /* path to unix elf path, if ELF_INFO_PATH is set */
size_t elf_path_len;
void* load_addr; /* 32 bit linear addr, where ELF module is loaded */
unsigned long size; /* size of elf module (guessed) */
unsigned long dbg_hdr_addr; /* address of debug header (if ELF_INFO_DEBUG_HEADER is set) */
unsigned long segments[3]; /* addresses of .text, .data and .bss segments (not filled yet) */
struct dbg_process* next;
struct dbg_process* prev;
};
extern enum DbgInfoLoad DEBUG_ReadWineLoaderDbgInfo(HANDLE hProcess, struct elf_info* elf_info);
extern BOOL DEBUG_SetElfSoLoadBreakpoint(const struct elf_info* elf_info);
extern struct dbg_process* dbg_curr_process;
extern DWORD dbg_curr_pid;
extern struct dbg_thread* dbg_curr_thread;
extern DWORD dbg_curr_tid;
extern CONTEXT dbg_context;
extern BOOL dbg_interactiveP;
extern int dbg_curr_frame;
/* debugger/expr.c */
extern void DEBUG_FreeExprMem(void);
struct expr * DEBUG_IntVarExpr(const char* name);
struct expr * DEBUG_SymbolExpr(const char * name);
struct expr * DEBUG_ConstExpr(int val);
struct expr * DEBUG_StringExpr(const char * str);
struct expr * DEBUG_SegAddr(struct expr *, struct expr *);
struct expr * DEBUG_USConstExpr(unsigned int val);
struct expr * DEBUG_BinopExpr(int oper, struct expr *, struct expr *);
struct expr * DEBUG_UnopExpr(int oper, struct expr *);
struct expr * DEBUG_StructPExpr(struct expr *, const char * element);
struct expr * DEBUG_StructExpr(struct expr *, const char * element);
struct expr * DEBUG_ArrayExpr(struct expr *, struct expr * index);
struct expr * DEBUG_CallExpr(const char *, int nargs, ...);
struct expr * DEBUG_TypeCastExpr(struct datatype *, struct expr *);
extern DBG_VALUE DEBUG_EvalExpr(struct expr *);
extern int DEBUG_DelDisplay(int displaynum);
extern struct expr * DEBUG_CloneExpr(const struct expr * exp);
extern int DEBUG_FreeExpr(struct expr * exp);
extern int DEBUG_DisplayExpr(const struct expr * exp);
struct dbg_internal_var
{
DWORD val;
const char* name;
LPDWORD pval;
unsigned long typeid;
};
/* debugger/hash.c */
extern struct name_hash * DEBUG_AddSymbol( const char *name,
const DBG_VALUE *addr,
const char *sourcefile,
int flags);
extern enum get_sym_val DEBUG_GetSymbolValue( const char * name, const int lineno, DBG_VALUE *addr, int );
extern const char * DEBUG_FindNearestSymbol( const DBG_ADDR *addr, int flag,
struct name_hash ** rtn,
unsigned int ebp,
struct list_id * source);
extern void DEBUG_ReadSymbolTable( const char * filename, unsigned long offset );
extern void DEBUG_AddLineNumber( struct name_hash * func, int line_num,
unsigned long offset );
extern struct wine_locals *
DEBUG_AddLocal( struct name_hash * func, int regno,
int offset,
int pc_start,
int pc_end,
char * name);
extern int DEBUG_CheckLinenoStatus(const DBG_ADDR *addr);
extern void DEBUG_GetFuncInfo(struct list_id * ret, const char * file,
const char * func);
extern int DEBUG_SetSymbolSize(struct name_hash * sym, unsigned int len);
extern int DEBUG_SetSymbolBPOff(struct name_hash * sym, unsigned int len);
extern int DEBUG_GetSymbolAddr(struct name_hash * sym, DBG_ADDR * addr);
extern int DEBUG_cmp_sym(const void * p1, const void * p2);
extern BOOL DEBUG_GetLineNumberAddr( const struct name_hash *, const int lineno,
DBG_ADDR *addr, int bp_flag );
enum sym_get_lval {sglv_found, sglv_unknown, sglv_aborted};
extern int DEBUG_SetLocalSymbolType(struct wine_locals * sym,
struct datatype * type);
extern BOOL DEBUG_Normalize(struct name_hash * nh );
void DEBUG_InfoSymbols(const char* str);
const char *DEBUG_GetSymbolName(const struct name_hash *);
enum type_expr_e
{
type_expr_type_id,
type_expr_udt_class,
type_expr_udt_struct,
type_expr_udt_union,
type_expr_enumeration
};
/* debugger/info.c */
extern void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format );
extern struct symbol_info DEBUG_PrintAddress( const DBG_ADDR *addr,
enum dbg_mode mode, int flag );
extern void DEBUG_Help(void);
extern void DEBUG_HelpInfo(void);
extern struct symbol_info DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr,
enum dbg_mode mode,
unsigned int ebp,
int flag );
extern void DEBUG_InfoClass(const char* clsName);
extern void DEBUG_WalkClasses(void);
extern void DEBUG_DumpModule(DWORD mod);
extern void DEBUG_WalkModules(void);
extern void DEBUG_WalkProcess(void);
extern void DEBUG_WalkThreads(void);
extern void DEBUG_WalkExceptions(DWORD tid);
extern void DEBUG_InfoSegments(DWORD s, int v);
extern void DEBUG_InfoVirtual(DWORD pid);
extern void DEBUG_InfoWindow(HWND hWnd);
extern void DEBUG_WalkWindows(HWND hWnd, int indent);
extern void DEBUG_DbgChannel(BOOL add, const char* chnl, const char* name);
struct type_expr_t
{
enum type_expr_e type;
unsigned deref_count;
union
{
unsigned long typeid;
const char* name;
} u;
};
/* debugger/memory.c */
extern int DEBUG_ReadMemory( const DBG_VALUE* value );
extern void DEBUG_WriteMemory( const DBG_VALUE* val, int value );
extern void DEBUG_ExamineMemory( const DBG_VALUE *addr, int count, char format);
extern void DEBUG_InvalAddr( const DBG_ADDR* addr );
extern void DEBUG_InvalLinAddr( void* addr );
extern DWORD DEBUG_ToLinear( const DBG_ADDR *address );
extern void DEBUG_GetCurrentAddress( DBG_ADDR * );
extern BOOL DEBUG_GrabAddress( DBG_VALUE* value, BOOL fromCode );
extern enum dbg_mode DEBUG_GetSelectorType( WORD sel );
#ifdef __i386__
extern void DEBUG_FixAddress( DBG_ADDR *address, DWORD def );
extern int DEBUG_IsSelectorSystem( WORD sel );
#endif
extern int DEBUG_PrintStringA(const DBG_ADDR* address, int len);
extern int DEBUG_PrintStringW(const DBG_ADDR* address, int len);
/* break.c */
extern void break_set_xpoints(BOOL set);
extern BOOL break_add_break(const ADDRESS* addr, BOOL verbose);
extern BOOL break_add_break_from_lvalue(const struct dbg_lvalue* value);
extern void break_add_break_from_id(const char* name, int lineno);
extern void break_add_break_from_lineno(int lineno);
extern void break_add_watch(const struct dbg_lvalue* lvalue, int is_write);
extern void break_add_watch_from_id(const char* name);
extern void break_check_delayed_bp(void);
extern void break_delete_xpoint(int num);
extern void break_delete_xpoints_from_module(unsigned long base);
extern void break_enable_xpoint(int num, BOOL enable);
extern void break_info(void);
extern BOOL break_should_continue(ADDRESS* addr, DWORD code, int* count);
extern void break_suspend_execution(void);
extern void break_restart_execution(int count);
extern int break_add_condition(int bpnum, struct expr* exp);
/* debugger/module.c */
extern DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type,
void* mod_addr, unsigned long size, HMODULE hmodule);
extern int DEBUG_LoadEntryPoints( const char * prefix );
extern DBG_MODULE* DEBUG_FindModuleByName(const char* name, enum DbgModuleType type);
extern DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, enum DbgModuleType type);
extern DBG_MODULE* DEBUG_FindModuleByAddr(void* addr, enum DbgModuleType type);
extern DBG_MODULE* DEBUG_GetProcessMainModule(DBG_PROCESS* process);
extern void DEBUG_ReportDIL(enum DbgInfoLoad dil, const char* pfx,
const char* filename, void *load_addr);
extern void DEBUG_InfoShare(void);
/* dbg.y */
extern void parser(const char*);
extern int input_read_line(const char* pfx, char* buffer, int size);
extern int input_fetch_entire_line(const char* pfx, char** line, size_t* alloc, BOOL check_nl);
/* debugger/msc.c */
extern void DEBUG_InitCVDataTypes(void);
extern enum DbgInfoLoad DEBUG_ProcessDebugDirectory( DBG_MODULE *module, const BYTE* file_map,
PIMAGE_DEBUG_DIRECTORY dbg, int nDbg );
/* debug.l */
extern void lexeme_flush(void);
extern char* lexeme_alloc(const char*);
/* debugger/pe.c */
extern void* DEBUG_MapDebugInfoFile(const char* name, DWORD offset, DWORD size,
HANDLE* hFile, HANDLE* hMap);
extern void DEBUG_UnmapDebugInfoFile(HANDLE hFile, HANDLE hMap, const void* addr);
extern void DEBUG_LoadPEModule( const char* name, HANDLE hFile, void *base );
extern enum DbgInfoLoad DEBUG_RegisterMSCDebugInfo(DBG_MODULE* module, HANDLE hFile,
void* nth, unsigned long nth_ofs);
extern enum DbgInfoLoad DEBUG_RegisterStabsDebugInfo(DBG_MODULE* module,
HANDLE hFile, void* nth,
unsigned long nth_ofs);
extern enum DbgInfoLoad DEBUG_RegisterPEDebugInfo(DBG_MODULE* wmod, HANDLE hFile,
void* _nth, unsigned long nth_ofs);
/* display.c */
extern int display_print(void);
extern int display_add(struct expr* exp, int count, char format, int local_frame);
extern int display_delete(int displaynum);
extern int display_info(void);
extern int display_enable(int displaynum, int enable);
/* debugger/registers.c */
extern void DEBUG_InfoRegisters(const CONTEXT* ctx);
extern BOOL DEBUG_ValidateRegisters(void);
/* expr.c */
extern void expr_free_all(void);
extern struct expr* expr_alloc_internal_var(const char* name);
extern struct expr* expr_alloc_symbol(const char* name);
extern struct expr* expr_alloc_sconstant(int val);
extern struct expr* expr_alloc_uconstant(unsigned val);
extern struct expr* expr_alloc_string(const char* str);
extern struct expr* expr_alloc_binary_op(int oper, struct expr*, struct expr*);
extern struct expr* expr_alloc_unary_op(int oper, struct expr*);
extern struct expr* expr_alloc_pstruct(struct expr*, const char* element);
extern struct expr* expr_alloc_struct(struct expr*, const char* element);
extern struct expr* expr_alloc_func_call(const char*, int nargs, ...);
extern struct expr* expr_alloc_typecast(struct type_expr_t*, struct expr*);
extern struct dbg_lvalue expr_eval(struct expr*);
extern struct expr* expr_clone(const struct expr* exp);
extern int expr_free(struct expr* exp);
extern int expr_print(const struct expr* exp);
/* debugger/source.c */
extern void DEBUG_ShowDir(void);
extern void DEBUG_AddPath(const char * path);
extern void DEBUG_List(struct list_id * line1, struct list_id * line2,
int delta);
extern void DEBUG_NukePath(void);
extern void DEBUG_Disassemble(const DBG_VALUE *, const DBG_VALUE*, int offset);
extern BOOL DEBUG_DisassembleInstruction(DBG_ADDR *addr);
/* info.c */
extern void print_help(void);
extern void info_help(void);
extern void info_win32_module(DWORD mod);
extern void info_win32_class(HWND hWnd, const char* clsName);
extern void info_win32_window(HWND hWnd, BOOL detailed);
extern void info_win32_processes(void);
extern void info_win32_threads(void);
extern void info_win32_exceptions(DWORD tid);
extern void info_win32_virtual(DWORD pid);
extern void info_win32_segments(DWORD start, int length);
extern void info_wine_dbg_channel(BOOL add, const char* chnl, const char* name);
/* debugger/stack.c */
extern void DEBUG_InfoStack(void);
extern void DEBUG_BackTrace(DWORD threadID, BOOL noisy);
extern int DEBUG_InfoLocals(void);
extern int DEBUG_SetFrame(int newframe);
extern int DEBUG_GetCurrentFrame(struct name_hash ** name,
unsigned int * eip,
unsigned int * ebp);
/* memory.c */
extern BOOL memory_read_value(const struct dbg_lvalue* val, DWORD size, void* result);
extern BOOL memory_write_value(const struct dbg_lvalue* val, DWORD size, void* value);
extern void memory_examine(const struct dbg_lvalue* addr, int count, char format);
extern void memory_report_invalid_addr(const void* addr);
extern void* memory_to_linear_addr(const ADDRESS* address);
extern BOOL memory_get_current_pc(ADDRESS* address);
extern BOOL memory_get_current_stack(ADDRESS* address);
extern BOOL memory_get_current_frame(ADDRESS* address);
extern BOOL memory_get_string(HANDLE hp, void* addr, unsigned cookie, BOOL unicode, char* buffer, int size);
extern BOOL memory_get_string_indirect(HANDLE hp, void* addr, BOOL unicode, char* buffer, int size);
extern void memory_disassemble(const struct dbg_lvalue*, const struct dbg_lvalue*, int offset);
extern BOOL memory_disasm_one_insn(ADDRESS* addr);
extern void print_bare_address(const ADDRESS* addr);
extern void print_address(const ADDRESS* addr, BOOLEAN with_line);
extern void print_addr_and_args(const ADDRESS* pc, const ADDRESS* frame);
extern void print_basic(const struct dbg_lvalue* value, int count, char format);
/* debugger/stabs.c */
extern enum DbgInfoLoad DEBUG_ParseStabs(const char* addr, void *load_offset,
unsigned int staboff, int stablen,
unsigned int strtaboff, int strtablen);
/* source.c */
extern void source_list(IMAGEHLP_LINE* src1, IMAGEHLP_LINE* src2, int delta);
extern void source_list_from_addr(const ADDRESS* addr, int nlines);
extern void source_show_path(void);
extern void source_add_path(const char* path);
extern void source_nuke_path(void);
/* debugger/types.c */
extern int DEBUG_nchar;
extern void DEBUG_InitTypes(void);
extern struct datatype * DEBUG_NewDataType(enum debug_type xtype,
const char * typename);
extern unsigned int DEBUG_TypeDerefPointer(const DBG_VALUE *value,
struct datatype ** newtype);
extern int DEBUG_AddStructElement(struct datatype * dt,
char * name, struct datatype * type,
int offset, int size);
extern int DEBUG_SetStructSize(struct datatype * dt, int size);
extern int DEBUG_SetPointerType(struct datatype * dt, struct datatype * dt2);
extern int DEBUG_SetArrayParams(struct datatype * dt, int min, int max,
struct datatype * dt2);
extern void DEBUG_Print( const DBG_VALUE *addr, int count, char format, int level );
extern unsigned int DEBUG_FindStructElement(DBG_VALUE * addr,
const char * ele_name, int * tmpbuf);
extern struct datatype * DEBUG_GetPointerType(struct datatype * dt);
extern int DEBUG_GetObjectSize(struct datatype * dt);
extern unsigned int DEBUG_ArrayIndex(const DBG_VALUE * addr, DBG_VALUE * result,
int index);
extern struct datatype * DEBUG_FindOrMakePointerType(struct datatype * reftype);
extern long long int DEBUG_GetExprValue(const DBG_VALUE * addr, const char ** format);
extern int DEBUG_SetBitfieldParams(struct datatype * dt, int offset,
int nbits, struct datatype * dt2);
extern int DEBUG_CopyFieldlist(struct datatype * dt, struct datatype * dt2);
extern const char* DEBUG_GetName(struct datatype * dt);
extern enum debug_type DEBUG_GetType(struct datatype * dt);
extern struct datatype * DEBUG_TypeCast(enum debug_type, const char *);
extern int DEBUG_PrintTypeCast(const struct datatype *);
extern int DEBUG_PrintType(const DBG_VALUE* addr);
extern struct datatype * DEBUG_GetBasicType(enum debug_type_basic);
extern int DEBUG_DumpTypes(void);
/* stack.c */
extern void stack_info(void);
extern void stack_backtrace(DWORD threadID, BOOL noisy);
extern int stack_set_frame(int newframe);
extern int stack_get_frame(SYMBOL_INFO* sym, IMAGEHLP_STACK_FRAME* ihsf);
/* debugger/winedbg.c */
extern void DEBUG_OutputA(const char* buffer, int len);
extern void DEBUG_OutputW(const WCHAR* buffer, int len);
/* symbol.c */
extern enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno, struct dbg_lvalue* addr, BOOL bp_disp);
extern void symbol_read_symtable(const char* filename, unsigned long offset);
extern enum dbg_line_status symbol_get_function_line_status(const ADDRESS* addr);
extern BOOL symbol_get_line(const char* filename, const char* func, IMAGEHLP_LINE* ret);
extern void symbol_info(const char* str);
extern int symbol_info_locals(void);
/* types.c */
extern void print_value(const struct dbg_lvalue* addr, char format, int level);
extern int types_print_type(DWORD linear, DWORD typeid, BOOL details);
extern int print_types(void);
extern long int types_extract_as_integer(const struct dbg_lvalue*);
extern BOOL types_deref(const struct dbg_lvalue* value, struct dbg_lvalue* result);
extern BOOL types_udt_find_element(struct dbg_lvalue* value, const char* name, long int* tmpbuf);
extern BOOL types_array_index(const struct dbg_lvalue* value, int index, struct dbg_lvalue* result);
extern BOOL types_get_info(unsigned long, unsigned long,
IMAGEHLP_SYMBOL_TYPE_INFO, void*);
extern unsigned long types_find_pointer(unsigned long linear, unsigned long typeid);
extern unsigned long types_find_type(unsigned long linear, const char* name, enum SymTagEnum tag);
/* winedbg.c */
extern void dbg_outputA(const char* buffer, int len);
extern void dbg_outputW(const WCHAR* buffer, int len);
#ifdef __GNUC__
extern int DEBUG_Printf(const char* format, ...) __attribute__((format (printf,1,2)));
extern int dbg_printf(const char* format, ...) __attribute__((format (printf,1,2)));
#else
extern int DEBUG_Printf(const char* format, ...);
extern int dbg_printf(const char* format, ...);
#endif
extern DBG_INTVAR* DEBUG_GetIntVar(const char*);
extern BOOL DEBUG_Attach(DWORD pid, BOOL cofe, BOOL wfe);
extern BOOL DEBUG_Detach(void);
extern void DEBUG_Run(const char* args);
extern DBG_PROCESS* DEBUG_AddProcess(DWORD pid, HANDLE h, const char* imageName);
extern DBG_PROCESS* DEBUG_GetProcess(DWORD pid);
extern void DEBUG_DelProcess(DBG_PROCESS* p);
extern DBG_THREAD* DEBUG_AddThread(DBG_PROCESS* p, DWORD tid, HANDLE h, LPVOID start, LPVOID teb);
extern DBG_THREAD* DEBUG_GetThread(DBG_PROCESS* p, DWORD tid);
extern void DEBUG_DelThread(DBG_THREAD* t);
extern BOOL DEBUG_ProcessGetString(char* buffer, int size, HANDLE hp, LPSTR addr);
extern BOOL DEBUG_ProcessGetStringIndirect(char* buffer, int size, HANDLE hp, LPVOID addr, BOOL unicode);
extern void DEBUG_WaitNextException(DWORD cont, int count, int mode);
extern BOOL DEBUG_InterruptDebuggee(void);
extern int curr_frame;
extern const struct dbg_internal_var* dbg_get_internal_var(const char*);
extern BOOL dbg_attach_debuggee(DWORD pid, BOOL cofe, BOOL wfe);
extern BOOL dbg_detach_debuggee(void);
extern BOOL dbg_interrupt_debuggee(void);
extern void dbg_run_debuggee(const char* args);
extern struct dbg_process* dbg_add_process(DWORD pid, HANDLE h, const char* imageName);
extern struct dbg_process* dbg_get_process(DWORD pid);
extern void dbg_del_process(struct dbg_process* p);
struct dbg_thread* dbg_add_thread(struct dbg_process* p, DWORD tid, HANDLE h, void* teb);
extern struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid);
extern void dbg_del_thread(struct dbg_thread* t);
extern void dbg_wait_next_exception(DWORD cont, int count, int mode);
extern BOOL dbg_get_debuggee_info(HANDLE hProcess, IMAGEHLP_MODULE* imh_mod);
/* gdbproxy.c */
extern BOOL DEBUG_GdbRemote(unsigned int);
extern BOOL gdb_remote(unsigned int);
extern void *DBG_alloc(size_t size);
extern void *DBG_realloc(void *ptr, size_t size);
extern void DBG_free(void *ptr);
extern char *DBG_strdup(const char *str);
static inline BOOL dbg_read_memory(const void* addr, void* buffer, size_t len)
{
DWORD rlen;
return ReadProcessMemory(dbg_curr_process->handle, addr, buffer, len, &rlen) && len == rlen;
}
#define DEBUG_STATUS_OFFSET 0x80003000
#define DEBUG_STATUS_INTERNAL_ERROR (DEBUG_STATUS_OFFSET+0)
#define DEBUG_STATUS_NO_SYMBOL (DEBUG_STATUS_OFFSET+1)
#define DEBUG_STATUS_DIV_BY_ZERO (DEBUG_STATUS_OFFSET+2)
#define DEBUG_STATUS_BAD_TYPE (DEBUG_STATUS_OFFSET+3)
#define DEBUG_STATUS_NO_FIELD (DEBUG_STATUS_OFFSET+4)
#define DEBUG_STATUS_ABORT (DEBUG_STATUS_OFFSET+5)
static inline BOOL dbg_write_memory(void* addr, const void* buffer, size_t len)
{
DWORD wlen;
return WriteProcessMemory(dbg_curr_process->handle, addr, buffer, len, &wlen) && len == wlen;
}
extern DBG_INTVAR DEBUG_IntVars[];
static inline BOOL dbg_read_memory_verbose(const void* addr, void* buffer, size_t len)
{
if (dbg_read_memory(addr, buffer, len)) return TRUE;
memory_report_invalid_addr(addr);
return FALSE;
}
#define DBG_IVARNAME(_var) DEBUG_IV_##_var
#define DBG_IVARSTRUCT(_var) DEBUG_IntVars[DBG_IVARNAME(_var)]
static inline BOOL dbg_write_memory_verbose(void* addr, const void* buffer, size_t len)
{
if (dbg_write_memory(addr, buffer, len)) return TRUE;
memory_report_invalid_addr(addr);
return FALSE;
}
static inline void* dbg_heap_realloc(void* buffer, size_t size)
{
return (buffer) ? HeapReAlloc(GetProcessHeap(), 0, buffer, size) :
HeapAlloc(GetProcessHeap(), 0, size);
}
extern struct dbg_internal_var dbg_internal_vars[];
extern const struct dbg_internal_var* dbg_context_vars;
#define DBG_IVARNAME(_var) dbg_internal_var_##_var
#define DBG_IVARSTRUCT(_var) dbg_internal_vars[DBG_IVARNAME(_var)]
#define DBG_IVAR(_var) (*(DBG_IVARSTRUCT(_var).pval))
#define INTERNAL_VAR(_var,_val,_ref,_typ) DBG_IVARNAME(_var),
enum debug_int_var {
#define INTERNAL_VAR(_var,_val,_ref,itype) DBG_IVARNAME(_var),
enum debug_int_var
{
#include "intvar.h"
DBG_IV_LAST
};
#undef INTERNAL_VAR
/* include CPU dependent bits */
#include "be_cpu.h"
#endif /* __WINE_DEBUGGER_H */

View File

@ -21,178 +21,229 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include "debugger.h"
#include "wine/debug.h"
#include <stdarg.h>
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
#define DISPTAB_DELTA 8 /* needs to be power of 2, search for MARK to see why :) */
/* needs to be power of 2, search for MARK to see why :) */
#define DISPTAB_DELTA 8
struct display {
struct expr *exp;
int count;
char format;
char enabled;
struct name_hash *function_name;
struct display
{
struct expr* exp;
int count;
char format;
char enabled;
char func_buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* func;
};
static struct display *displaypoints = NULL;
static unsigned int maxdisplays = 0, ndisplays = 0;
static struct name_hash *DEBUG_GetCurrentFrameFunctionName(void)
static inline BOOL cmp_symbol(const SYMBOL_INFO* si1, const SYMBOL_INFO* si2)
{
struct name_hash *name;
unsigned int eip, ebp;
if (DEBUG_GetCurrentFrame(&name, &eip, &ebp))
return name;
return NULL;
if (si1->NameLen != si2->NameLen) return FALSE;
return !memcmp(si1, si2, sizeof(SYMBOL_INFO) + si1->NameLen);
}
int DEBUG_AddDisplay(struct expr *exp, int count, char format, int in_frame)
int display_add(struct expr *exp, int count, char format, int in_frame)
{
int i;
int i;
for (i = 0; i < ndisplays; i++)
if (displaypoints[i].exp == NULL)
break;
for (i = 0; i < ndisplays; i++)
if (displaypoints[i].exp == NULL)
break;
if (i == maxdisplays) /* no space left - expand */
displaypoints = DBG_realloc(displaypoints,
(maxdisplays += DISPTAB_DELTA) * sizeof(*displaypoints));
if (i == maxdisplays)
{
/* no space left - expand */
maxdisplays += DISPTAB_DELTA;
displaypoints = dbg_heap_realloc(displaypoints,
maxdisplays * sizeof(*displaypoints));
}
if (i == ndisplays)
++ndisplays;
if (i == ndisplays) ndisplays++;
displaypoints[i].exp = DEBUG_CloneExpr(exp);
displaypoints[i].count = count;
displaypoints[i].format = format;
displaypoints[i].enabled = TRUE;
displaypoints[i].function_name =
(in_frame ? DEBUG_GetCurrentFrameFunctionName() : NULL);
displaypoints[i].exp = expr_clone(exp);
displaypoints[i].count = count;
displaypoints[i].format = format;
displaypoints[i].enabled = TRUE;
if (in_frame)
{
displaypoints[i].func = (SYMBOL_INFO*)displaypoints[i].func_buffer;
displaypoints[i].func->SizeOfStruct = sizeof(SYMBOL_INFO);
displaypoints[i].func->MaxNameLen = sizeof(displaypoints[i].func_buffer) -
sizeof(*displaypoints[i].func);
if (!stack_get_frame(displaypoints[i].func, NULL))
{
expr_free(displaypoints[i].exp);
displaypoints[i].exp = NULL;
return FALSE;
}
}
else displaypoints[i].func = NULL;
return TRUE;
return TRUE;
}
int DEBUG_InfoDisplay(void)
int display_info(void)
{
int i;
int i;
char buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* func;
const char* info;
for (i = 0; i < ndisplays; i++) {
if (displaypoints[i].exp == NULL)
continue;
func = (SYMBOL_INFO*)buffer;
func->SizeOfStruct = sizeof(SYMBOL_INFO);
func->MaxNameLen = sizeof(buffer) - sizeof(*func);
if (!stack_get_frame(func, NULL)) return FALSE;
if (displaypoints[i].function_name)
DEBUG_Printf("%d in %s%s : ", i + 1,
DEBUG_GetSymbolName(displaypoints[i].function_name),
(displaypoints[i].enabled ?
(displaypoints[i].function_name != DEBUG_GetCurrentFrameFunctionName() ?
" (out of scope)" : "")
: " (disabled)")
);
else
DEBUG_Printf("%d%s : ", i + 1,
(displaypoints[i].enabled ? "" : " (disabled)"));
DEBUG_DisplayExpr(displaypoints[i].exp);
DEBUG_Printf("\n");
}
for (i = 0; i < ndisplays; i++)
{
if (displaypoints[i].exp == NULL) continue;
return TRUE;
if (displaypoints[i].enabled)
{
if (displaypoints[i].func && !cmp_symbol(displaypoints[i].func, func))
info = " (out of scope)";
else
info = "";
}
else
info = " (disabled)";
dbg_printf("%d in %s%s: ",
i + 1, func ? displaypoints[i].func->Name : "", info);
expr_print(displaypoints[i].exp);
dbg_printf("\n");
}
return TRUE;
}
void DEBUG_PrintOneDisplay(int i)
static void print_one_display(int i)
{
DBG_VALUE value;
struct dbg_lvalue lvalue;
if (displaypoints[i].enabled) {
value = DEBUG_EvalExpr(displaypoints[i].exp);
if (value.type == NULL) {
DEBUG_Printf("Unable to evaluate expression ");
DEBUG_DisplayExpr(displaypoints[i].exp);
DEBUG_Printf("\nDisabling display %d ...\n", i + 1);
displaypoints[i].enabled = FALSE;
return;
}
}
if (displaypoints[i].enabled)
{
lvalue = expr_eval(displaypoints[i].exp);
if (lvalue.typeid == dbg_itype_none)
{
dbg_printf("Unable to evaluate expression ");
expr_print(displaypoints[i].exp);
dbg_printf("\nDisabling display %d ...\n", i + 1);
displaypoints[i].enabled = FALSE;
return;
}
}
DEBUG_Printf("%d : ", i + 1);
DEBUG_DisplayExpr(displaypoints[i].exp);
DEBUG_Printf(" = ");
if (!displaypoints[i].enabled)
DEBUG_Printf("(disabled)\n");
else
dbg_printf("%d: ", i + 1);
expr_print(displaypoints[i].exp);
dbg_printf(" = ");
if (!displaypoints[i].enabled)
dbg_printf("(disabled)\n");
else
if (displaypoints[i].format == 'i')
DEBUG_ExamineMemory(&value, displaypoints[i].count, displaypoints[i].format);
memory_examine(&lvalue, displaypoints[i].count, displaypoints[i].format);
else
DEBUG_Print(&value, displaypoints[i].count, displaypoints[i].format, 0);
print_value(&lvalue, displaypoints[i].format, 0);
}
int DEBUG_DoDisplay(void)
int display_print(void)
{
int i;
struct name_hash *cur_function_name = DEBUG_GetCurrentFrameFunctionName();
int i;
char buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* func;
for (i = 0; i < ndisplays; i++) {
if (displaypoints[i].exp == NULL || !displaypoints[i].enabled)
continue;
if (displaypoints[i].function_name
&& displaypoints[i].function_name != cur_function_name)
continue;
DEBUG_PrintOneDisplay(i);
}
func = (SYMBOL_INFO*)buffer;
func->SizeOfStruct = sizeof(SYMBOL_INFO);
func->MaxNameLen = sizeof(buffer) - sizeof(*func);
if (!stack_get_frame(func, NULL)) return FALSE;
return TRUE;
for (i = 0; i < ndisplays; i++)
{
if (displaypoints[i].exp == NULL || !displaypoints[i].enabled)
continue;
if (displaypoints[i].func && !cmp_symbol(displaypoints[i].func, func))
continue;
print_one_display(i);
}
return TRUE;
}
int DEBUG_DelDisplay(int displaynum)
int display_delete(int displaynum)
{
int i;
int i;
if (displaynum > ndisplays || displaynum == 0 || displaynum < -1
|| displaypoints[displaynum - 1].exp == NULL) {
DEBUG_Printf("Invalid display number\n");
return TRUE;
}
if (displaynum > ndisplays || displaynum == 0 || displaynum < -1 ||
displaypoints[displaynum - 1].exp == NULL)
{
dbg_printf("Invalid display number\n");
return TRUE;
}
if (displaynum == -1) {
for (i = 0; i < ndisplays; i++) {
if (displaypoints[i].exp != NULL) {
DEBUG_FreeExpr(displaypoints[i].exp);
displaypoints[i].exp = NULL;
}
}
displaypoints = DBG_realloc(displaypoints,
(maxdisplays = DISPTAB_DELTA) * sizeof(*displaypoints));
ndisplays = 0;
} else if (displaypoints[--displaynum].exp != NULL) {
DEBUG_FreeExpr(displaypoints[displaynum].exp);
displaypoints[displaynum].exp = NULL;
while (displaynum == ndisplays - 1
&& displaypoints[displaynum].exp == NULL)
--ndisplays, --displaynum;
if (maxdisplays - ndisplays >= 2 * DISPTAB_DELTA) {
maxdisplays = (ndisplays + DISPTAB_DELTA - 1) & ~(DISPTAB_DELTA - 1); /* MARK */
displaypoints = DBG_realloc(displaypoints,
maxdisplays * sizeof(*displaypoints));
}
}
return TRUE;
if (displaynum == -1)
{
for (i = 0; i < ndisplays; i++)
{
if (displaypoints[i].exp != NULL)
{
expr_free(displaypoints[i].exp);
displaypoints[i].exp = NULL;
}
}
maxdisplays = DISPTAB_DELTA;
displaypoints = dbg_heap_realloc(displaypoints,
(maxdisplays = DISPTAB_DELTA) * sizeof(*displaypoints));
ndisplays = 0;
}
else if (displaypoints[--displaynum].exp != NULL)
{
expr_free(displaypoints[displaynum].exp);
displaypoints[displaynum].exp = NULL;
while (displaynum == ndisplays - 1 && displaypoints[displaynum].exp == NULL)
{
--ndisplays;
--displaynum;
}
if (maxdisplays - ndisplays >= 2 * DISPTAB_DELTA)
{
/* MARK */
maxdisplays = (ndisplays + DISPTAB_DELTA - 1) & ~(DISPTAB_DELTA - 1);
displaypoints = dbg_heap_realloc(displaypoints,
maxdisplays * sizeof(*displaypoints));
}
}
return TRUE;
}
int DEBUG_EnableDisplay(int displaynum, int enable)
int display_enable(int displaynum, int enable)
{
--displaynum;
if (displaynum >= ndisplays || displaynum < 0 || displaypoints[displaynum].exp == NULL) {
DEBUG_Printf("Invalid display number\n");
return TRUE;
}
char buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* func;
displaypoints[displaynum].enabled = enable;
if (!displaypoints[displaynum].function_name
|| displaypoints[displaynum].function_name == DEBUG_GetCurrentFrameFunctionName())
DEBUG_PrintOneDisplay(displaynum);
func = (SYMBOL_INFO*)buffer;
func->SizeOfStruct = sizeof(SYMBOL_INFO);
func->MaxNameLen = sizeof(buffer) - sizeof(*func);
if (!stack_get_frame(func, NULL)) return FALSE;
return TRUE;
--displaynum;
if (displaynum >= ndisplays || displaynum < 0 ||
displaypoints[displaynum].exp == NULL)
{
dbg_printf("Invalid display number\n");
return TRUE;
}
displaypoints[displaynum].enabled = enable;
if (!displaypoints[displaynum].func ||
cmp_symbol(displaypoints[displaynum].func, func))
{
print_one_display(displaynum);
}
return TRUE;
}

View File

@ -1,610 +0,0 @@
/*
* File elf.c - processing of ELF files
*
* Copyright (C) 1996, Eric Youngdale.
* 1999-2004 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#include "debugger.h"
#if defined(__svr4__) || defined(__sun)
#define __ELF__
#endif
#ifdef HAVE_ELF_H
# include <elf.h>
#endif
#ifdef HAVE_SYS_ELF32_H
# include <sys/elf32.h>
#endif
#ifdef HAVE_SYS_EXEC_ELF_H
# include <sys/exec_elf.h>
#endif
#if !defined(DT_NUM)
# if defined(DT_COUNT)
# define DT_NUM DT_COUNT
# else
/* this seems to be a satisfactory value on Solaris, which doesn't support this AFAICT */
# define DT_NUM 24
# endif
#endif
#ifdef HAVE_LINK_H
# include <link.h>
#endif
#ifdef HAVE_SYS_LINK_H
# include <sys/link.h>
#endif
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
typedef struct tagELF_DBG_INFO
{
void *elf_addr;
} ELF_DBG_INFO;
#ifdef __ELF__
/*
* Walk through the entire symbol table and add any symbols we find there.
* This can be used in cases where we have stripped ELF shared libraries,
* or it can be used in cases where we have data symbols for which the address
* isn't encoded in the stabs.
*
* This is all really quite easy, since we don't have to worry about line
* numbers or local data variables.
*/
static int DEBUG_ProcessElfSymtab(DBG_MODULE* module, const char* addr,
void *load_addr, const Elf32_Shdr* symtab,
const Elf32_Shdr* strtab)
{
const char* curfile = NULL;
struct name_hash* curr_sym = NULL;
int flags;
int i;
DBG_VALUE new_value;
int nsym;
const char* strp;
const char* symname;
const Elf32_Sym* symp;
symp = (Elf32_Sym *)(addr + symtab->sh_offset);
nsym = symtab->sh_size / sizeof(*symp);
strp = (char *)(addr + strtab->sh_offset);
for (i = 0; i < nsym; i++, symp++)
{
/*
* Ignore certain types of entries which really aren't of that much
* interest.
*/
if (ELF32_ST_TYPE(symp->st_info) == STT_SECTION ||
symp->st_shndx == SHN_UNDEF)
{
continue;
}
symname = strp + symp->st_name;
/*
* Save the name of the current file, so we have a way of tracking
* static functions/data.
*/
if (ELF32_ST_TYPE(symp->st_info) == STT_FILE)
{
curfile = symname;
continue;
}
new_value.type = NULL;
new_value.addr.seg = 0;
new_value.addr.off = (unsigned long)load_addr + symp->st_value;
new_value.cookie = DV_TARGET;
flags = SYM_WINE | ((ELF32_ST_TYPE(symp->st_info) == STT_FUNC)
? SYM_FUNC : SYM_DATA);
if (ELF32_ST_BIND(symp->st_info) == STB_GLOBAL)
curr_sym = DEBUG_AddSymbol(symname, &new_value, NULL, flags);
else
curr_sym = DEBUG_AddSymbol(symname, &new_value, curfile, flags);
/*
* Record the size of the symbol. This can come in handy in
* some cases. Not really used yet, however.
*/
if (symp->st_size != 0)
DEBUG_SetSymbolSize(curr_sym, symp->st_size);
}
return TRUE;
}
/*
* Loads the symbolic information from ELF module stored in 'filename'
* the module has been loaded at 'load_offset' address, so symbols' address
* relocation is performed
* returns
* -1 if the file cannot be found/opened
* 0 if the file doesn't contain symbolic info (or this info cannot be
* read or parsed)
* 1 on success
*/
enum DbgInfoLoad DEBUG_LoadElfStabs(DBG_MODULE* module)
{
enum DbgInfoLoad dil = DIL_ERROR;
char* addr = (char*)0xffffffff;
int fd = -1;
struct stat statbuf;
const Elf32_Ehdr* ehptr;
const Elf32_Shdr* spnt;
const char* shstrtab;
int i;
int stabsect, stabstrsect, debugsect;
if (module->type != DMT_ELF || !module->elf_dbg_info)
{
WINE_ERR("Bad elf module '%s'\n", module->module_name);
return DIL_ERROR;
}
/* check that the file exists, and that the module hasn't been loaded yet */
if (stat(module->module_name, &statbuf) == -1) goto leave;
if (S_ISDIR(statbuf.st_mode)) goto leave;
/*
* Now open the file, so that we can mmap() it.
*/
if ((fd = open(module->module_name, O_RDONLY)) == -1) goto leave;
dil = DIL_NOINFO;
/*
* Now mmap() the file.
*/
addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (addr == (char*)0xffffffff) goto leave;
/*
* Next, we need to find a few of the internal ELF headers within
* this thing. We need the main executable header, and the section
* table.
*/
ehptr = (Elf32_Ehdr*)addr;
spnt = (Elf32_Shdr*)(addr + ehptr->e_shoff);
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
stabsect = stabstrsect = debugsect = -1;
for (i = 0; i < ehptr->e_shnum; i++)
{
if (strcmp(shstrtab + spnt[i].sh_name, ".stab") == 0)
stabsect = i;
if (strcmp(shstrtab + spnt[i].sh_name, ".stabstr") == 0)
stabstrsect = i;
if (strcmp(shstrtab + spnt[i].sh_name, ".debug_info") == 0)
debugsect = i;
}
if (stabsect != -1 && stabstrsect != -1)
{
/*
* OK, now just parse all of the stabs.
*/
if (DEBUG_ParseStabs(addr,
module->elf_dbg_info->elf_addr,
spnt[stabsect].sh_offset,
spnt[stabsect].sh_size,
spnt[stabstrsect].sh_offset,
spnt[stabstrsect].sh_size))
{
dil = DIL_LOADED;
}
else
{
dil = DIL_ERROR;
WINE_WARN("Couldn't read correctly read stabs\n");
goto leave;
}
}
else if (debugsect != -1)
{
/* Dwarf 2 debug information */
dil = DIL_NOT_SUPPORTED;
}
/* now load dynamic symbol info */
for (i = 0; i < ehptr->e_shnum; i++)
{
if ((strcmp(shstrtab + spnt[i].sh_name, ".symtab") == 0) &&
(spnt[i].sh_type == SHT_SYMTAB))
DEBUG_ProcessElfSymtab(module, addr, module->elf_dbg_info->elf_addr,
spnt + i, spnt + spnt[i].sh_link);
if ((strcmp(shstrtab + spnt[i].sh_name, ".dynsym") == 0) &&
(spnt[i].sh_type == SHT_DYNSYM))
DEBUG_ProcessElfSymtab(module, addr, module->elf_dbg_info->elf_addr,
spnt + i, spnt + spnt[i].sh_link);
}
leave:
if (addr != (char*)0xffffffff) munmap(addr, statbuf.st_size);
if (fd != -1) close(fd);
return dil;
}
static unsigned is_dt_flag_valid(unsigned d_tag)
{
#ifndef DT_PROCNUM
#define DT_PROCNUM 0
#endif
#ifndef DT_EXTRANUM
#define DT_EXTRANUM 0
#endif
return (d_tag >= 0 && d_tag < DT_NUM + DT_PROCNUM + DT_EXTRANUM)
#if defined(DT_LOOS) && defined(DT_HIOS)
|| (d_tag >= DT_LOOS && d_tag < DT_HIOS)
#endif
#if defined(DT_LOPROC) && defined(DT_HIPROC)
|| (d_tag >= DT_LOPROC && d_tag < DT_HIPROC)
#endif
;
}
/*
* Loads the information for ELF module stored in 'filename'
* the module has been loaded at 'load_offset' address
* returns
* -1 if the file cannot be found/opened
* 0 if the file doesn't contain symbolic info (or this info cannot be
* read or parsed)
* 1 on success
*/
static enum DbgInfoLoad DEBUG_ProcessElfFile(HANDLE hProcess,
const char* filename,
void *load_offset,
struct elf_info* elf_info)
{
static const unsigned char elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
enum DbgInfoLoad dil = DIL_ERROR;
const char* addr = (char*)0xffffffff;
int fd = -1;
struct stat statbuf;
const Elf32_Ehdr* ehptr;
const Elf32_Shdr* spnt;
const Elf32_Phdr* ppnt;
const char* shstrtab;
int i;
DWORD delta;
WINE_TRACE("Processing elf file '%s' at %p\n", filename, load_offset);
/* check that the file exists, and that the module hasn't been loaded yet */
if (stat(filename, &statbuf) == -1) goto leave;
/*
* Now open the file, so that we can mmap() it.
*/
if ((fd = open(filename, O_RDONLY)) == -1) goto leave;
/*
* Now mmap() the file.
*/
addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (addr == (char*)-1) goto leave;
dil = DIL_NOINFO;
/*
* Next, we need to find a few of the internal ELF headers within
* this thing. We need the main executable header, and the section
* table.
*/
ehptr = (Elf32_Ehdr*)addr;
if (memcmp(ehptr->e_ident, elf_signature, sizeof(elf_signature))) goto leave;
spnt = (Elf32_Shdr*)(addr + ehptr->e_shoff);
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
/* if non relocatable ELF, then remove fixed address from computation
* otherwise, all addresses are zero based
*/
delta = (load_offset == 0) ? ehptr->e_entry : 0;
/* grab size of module once loaded in memory */
ppnt = (Elf32_Phdr*)(addr + ehptr->e_phoff);
elf_info->size = 0;
for (i = 0; i < ehptr->e_phnum; i++)
{
if (ppnt[i].p_type != PT_LOAD) continue;
elf_info->size += (ppnt[i].p_align <= 1) ? ppnt[i].p_memsz :
(ppnt[i].p_memsz + ppnt[i].p_align - 1) & ~(ppnt[i].p_align - 1);
}
for (i = 0; i < ehptr->e_shnum; i++)
{
if (strcmp(shstrtab + spnt[i].sh_name, ".dynamic") == 0 &&
spnt[i].sh_type == SHT_DYNAMIC)
{
if (elf_info->flags & ELF_INFO_DEBUG_HEADER)
{
Elf32_Dyn dyn;
char* ptr = (char*)spnt[i].sh_addr;
unsigned long len;
do
{
if (!ReadProcessMemory(hProcess, ptr, &dyn, sizeof(dyn), &len) ||
len != sizeof(dyn) || !is_dt_flag_valid(dyn.d_tag))
dyn.d_tag = DT_NULL;
ptr += sizeof(dyn);
} while (dyn.d_tag != DT_DEBUG && dyn.d_tag != DT_NULL);
if (dyn.d_tag == DT_NULL)
{
dil = DIL_ERROR;
goto leave;
}
elf_info->dbg_hdr_addr = dyn.d_un.d_ptr;
}
}
}
elf_info->segments[0] = elf_info->segments[1] = elf_info->segments[2] = 0;
if (elf_info->flags & ELF_INFO_PATH)
{
strncpy(elf_info->elf_path, filename, elf_info->elf_path_len);
elf_info->elf_path[elf_info->elf_path_len - 1] = '\0';
}
elf_info->load_addr = (load_offset == 0) ? (void *)ehptr->e_entry : load_offset;
if (elf_info->flags & ELF_INFO_MODULE)
{
DBG_MODULE* module;
module = DEBUG_AddModule(filename, DMT_ELF, elf_info->load_addr, elf_info->size, 0);
if (module)
{
if ((module->elf_dbg_info = DBG_alloc(sizeof(ELF_DBG_INFO))) == NULL)
{
WINE_ERR("OOM\n");
exit(0);
}
module->elf_dbg_info->elf_addr = load_offset;
module->dil = dil = DEBUG_LoadElfStabs(module);
}
else dil = DIL_ERROR;
}
leave:
if (addr != (char*)0xffffffff) munmap((void*)addr, statbuf.st_size);
if (fd != -1) close(fd);
return dil;
}
static enum DbgInfoLoad DEBUG_ProcessElfFileFromPath(HANDLE hProcess,
const char * filename,
void *load_offset,
const char* path,
struct elf_info* elf_info)
{
enum DbgInfoLoad dil = DIL_ERROR;
char *s, *t, *fn;
char* paths = NULL;
if (!path) return dil;
for (s = paths = DBG_strdup(path); s && *s; s = (t) ? (t+1) : NULL)
{
t = strchr(s, ':');
if (t) *t = '\0';
fn = (char*)DBG_alloc(strlen(filename) + 1 + strlen(s) + 1);
if (!fn) break;
strcpy(fn, s );
strcat(fn, "/");
strcat(fn, filename);
dil = DEBUG_ProcessElfFile(hProcess, fn, load_offset, elf_info);
DBG_free(fn);
if (dil != DIL_ERROR) break;
s = (t) ? (t+1) : NULL;
}
DBG_free(paths);
return dil;
}
static enum DbgInfoLoad DEBUG_ProcessElfObject(HANDLE hProcess,
const char* filename,
void *load_offset,
struct elf_info* elf_info)
{
enum DbgInfoLoad dil = DIL_ERROR;
if (filename == NULL || *filename == '\0') return DIL_ERROR;
if (DEBUG_FindModuleByName(filename, DMT_ELF))
{
assert(!(elf_info->flags & ELF_INFO_PATH));
return DIL_LOADED;
}
if (strstr(filename, "libstdc++")) return DIL_ERROR; /* We know we can't do it */
dil = DEBUG_ProcessElfFile(hProcess, filename, load_offset, elf_info);
/* if relative pathname, try some absolute base dirs */
if (dil == DIL_ERROR && !strchr(filename, '/'))
{
dil = DEBUG_ProcessElfFileFromPath(hProcess, filename, load_offset,
getenv("PATH"), elf_info);
if (dil == DIL_ERROR)
dil = DEBUG_ProcessElfFileFromPath(hProcess, filename, load_offset,
getenv("LD_LIBRARY_PATH"), elf_info);
if (dil == DIL_ERROR)
dil = DEBUG_ProcessElfFileFromPath(hProcess, filename, load_offset,
getenv("WINEDLLPATH"), elf_info);
}
DEBUG_ReportDIL(dil, "ELF", filename, load_offset);
return dil;
}
static BOOL DEBUG_WalkList(const struct r_debug* dbg_hdr)
{
void* lm_addr;
struct link_map lm;
char bufstr[256];
struct elf_info elf_info;
elf_info.flags = ELF_INFO_MODULE;
/*
* Now walk the linked list. In all known ELF implementations,
* the dynamic loader maintains this linked list for us. In some
* cases the first entry doesn't appear with a name, in other cases it
* does.
*/
for (lm_addr = (void *)dbg_hdr->r_map; lm_addr; lm_addr = (void *)lm.l_next)
{
if (!DEBUG_READ_MEM_VERBOSE(lm_addr, &lm, sizeof(lm)))
return FALSE;
if (lm.l_prev != NULL && /* skip first entry, normally debuggee itself */
lm.l_name != NULL &&
DEBUG_READ_MEM_VERBOSE((void*)lm.l_name, bufstr, sizeof(bufstr)))
{
bufstr[sizeof(bufstr) - 1] = '\0';
DEBUG_ProcessElfObject(DEBUG_CurrProcess->handle, bufstr,
(void *)lm.l_addr, &elf_info);
}
}
return TRUE;
}
static BOOL DEBUG_RescanElf(void)
{
struct r_debug dbg_hdr;
if (DEBUG_CurrProcess &&
DEBUG_READ_MEM_VERBOSE((void*)DEBUG_CurrProcess->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr)))
{
switch (dbg_hdr.r_state)
{
case RT_CONSISTENT:
DEBUG_WalkList(&dbg_hdr);
DEBUG_CheckDelayedBP();
break;
case RT_ADD:
break;
case RT_DELETE:
/* FIXME: this is not currently handled */
break;
}
}
return FALSE;
}
/******************************************************************
* DEBUG_ReadWineLoaderDbgInfo
*
* Try to find a decent wine executable which could have loader the debuggee
*/
enum DbgInfoLoad DEBUG_ReadWineLoaderDbgInfo(HANDLE hProcess, struct elf_info* elf_info)
{
const char* ptr;
enum DbgInfoLoad dil;
/* All binaries are loaded with WINELOADER (if run from tree) or by the
* main executable (either wine-kthread or wine-pthread)
* Note: the heuristic used to know whether we need to load wine-pthread or
* wine-kthread is not 100% safe
*/
elf_info->flags |= ELF_INFO_DEBUG_HEADER;
if ((ptr = getenv("WINELOADER")))
dil = DEBUG_ProcessElfObject(hProcess, ptr, 0, elf_info);
else
{
if ((dil = DEBUG_ProcessElfObject(hProcess, "wine-kthread", 0, elf_info)) == DIL_ERROR)
dil = DEBUG_ProcessElfObject(hProcess, "wine-pthread", 0, elf_info);
}
return dil;
}
/******************************************************************
* DEBUG_SetElfSoLoadBreakpoint
*
* Sets a breakpoint to handle .so loading events, so we can add debug info
* on the fly
*/
BOOL DEBUG_SetElfSoLoadBreakpoint(const struct elf_info* elf_info)
{
struct r_debug dbg_hdr;
/*
* OK, now dig into the actual tables themselves.
*/
if (!DEBUG_READ_MEM_VERBOSE((void*)elf_info->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr)))
return FALSE;
assert(!DEBUG_CurrProcess->dbg_hdr_addr);
DEBUG_CurrProcess->dbg_hdr_addr = elf_info->dbg_hdr_addr;
if (dbg_hdr.r_brk)
{
DBG_VALUE value;
WINE_TRACE("Setting up a breakpoint on r_brk(%lx)\n",
(unsigned long)dbg_hdr.r_brk);
DEBUG_SetBreakpoints(FALSE);
value.type = NULL;
value.cookie = DV_TARGET;
value.addr.seg = 0;
value.addr.off = (DWORD)dbg_hdr.r_brk;
DEBUG_AddBreakpoint(&value, DEBUG_RescanElf, TRUE);
DEBUG_SetBreakpoints(TRUE);
}
return DEBUG_WalkList(&dbg_hdr);
}
#else /* !__ELF__ */
enum DbgInfoLoad DEBUG_ReadWineLoaderDbgInfo(HANDLE hProcess, struct elf_info* elf_info)
{
return DIL_ERROR;
}
BOOL DEBUG_SetElfSoLoadBreakpoint(const struct elf_info* elf_info)
{
return FALSE;
}
#endif /* __ELF__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,161 +0,0 @@
/*
* Convenience functions to handle use of external debugger.
*
* Copyright 1999 Kevin Holbrook
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "wine/port.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define DBG_BUFF_SIZE 12
#define DBG_EXTERNAL_DEFAULT "gdb"
#define DBG_LOCATION_DEFAULT "/usr/local/bin/wine"
#define DBG_SLEEPTIME_DEFAULT 120
/* DEBUG_ExternalDebugger
*
* This function invokes an external debugger on the current
* wine process. The form of the command executed is:
* <debugger image> <wine image> <attach process id>
*
* The debugger command is normally invoked by a newly created xterm.
*
* The current calling process is temporarily put to sleep
* so that the invoked debugger has time to come up and attach.
*
* The following environment variables may be used:
*
* Name Use Default
* -------------------------------------------------------------------------------------
* WINE_DBG_EXTERNAL debugger command to invoke ("gdb")
* WINE_DBG_LOCATION fully qualified location of wine image ("/usr/local/bin/wine")
* WINE_DBG_NO_XTERM if set do not invoke xterm with command (not set)
* WINE_DBG_SLEEPTIME number of seconds to make process sleep (120)
*
*
* Usage:
*
* #include "wine/debug.h"
*
* DEBUG_ExternalDebugger();
*
*
* Environment Example:
*
* export WINE_DBG_EXTERNAL="ddd"
* export WINE_DBG_NO_XTERM=1
* export WINE_DBG_SLEEPTIME=60
*
*/
void DEBUG_ExternalDebugger(void)
{
pid_t attach_pid;
pid_t child_pid;
int dbg_sleep_secs = DBG_SLEEPTIME_DEFAULT;
char *dbg_sleeptime;
dbg_sleeptime = getenv("WINE_DBG_SLEEPTIME");
/* convert sleep time string to integer seconds */
if (dbg_sleeptime)
{
dbg_sleep_secs = atoi(dbg_sleeptime);
/* check for conversion error */
if (dbg_sleep_secs == 0)
dbg_sleep_secs = DBG_SLEEPTIME_DEFAULT;
}
/* get the current process id */
attach_pid = getpid();
/* create new process */
child_pid = fork();
/* check if we are the child process */
if (child_pid == 0)
{
int status;
const char *dbg_external;
const char *dbg_wine_location;
const char *dbg_no_xterm;
char pid_string[DBG_BUFF_SIZE];
/* check settings in environment for debugger to use */
dbg_external = getenv("WINE_DBG_EXTERNAL");
dbg_wine_location = getenv("WINE_DBG_LOCATION");
dbg_no_xterm = getenv("WINE_DBG_NO_XTERM");
/* if not set in environment, use default */
if (!dbg_external)
dbg_external = "gdb";
/* if not set in environment, use default */
if (!dbg_wine_location)
if (!(dbg_wine_location = getenv("WINELOADER")))
dbg_wine_location = "miscemu/wine";
/* check for empty string in WINE_DBG_NO_XTERM */
if (dbg_no_xterm && (strlen(dbg_no_xterm) < 1))
dbg_no_xterm = NULL;
/* clear the buffer */
memset(pid_string, 0, DBG_BUFF_SIZE);
/* make pid into string */
snprintf(pid_string, sizeof(pid_string), "%ld", (long) attach_pid);
/* now exec the debugger to get it's own clean memory space */
if (dbg_no_xterm)
status = execlp(dbg_external, dbg_external, dbg_wine_location, pid_string, NULL);
else
status = execlp("xterm", "xterm", "-e", dbg_external, dbg_wine_location, pid_string, NULL);
if (status == -1)
{
if (dbg_no_xterm)
fprintf(stderr, "DEBUG_ExternalDebugger failed to execute \"%s %s %s\" (%s)\n",
dbg_external, dbg_wine_location, pid_string, strerror(errno));
else
fprintf(stderr, "DEBUG_ExternalDebugger failed to execute \"xterm -e %s %s %s\" (%s)\n",
dbg_external, dbg_wine_location, pid_string, strerror(errno));
}
}
else if (child_pid != -1)
{
/* make the parent/caller sleep so the child/debugger can catch it */
sleep(dbg_sleep_secs);
}
else
fprintf(stderr, "DEBUG_ExternalDebugger failed.\n");
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -20,52 +20,16 @@
*/
/* break handling */
INTERNAL_VAR(BreakAllThreadsStartup, FALSE, NULL, DT_BASIC_CONST_INT)
INTERNAL_VAR(BreakOnCritSectTimeOut, FALSE, NULL, DT_BASIC_CONST_INT)
INTERNAL_VAR(BreakOnAttach, FALSE, NULL, DT_BASIC_CONST_INT)
INTERNAL_VAR(BreakOnFirstChance, TRUE, NULL, DT_BASIC_CONST_INT)
INTERNAL_VAR(BreakOnDllLoad, FALSE, NULL, DT_BASIC_CONST_INT)
INTERNAL_VAR(CanDeferOnBPByAddr, FALSE, NULL, DT_BASIC_CONST_INT)
/* debugging debugger */
INTERNAL_VAR(ExtDbgOnInvalidAddress, FALSE, NULL, DT_BASIC_CONST_INT)
INTERNAL_VAR(ExtDbgOnInternalException, FALSE, NULL, DT_BASIC_CONST_INT)
INTERNAL_VAR(BreakAllThreadsStartup, FALSE, NULL, dbg_itype_unsigned_int)
INTERNAL_VAR(BreakOnCritSectTimeOut, FALSE, NULL, dbg_itype_unsigned_int)
INTERNAL_VAR(BreakOnAttach, FALSE, NULL, dbg_itype_unsigned_int)
INTERNAL_VAR(BreakOnFirstChance, TRUE, NULL, dbg_itype_unsigned_int)
INTERNAL_VAR(BreakOnDllLoad, FALSE, NULL, dbg_itype_unsigned_int)
INTERNAL_VAR(CanDeferOnBPByAddr, FALSE, NULL, dbg_itype_unsigned_int)
/* current process/thread */
INTERNAL_VAR(ThreadId, FALSE, &DEBUG_CurrTid, DT_BASIC_CONST_INT)
INTERNAL_VAR(ProcessId, FALSE, &DEBUG_CurrPid, DT_BASIC_CONST_INT)
INTERNAL_VAR(ThreadId, FALSE, &dbg_curr_tid, dbg_itype_unsigned_int)
INTERNAL_VAR(ProcessId, FALSE, &dbg_curr_pid, dbg_itype_unsigned_int)
/* context manipulation */
#ifdef __i386__
/* FIXME: 16 bit registers use imply that CPU is little endian, which is
* the case when running natively i386 code
*/
INTERNAL_VAR(eip, 0, &DEBUG_context.Eip, DT_BASIC_CONST_INT)
INTERNAL_VAR(ip, 0, &DEBUG_context.Eip, DT_BASIC_USHORTINT)
INTERNAL_VAR(pc, 0, &DEBUG_context.Eip, DT_BASIC_CONST_INT)
INTERNAL_VAR(flags, 0, &DEBUG_context.EFlags, DT_BASIC_CONST_INT)
INTERNAL_VAR(esp, 0, &DEBUG_context.Esp, DT_BASIC_CONST_INT)
INTERNAL_VAR(sp, 0, &DEBUG_context.Esp, DT_BASIC_USHORTINT)
INTERNAL_VAR(eax, 0, &DEBUG_context.Eax, DT_BASIC_CONST_INT)
INTERNAL_VAR(ax, 0, &DEBUG_context.Eax, DT_BASIC_USHORTINT)
INTERNAL_VAR(ebx, 0, &DEBUG_context.Ebx, DT_BASIC_CONST_INT)
INTERNAL_VAR(bx, 0, &DEBUG_context.Ebx, DT_BASIC_USHORTINT)
INTERNAL_VAR(ecx, 0, &DEBUG_context.Ecx, DT_BASIC_CONST_INT)
INTERNAL_VAR(cx, 0, &DEBUG_context.Ecx, DT_BASIC_USHORTINT)
INTERNAL_VAR(edx, 0, &DEBUG_context.Edx, DT_BASIC_CONST_INT)
INTERNAL_VAR(dx, 0, &DEBUG_context.Edx, DT_BASIC_USHORTINT)
INTERNAL_VAR(esi, 0, &DEBUG_context.Esi, DT_BASIC_CONST_INT)
INTERNAL_VAR(si, 0, &DEBUG_context.Esi, DT_BASIC_USHORTINT)
INTERNAL_VAR(edi, 0, &DEBUG_context.Edi, DT_BASIC_CONST_INT)
INTERNAL_VAR(di, 0, &DEBUG_context.Edi, DT_BASIC_USHORTINT)
INTERNAL_VAR(ebp, 0, &DEBUG_context.Ebp, DT_BASIC_CONST_INT)
INTERNAL_VAR(bp, 0, &DEBUG_context.Ebp, DT_BASIC_USHORTINT)
INTERNAL_VAR(es, 0, &DEBUG_context.SegEs, DT_BASIC_CONST_INT)
INTERNAL_VAR(ds, 0, &DEBUG_context.SegDs, DT_BASIC_CONST_INT)
INTERNAL_VAR(cs, 0, &DEBUG_context.SegCs, DT_BASIC_CONST_INT)
INTERNAL_VAR(ss, 0, &DEBUG_context.SegSs, DT_BASIC_CONST_INT)
INTERNAL_VAR(fs, 0, &DEBUG_context.SegFs, DT_BASIC_CONST_INT)
INTERNAL_VAR(gs, 0, &DEBUG_context.SegGs, DT_BASIC_CONST_INT)
INTERNAL_VAR(regs, 0, (DWORD*)&DEBUG_context, DT_BASIC_CONTEXT)
#endif
/* symbol manipulation */
INTERNAL_VAR(AlwaysShowThunks, FALSE, NULL, dbg_itype_unsigned_int)

View File

@ -3,7 +3,7 @@
*
* Copyright 1993 Eric Youngdale
* Copyright 1995 Alexandre Julliard
* Copyright 2000 Eric Pouech
* Copyright 2000-2004 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -25,371 +25,581 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "debugger.h"
#include "winbase.h"
#include "wine/debug.h"
#ifdef __i386__
#define IS_VM86_MODE() (DEBUG_context.EFlags & V86_FLAG)
#endif
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
static void DEBUG_Die(const char* msg)
void* be_cpu_linearize(HANDLE hThread, const ADDRESS* addr)
{
DEBUG_Printf(msg);
exit(1);
assert(addr->Mode == AddrModeFlat);
return (void*)addr->Offset;
}
void* DBG_alloc(size_t size)
unsigned be_cpu_build_addr(HANDLE hThread, const CONTEXT* ctx, ADDRESS* addr,
unsigned seg, unsigned long offset)
{
void *res = malloc(size ? size : 1);
if (res == NULL)
DEBUG_Die("Memory exhausted.\n");
memset(res, 0, size);
return res;
addr->Mode = AddrModeFlat;
addr->Segment = 0; /* don't need segment */
addr->Offset = offset;
return TRUE;
}
void* DBG_realloc(void *ptr, size_t size)
void* memory_to_linear_addr(const ADDRESS* addr)
{
void* res = realloc(ptr, size);
if ((res == NULL) && size)
DEBUG_Die("Memory exhausted.\n");
return res;
return be_cpu->linearize(dbg_curr_thread->handle, addr);
}
char* DBG_strdup(const char *str)
BOOL memory_get_current_pc(ADDRESS* addr)
{
char *res = strdup(str);
if (!res)
DEBUG_Die("Memory exhausted.\n");
return res;
assert(be_cpu->get_addr);
return be_cpu->get_addr(dbg_curr_thread->handle, &dbg_context,
be_cpu_addr_pc, addr);
}
void DBG_free(void *ptr)
BOOL memory_get_current_stack(ADDRESS* addr)
{
free(ptr);
assert(be_cpu->get_addr);
return be_cpu->get_addr(dbg_curr_thread->handle, &dbg_context,
be_cpu_addr_stack, addr);
}
enum dbg_mode DEBUG_GetSelectorType( WORD sel )
BOOL memory_get_current_frame(ADDRESS* addr)
{
#ifdef __i386__
LDT_ENTRY le;
if (IS_VM86_MODE()) return MODE_VM86;
if (sel == 0) return MODE_32;
if (GetThreadSelectorEntry( DEBUG_CurrThread->handle, sel, &le))
return le.HighWord.Bits.Default_Big ? MODE_32 : MODE_16;
/* selector doesn't exist */
return MODE_INVALID;
#else
return MODE_32;
#endif
}
#ifdef __i386__
void DEBUG_FixAddress( DBG_ADDR *addr, DWORD def)
{
if (addr->seg == 0xffffffff) addr->seg = def;
if (DEBUG_IsSelectorSystem(addr->seg)) addr->seg = 0;
assert(be_cpu->get_addr);
return be_cpu->get_addr(dbg_curr_thread->handle, &dbg_context,
be_cpu_addr_frame, addr);
}
/* Determine if sel is a system selector (i.e. not managed by Wine) */
BOOL DEBUG_IsSelectorSystem(WORD sel)
void memory_report_invalid_addr(const void* addr)
{
if (IS_VM86_MODE()) return FALSE; /* no system selectors in vm86 mode */
return !(sel & 4) || ((sel >> 3) < 17);
}
#endif /* __i386__ */
ADDRESS address;
DWORD DEBUG_ToLinear( const DBG_ADDR *addr )
{
#ifdef __i386__
LDT_ENTRY le;
if (IS_VM86_MODE()) return (DWORD)(LOWORD(addr->seg) << 4) + addr->off;
if (DEBUG_IsSelectorSystem(addr->seg))
return addr->off;
if (GetThreadSelectorEntry( DEBUG_CurrThread->handle, addr->seg, &le)) {
return (le.HighWord.Bits.BaseHi << 24) + (le.HighWord.Bits.BaseMid << 16) + le.BaseLow + addr->off;
}
return 0;
#else
return addr->off;
#endif
}
void DEBUG_GetCurrentAddress( DBG_ADDR *addr )
{
#ifdef __i386__
addr->seg = DEBUG_context.SegCs;
if (DEBUG_IsSelectorSystem(addr->seg))
addr->seg = 0;
addr->off = DEBUG_context.Eip;
#elif defined(__sparc__)
addr->seg = 0;
addr->off = DEBUG_context.pc;
#elif defined(__powerpc__)
addr->seg = 0;
addr->off = DEBUG_context.Iar;
#else
# error You must define GET_IP for this CPU
#endif
}
void DEBUG_InvalAddr( const DBG_ADDR* addr )
{
DEBUG_Printf("*** Invalid address ");
DEBUG_PrintAddress(addr, DEBUG_CurrThread ? DEBUG_CurrThread->dbg_mode : MODE_32, FALSE);
DEBUG_Printf("\n");
if (DBG_IVAR(ExtDbgOnInvalidAddress)) DEBUG_ExternalDebugger();
}
void DEBUG_InvalLinAddr( void* addr )
{
DBG_ADDR address;
address.seg = 0;
address.off = (unsigned long)addr;
DEBUG_InvalAddr( &address );
address.Mode = AddrModeFlat;
address.Segment = 0;
address.Offset = (unsigned long)addr;
dbg_printf("*** Invalid address ");
print_address(&address, FALSE);
dbg_printf("\n");
}
/***********************************************************************
* DEBUG_ReadMemory
* memory_read_value
*
* Read a memory value.
*/
/* FIXME: this function is now getting closer and closer to
* DEBUG_ExprGetValue. They should be merged...
*/
int DEBUG_ReadMemory( const DBG_VALUE* val )
BOOL memory_read_value(const struct dbg_lvalue* lvalue, DWORD size, void* result)
{
int value = 0; /* to clear any unused byte */
int os = DEBUG_GetObjectSize(val->type);
assert(sizeof(value) >= os);
/* FIXME: only works on little endian systems */
if (val->cookie == DV_TARGET) {
DBG_ADDR addr = val->addr;
void* lin;
#ifdef __i386__
DEBUG_FixAddress( &addr, DEBUG_context.SegDs );
#endif
lin = (void*)DEBUG_ToLinear( &addr );
DEBUG_READ_MEM_VERBOSE(lin, &value, os);
} else {
if (val->addr.off)
memcpy(&value, (void*)val->addr.off, os);
if (lvalue->cookie == DLV_TARGET)
{
if (!dbg_read_memory_verbose(memory_to_linear_addr(&lvalue->addr), result, size))
return FALSE;
}
return value;
}
/***********************************************************************
* DEBUG_WriteMemory
*
* Store a value in memory.
*/
void DEBUG_WriteMemory( const DBG_VALUE* val, int value )
{
int os = DEBUG_GetObjectSize(val->type);
assert(sizeof(value) >= os);
/* FIXME: only works on little endian systems */
if (val->cookie == DV_TARGET) {
DBG_ADDR addr = val->addr;
void* lin;
#ifdef __i386__
DEBUG_FixAddress( &addr, DEBUG_context.SegDs );
#endif
lin = (void*)DEBUG_ToLinear( &addr );
DEBUG_WRITE_MEM_VERBOSE(lin, &value, os);
} else {
memcpy((void*)val->addr.off, &value, os);
}
}
/***********************************************************************
* DEBUG_GrabAddress
*
* Get the address from a value
*/
BOOL DEBUG_GrabAddress( DBG_VALUE* value, BOOL fromCode )
{
assert(value->cookie == DV_TARGET || value->cookie == DV_HOST);
#ifdef __i386__
DEBUG_FixAddress( &value->addr,
(fromCode) ? DEBUG_context.SegCs : DEBUG_context.SegDs);
#endif
/*
* Dereference pointer to get actual memory address we need to be
* reading. We will use the same segment as what we have already,
* and hope that this is a sensible thing to do.
*/
if (value->type != NULL) {
if (value->type == DEBUG_GetBasicType(DT_BASIC_CONST_INT)) {
/*
* We know that we have the actual offset stored somewhere
* else in 32-bit space. Grab it, and we
* should be all set.
*/
unsigned int seg2 = value->addr.seg;
value->addr.seg = 0;
value->addr.off = DEBUG_GetExprValue(value, NULL);
value->addr.seg = seg2;
} else {
struct datatype * testtype;
if (DEBUG_TypeDerefPointer(value, &testtype) == 0)
return FALSE;
if (testtype != NULL || value->type == DEBUG_GetBasicType(DT_BASIC_CONST_INT))
value->addr.off = DEBUG_GetExprValue(value, NULL);
}
} else if (!value->addr.seg && !value->addr.off) {
DEBUG_Printf("Invalid expression\n");
return FALSE;
else
{
assert(lvalue->addr.Mode == AddrModeFlat);
if (!lvalue->addr.Offset) return FALSE;
memcpy(result, (void*)lvalue->addr.Offset, size);
}
return TRUE;
}
/***********************************************************************
* DEBUG_ExamineMemory
* memory_write_value
*
* Store a value in memory.
*/
BOOL memory_write_value(const struct dbg_lvalue* lvalue, DWORD size, void* value)
{
BOOL ret = TRUE;
DWORD os;
DWORD linear = (DWORD)memory_to_linear_addr(&lvalue->addr);
os = ~size;
types_get_info(linear, lvalue->typeid, TI_GET_LENGTH, &os);
assert(size == os);
/* FIXME: only works on little endian systems */
if (lvalue->cookie == DLV_TARGET)
{
ret = dbg_write_memory_verbose((void*)linear, value, size);
}
else
{
assert(lvalue->addr.Mode == AddrModeFlat);
memcpy((void*)lvalue->addr.Offset, value, size);
}
return ret;
}
/***********************************************************************
* memory_examine
*
* Implementation of the 'x' command.
*/
void DEBUG_ExamineMemory( const DBG_VALUE *_value, int count, char format )
void memory_examine(const struct dbg_lvalue* lvalue, int count, char format)
{
DBG_VALUE value = *_value;
int i;
unsigned char * pnt;
if (!DEBUG_GrabAddress(&value, (format == 'i'))) return;
int i;
ADDRESS x;
char buffer[256];
x.Mode = AddrModeFlat;
x.Offset = types_extract_as_integer(lvalue);
if (format != 'i' && count > 1)
{
DEBUG_PrintAddress( &value.addr, DEBUG_CurrThread->dbg_mode, FALSE );
DEBUG_Printf(": ");
print_address(&x, FALSE);
dbg_printf(": ");
}
pnt = (void*)DEBUG_ToLinear( &value.addr );
switch(format)
switch (format)
{
case 'u':
if (count == 1) count = 256;
DEBUG_nchar += DEBUG_PrintStringW(&value.addr, count);
DEBUG_Printf("\n");
return;
case 's':
if (count == 1) count = 256;
DEBUG_nchar += DEBUG_PrintStringA(&value.addr, count);
DEBUG_Printf("\n");
return;
case 'i':
while (count-- && DEBUG_DisassembleInstruction( &value.addr ));
return;
case 'g':
while (count--)
{
GUID guid;
if (!DEBUG_READ_MEM_VERBOSE(pnt, &guid, sizeof(guid))) break;
DEBUG_Printf("{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] );
pnt += sizeof(guid);
value.addr.off += sizeof(guid);
if (count)
{
DEBUG_PrintAddress( &value.addr, DEBUG_CurrThread->dbg_mode, FALSE );
DEBUG_Printf(": ");
}
}
return;
case 'u':
if (count == 1) count = 256;
memory_get_string(dbg_curr_thread->handle, (void*)x.Offset, lvalue->cookie,
TRUE, buffer, min(count, sizeof(buffer)));
dbg_printf("%s\n", buffer);
return;
case 's':
if (count == 1) count = 256;
memory_get_string(dbg_curr_thread->handle, (void*)x.Offset, lvalue->cookie,
FALSE, buffer, min(count, sizeof(buffer)));
dbg_printf("%s\n", buffer);
return;
case 'i':
while (count-- && memory_disasm_one_insn(&x));
return;
case 'g':
while (count--)
{
GUID guid;
if (!dbg_read_memory_verbose((void*)x.Offset, &guid, sizeof(guid))) break;
dbg_printf("{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
x.Offset += sizeof(guid);
if (count)
{
print_address(&x, FALSE);
dbg_printf(": ");
}
}
return;
#define DO_DUMP2(_t,_l,_f,_vv) { \
_t _v; \
for(i=0; i<count; i++) { \
if (!DEBUG_READ_MEM_VERBOSE(pnt, &_v, sizeof(_t))) break; \
DEBUG_Printf(_f,(_vv)); \
pnt += sizeof(_t); value.addr.off += sizeof(_t); \
if ((i % (_l)) == (_l)-1) { \
DEBUG_Printf("\n"); \
DEBUG_PrintAddress( &value.addr, DEBUG_CurrThread->dbg_mode, FALSE );\
DEBUG_Printf(": ");\
} \
} \
DEBUG_Printf("\n"); \
} \
#define DO_DUMP2(_t,_l,_f,_vv) { \
_t _v; \
for (i = 0; i < count; i++) { \
if (!dbg_read_memory_verbose((void*)x.Offset, &_v, \
sizeof(_t))) break; \
dbg_printf(_f, (_vv)); \
x.Offset += sizeof(_t); \
if ((i % (_l)) == (_l) - 1) { \
dbg_printf("\n"); \
print_address(&x, FALSE); \
dbg_printf(": "); \
} \
} \
dbg_printf("\n"); \
} \
return
#define DO_DUMP(_t,_l,_f) DO_DUMP2(_t,_l,_f,_v)
case 'x': DO_DUMP(int, 4, " %8.8x");
case 'd': DO_DUMP(unsigned int, 4, " %10d");
case 'w': DO_DUMP(unsigned short, 8, " %04x");
case 'c': DO_DUMP2(char, 32, " %c", (_v < 0x20) ? ' ' : _v);
case 'b': DO_DUMP2(char, 16, " %02x", (_v) & 0xff);
}
case 'x': DO_DUMP(int, 4, " %8.8x");
case 'd': DO_DUMP(unsigned int, 4, " %10d");
case 'w': DO_DUMP(unsigned short, 8, " %04x");
case 'c': DO_DUMP2(char, 32, " %c", (_v < 0x20) ? ' ' : _v);
case 'b': DO_DUMP2(char, 16, " %02x", (_v) & 0xff);
}
}
#define CHARBUFSIZE 16
BOOL memory_get_string(HANDLE hp, void* addr, unsigned cookie, BOOL unicode,
char* buffer, int size)
{
DWORD sz;
WCHAR* buffW;
/******************************************************************
* DEBUG_PrintStringA
buffer[0] = 0;
if (!addr) return FALSE;
switch (cookie)
{
case DLV_TARGET:
if (!unicode) return ReadProcessMemory(hp, addr, buffer, size, &sz);
buffW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
ReadProcessMemory(hp, addr, buffW, size * sizeof(WCHAR), &sz);
WideCharToMultiByte(CP_ACP, 0, buffW, sz / sizeof(WCHAR), buffer, size,
NULL, NULL);
HeapFree(GetProcessHeap(), 0, buffW);
return TRUE;
case DLV_HOST:
strncpy(buffer, addr, size);
buffer[size - 1] = 0;
return TRUE;
}
return FALSE;
}
BOOL memory_get_string_indirect(HANDLE hp, void* addr, BOOL unicode, char* buffer, int size)
{
void* ad;
DWORD sz;
buffer[0] = 0;
if (addr &&
ReadProcessMemory(hp, addr, &ad, sizeof(ad), &sz) && sz == sizeof(ad) && ad)
{
return memory_get_string(hp, ad, DLV_TARGET, unicode, buffer, size);
}
return FALSE;
}
static void print_typed_basic(const struct dbg_lvalue* lvalue)
{
long long int val_int;
void* val_ptr;
long double val_real;
DWORD tag, size, count, bt, rtype;
DWORD linear = (DWORD)memory_to_linear_addr(&lvalue->addr);
assert(lvalue->cookie == DLV_TARGET || lvalue->cookie == DLV_HOST);
if (lvalue->typeid == dbg_itype_none ||
!types_get_info(linear, lvalue->typeid, TI_GET_SYMTAG, &tag))
return;
switch (tag)
{
case SymTagBaseType:
if (!types_get_info(linear, lvalue->typeid, TI_GET_LENGTH, &size) ||
!types_get_info(linear, lvalue->typeid, TI_GET_BASETYPE, &bt))
{
WINE_ERR("Couldn't get information\n");
RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
}
switch (bt)
{
case btInt:
if (!be_cpu->fetch_integer(lvalue, size, TRUE, &val_int)) return;
dbg_printf("%lld", val_int);
break;
case btUInt:
if (!be_cpu->fetch_integer(lvalue, size, FALSE, &val_int)) return;
dbg_printf("%llu", val_int);
break;
case btFloat:
if (!be_cpu->fetch_float(lvalue, size, &val_real)) return;
dbg_printf("%Lf", val_real);
break;
case btChar:
if (!be_cpu->fetch_integer(lvalue, size, TRUE, &val_int)) return;
/* FIXME: should do the same for a Unicode character (size == 2) */
if (size == 1 && (val_int < 0x20 || val_int > 0x80))
dbg_printf("%d", (int)val_int);
else
dbg_printf("'%c'", (char)val_int);
break;
default:
WINE_FIXME("Unsupported basetype %lu\n", bt);
break;
}
break;
case SymTagPointerType:
if (!memory_read_value(lvalue, sizeof(void*), &val_ptr)) return;
if (!types_get_info(linear, lvalue->typeid, TI_GET_TYPE, &rtype) ||
rtype == dbg_itype_none)
{
dbg_printf("Internal symbol error: unable to access memory location %p", val_ptr);
break;
}
if (types_get_info(linear, rtype, TI_GET_SYMTAG, &tag) && tag == SymTagBaseType &&
types_get_info(linear, rtype, TI_GET_BASETYPE, &bt) && bt == btChar &&
types_get_info(linear, rtype, TI_GET_LENGTH, &size))
{
char buffer[1024];
memory_get_string(dbg_curr_thread->handle, (void*)val_ptr, lvalue->cookie,
size == 2, buffer, sizeof(buffer));
dbg_printf("\"%s\"", buffer);
}
else dbg_printf("%p", val_ptr);
break;
case SymTagArrayType:
case SymTagUDT:
assert(lvalue->cookie == DLV_TARGET);
if (!memory_read_value(lvalue, sizeof(val_ptr), &val_ptr)) return;
dbg_printf("%p", val_ptr);
break;
case SymTagEnum:
{
BOOL ok = FALSE;
assert(lvalue->cookie == DLV_TARGET);
/* FIXME: it depends on underlying type for enums
* (not supported yet in dbghelp)
* Assuming 4 as for an int
*/
if (!be_cpu->fetch_integer(lvalue, 4, TRUE, &val_int)) return;
if (types_get_info(linear, lvalue->typeid, TI_GET_CHILDRENCOUNT, &count))
{
char buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
TI_FINDCHILDREN_PARAMS* fcp = (TI_FINDCHILDREN_PARAMS*)buffer;
WCHAR* ptr;
char tmp[256];
VARIANT variant;
int i;
fcp->Start = 0;
while (count)
{
fcp->Count = min(count, 256);
if (types_get_info(linear, lvalue->typeid, TI_FINDCHILDREN, fcp))
{
for (i = 0; i < min(fcp->Count, count); i++)
{
if (!types_get_info(linear, fcp->ChildId[i], TI_GET_VALUE, &variant))
continue;
switch (variant.n1.n2.vt)
{
case VT_I4: ok = (val_int == variant.n1.n2.n3.lVal); break;
default: WINE_FIXME("Unsupported variant type (%u)\n", variant.n1.n2.vt);
}
if (ok)
{
ptr = NULL;
types_get_info(linear, fcp->ChildId[i], TI_GET_SYMNAME, &ptr);
if (!ptr) continue;
WideCharToMultiByte(CP_ACP, 0, ptr, -1, tmp, sizeof(tmp), NULL, NULL);
HeapFree(GetProcessHeap(), 0, ptr);
dbg_printf("%s", tmp);
count = 0; /* so that we'll get away from outter loop */
break;
}
}
}
}
count -= min(count, 256);
fcp->Start += 256;
}
if (!ok) dbg_printf("%lld", val_int);
}
break;
default:
WINE_FIXME("Unsupported tag %lu\n", tag);
break;
}
}
/***********************************************************************
* print_basic
*
* Prints on channel chnl, the string starting at address in target
* address space. The string stops when either len chars (if <> -1)
* have been printed, or the '\0' char is printed
* Implementation of the 'print' command.
*/
int DEBUG_PrintStringA(const DBG_ADDR* address, int len)
void print_basic(const struct dbg_lvalue* lvalue, int count, char format)
{
char* lin = (void*)DEBUG_ToLinear(address);
char ch[CHARBUFSIZE+1];
int written = 0;
long int res;
if (len == -1) len = 32767; /* should be big enough */
while (written < len)
assert(lvalue->cookie == DLV_TARGET || lvalue->cookie == DLV_HOST);
if (lvalue->typeid == dbg_itype_none)
{
int to_write = min(CHARBUFSIZE, len - written );
if (!DEBUG_READ_MEM_VERBOSE(lin, ch, to_write)) break;
ch[to_write] = '\0'; /* protect from displaying junk */
to_write = lstrlenA(ch);
DEBUG_OutputA(ch, to_write);
lin += to_write;
written += to_write;
if (to_write < CHARBUFSIZE) break;
dbg_printf("Unable to evaluate expression\n");
return;
}
res = types_extract_as_integer(lvalue);
/* FIXME: this implies i386 byte ordering */
switch (format)
{
case 'x':
if (lvalue->addr.Mode != AddrModeFlat)
dbg_printf("0x%04lx", res);
else
dbg_printf("0x%08lx", res);
break;
case 'd':
dbg_printf("%ld\n", res);
break;
case 'c':
dbg_printf("%d = '%c'", (char)(res & 0xff), (char)(res & 0xff));
break;
case 'u':
{
WCHAR wch = (WCHAR)(res & 0xFFFF);
dbg_printf("%d = '", wch);
dbg_outputW(&wch, 1);
dbg_printf("'");
}
break;
case 'i':
case 's':
case 'w':
case 'b':
dbg_printf("Format specifier '%c' is meaningless in 'print' command\n", format);
case 0:
print_typed_basic(lvalue);
break;
}
return written; /* number of actually written chars */
}
int DEBUG_PrintStringW(const DBG_ADDR* address, int len)
void print_bare_address(const ADDRESS* addr)
{
WCHAR* lin = (void*)DEBUG_ToLinear(address);
WCHAR ch[CHARBUFSIZE+1];
int written = 0;
if (len == -1) len = 32767; /* should be big enough */
while (written < len)
switch (addr->Mode)
{
int to_write = min(CHARBUFSIZE, len - written );
if (!DEBUG_READ_MEM_VERBOSE(lin, ch, to_write * sizeof(WCHAR))) break;
ch[to_write] = 0; /* protect from displaying junk */
to_write = lstrlenW(ch);
DEBUG_OutputW(ch, to_write);
lin += to_write;
written += to_write;
if (to_write < CHARBUFSIZE) break;
case AddrModeFlat:
dbg_printf("0x%08lx", addr->Offset);
break;
case AddrModeReal:
case AddrMode1616:
dbg_printf("0x%04x:0x%04lx", addr->Segment, addr->Offset);
break;
case AddrMode1632:
dbg_printf("0x%04x:0x%08lx", addr->Segment, addr->Offset);
break;
}
return written; /* number of actually written chars */
}
/***********************************************************************
* print_address
*
* Print an 16- or 32-bit address, with the nearest symbol if any.
*/
void print_address(const ADDRESS* addr, BOOLEAN with_line)
{
char buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* si = (SYMBOL_INFO*)buffer;
void* lin = memory_to_linear_addr(addr);
print_bare_address(addr);
si->SizeOfStruct = sizeof(*si);
si->MaxNameLen = 256;
if (!SymFromAddr(dbg_curr_process->handle, (unsigned long)lin, NULL, si)) return;
dbg_printf(" %s", si->Name);
if (with_line)
{
IMAGEHLP_LINE il;
IMAGEHLP_MODULE im;
il.SizeOfStruct = sizeof(il);
if (SymGetLineFromAddr(dbg_curr_process->handle, (unsigned long)lin, NULL, &il))
dbg_printf(" [%s:%lu]", il.FileName, il.LineNumber);
im.SizeOfStruct = sizeof(im);
if (SymGetModuleInfo(dbg_curr_process->handle, (unsigned long)lin, &im))
dbg_printf(" in %s", im.ModuleName);
}
}
struct foo
{
char* tmp;
DWORD frame;
};
static BOOL WINAPI sym_enum_cb(SYMBOL_INFO* sym_info, ULONG size, void* user)
{
struct foo* foo = (struct foo*)user;
DWORD addr;
unsigned val;
long offset;
if ((sym_info->Flags & (SYMFLAG_PARAMETER|SYMFLAG_FRAMEREL)) == (SYMFLAG_PARAMETER|SYMFLAG_FRAMEREL))
{
if (foo->tmp[0]) strcat(foo->tmp, ", ");
addr = foo->frame;
types_get_info(sym_info->ModBase, sym_info->TypeIndex, TI_GET_OFFSET, &offset);
addr += offset;
dbg_read_memory_verbose((char*)addr, &val, sizeof(val));
sprintf(foo->tmp + strlen(foo->tmp), "%s=0x%x", sym_info->Name, val);
}
return TRUE;
}
void print_addr_and_args(const ADDRESS* pc, const ADDRESS* frame)
{
char buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* si = (SYMBOL_INFO*)buffer;
IMAGEHLP_STACK_FRAME isf;
IMAGEHLP_LINE il;
IMAGEHLP_MODULE im;
struct foo foo;
char tmp[1024];
DWORD disp;
if (pc->Mode != AddrModeFlat)
dbg_printf("0x%04x:0x%04lx", pc->Segment, pc->Offset);
else
dbg_printf("0x%08lx", pc->Offset);
isf.InstructionOffset = (unsigned long)memory_to_linear_addr(pc);
isf.FrameOffset = (unsigned long)memory_to_linear_addr(frame);
si->SizeOfStruct = sizeof(*si);
si->MaxNameLen = 256;
if (!SymFromAddr(dbg_curr_process->handle, isf.InstructionOffset, &disp, si))
return;
dbg_printf(" %s", si->Name);
if (disp) dbg_printf("+0x%lx", disp);
SymSetContext(dbg_curr_process->handle, &isf, NULL);
foo.tmp = tmp;
foo.frame = isf.FrameOffset;
tmp[0] = '\0';
SymEnumSymbols(dbg_curr_process->handle, 0, NULL, sym_enum_cb, &foo);
if (tmp[0]) dbg_printf("(%s)", tmp);
il.SizeOfStruct = sizeof(il);
if (SymGetLineFromAddr(dbg_curr_process->handle, isf.InstructionOffset,
NULL, &il))
dbg_printf(" [%s:%lu]", il.FileName, il.LineNumber);
im.SizeOfStruct = sizeof(im);
if (SymGetModuleInfo(dbg_curr_process->handle, isf.InstructionOffset, &im))
dbg_printf(" in %s", im.ModuleName);
}
BOOL memory_disasm_one_insn(ADDRESS* addr)
{
char ch;
print_address(addr, TRUE);
dbg_printf(": ");
if (!dbg_read_memory(memory_to_linear_addr(addr), &ch, sizeof(ch)))
{
dbg_printf("-- no code accessible --\n");
return FALSE;
}
be_cpu->disasm_one_insn(addr, TRUE);
dbg_printf("\n");
return TRUE;
}
void memory_disassemble(const struct dbg_lvalue* xstart,
const struct dbg_lvalue* xend, int offset)
{
static ADDRESS last = {0,0,0};
if (!xstart && !xend)
{
if (!last.Segment && !last.Offset) memory_get_current_pc(&last);
}
else
{
if (xstart)
{
last.Mode = AddrModeFlat;
last.Offset = types_extract_as_integer(xstart);
}
if (xend) offset = types_extract_as_integer(xend) - last.Offset + 1;
}
while (offset-- > 0 && memory_disasm_one_insn(&last));
}

View File

@ -1,479 +0,0 @@
/*
* File module.c - module handling for the wine debugger
*
* Copyright (C) 1993, Eric Youngdale.
* 2000, Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "debugger.h"
#include "wingdi.h"
#include "winuser.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
/***********************************************************************
* Creates and links a new module to the current process
*
*/
DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type,
void* mod_addr, unsigned long size, HMODULE hmodule)
{
DBG_MODULE* wmod;
if (!(wmod = (DBG_MODULE*)DBG_alloc(sizeof(*wmod))))
return NULL;
memset(wmod, 0, sizeof(*wmod));
wmod->dil = DIL_DEFERRED;
wmod->main = (DEBUG_CurrProcess->num_modules == 0);
wmod->type = type;
wmod->load_addr = mod_addr;
wmod->size = size;
wmod->handle = hmodule;
wmod->dbg_index = DEBUG_CurrProcess->next_index;
wmod->module_name = DBG_strdup(name);
DEBUG_CurrProcess->next_index++;
DEBUG_CurrProcess->modules = DBG_realloc(DEBUG_CurrProcess->modules,
++DEBUG_CurrProcess->num_modules * sizeof(DBG_MODULE*));
DEBUG_CurrProcess->modules[DEBUG_CurrProcess->num_modules - 1] = wmod;
return wmod;
}
/***********************************************************************
* DEBUG_FindModuleByName
*
*/
DBG_MODULE* DEBUG_FindModuleByName(const char* name, enum DbgModuleType type)
{
int i;
DBG_MODULE** amod = DEBUG_CurrProcess->modules;
for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
!strcasecmp(name, amod[i]->module_name))
return amod[i];
}
return NULL;
}
/***********************************************************************
* DEBUG_FindModuleByAddr
*
* either the addr where module is loaded, or any address inside the
* module
*/
DBG_MODULE* DEBUG_FindModuleByAddr(void* addr, enum DbgModuleType type)
{
int i;
DBG_MODULE** amod = DEBUG_CurrProcess->modules;
DBG_MODULE* res = NULL;
for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
(char *)addr >= (char *)amod[i]->load_addr &&
(char *)addr < (char *)amod[i]->load_addr + amod[i]->size) {
/* amod[i] contains it... check against res now */
if (!res || res->load_addr < amod[i]->load_addr)
res = amod[i];
}
}
return res;
}
/***********************************************************************
* DEBUG_FindModuleByHandle
*/
DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, enum DbgModuleType type)
{
int i;
DBG_MODULE** amod = DEBUG_CurrProcess->modules;
for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
handle == amod[i]->handle)
return amod[i];
}
return NULL;
}
/***********************************************************************
* DEBUG_GetProcessMainModule
*/
DBG_MODULE* DEBUG_GetProcessMainModule(DBG_PROCESS* process)
{
if (!process || !process->num_modules) return NULL;
/* main module is the first to be loaded on a given process, so it's the first
* in the array */
assert(process->modules[0]->main);
return process->modules[0];
}
#if 0
/***********************************************************************
* DEBUG_RegisterNEModule
*
*/
static DBG_MODULE* DEBUG_RegisterNEModule(HMODULE hModule, void* load_addr,
unsigned long size, const char *module_name)
{
DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_NE, load_addr, size, hModule);
if (!wmod) return NULL;
DEBUG_CurrProcess->next_index++;
return wmod;
}
/***********************************************************************
* DEBUG_GetEP16
*
* Helper function fo DEBUG_LoadModuleEPs16:
* finds the address of a given entry point from a given module
*/
static BOOL DEBUG_GetEP16(char* moduleAddr, const NE_MODULE* module,
WORD ordinal, DBG_ADDR* addr)
{
void* idx;
ET_ENTRY entry;
ET_BUNDLE bundle;
SEGTABLEENTRY ste;
bundle.next = module->entry_table;
do {
if (!bundle.next)
return FALSE;
idx = moduleAddr + bundle.next;
if (!DEBUG_READ_MEM_VERBOSE(idx, &bundle, sizeof(bundle)))
return FALSE;
} while ((ordinal < bundle.first + 1) || (ordinal > bundle.last));
if (!DEBUG_READ_MEM_VERBOSE((char*)idx + sizeof(ET_BUNDLE) +
(ordinal - bundle.first - 1) * sizeof(ET_ENTRY),
&entry, sizeof(ET_ENTRY)))
return FALSE;
addr->seg = entry.segnum;
addr->off = entry.offs;
if (addr->seg == 0xfe) addr->seg = 0xffff; /* constant entry */
else {
if (!DEBUG_READ_MEM_VERBOSE(moduleAddr + module->seg_table +
sizeof(ste) * (addr->seg - 1),
&ste, sizeof(ste)))
return FALSE;
addr->seg = GlobalHandleToSel16(ste.hSeg);
}
return TRUE;
}
/***********************************************************************
* DEBUG_LoadModule16
*
* Load the entry points of a Win16 module into the hash table.
*/
static void DEBUG_LoadModule16(HMODULE hModule, NE_MODULE* module, char* moduleAddr, const char* name)
{
DBG_VALUE value;
BYTE buf[1 + 256 + 2];
char epname[512];
char* cpnt;
DBG_MODULE* wmod;
wmod = DEBUG_RegisterNEModule(hModule, moduleAddr, name);
value.type = NULL;
value.cookie = DV_TARGET;
value.addr.seg = 0;
value.addr.off = 0;
cpnt = moduleAddr + module->name_table;
/* First search the resident names */
/* skip module name */
if (!DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) || !buf[0])
return;
cpnt += 1 + buf[0] + sizeof(WORD);
while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) {
snprintf(epname, sizeof(epname), "%s.%.*s", name, buf[0], &buf[1]);
if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) {
DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC);
}
cpnt += buf[0] + 1 + sizeof(WORD);
}
/* Now search the non-resident names table */
if (!module->nrname_handle) return; /* No non-resident table */
cpnt = (char *)GlobalLock16(module->nrname_handle);
while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) {
snprintf(epname, sizeof(epname), "%s.%.*s", name, buf[0], &buf[1]);
if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) {
DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC);
}
cpnt += buf[0] + 1 + sizeof(WORD);
}
GlobalUnlock16(module->nrname_handle);
}
#endif
/***********************************************************************
* DEBUG_LoadEntryPoints
*
* Load the entry points of all the modules into the hash table.
*/
int DEBUG_LoadEntryPoints(const char* pfx)
{
int first = 0;
/* FIXME: with address space separation in space, this is plain wrong
* it requires the 16 bit WOW debugging interface...
*/
#if 0
MODULEENTRY entry;
NE_MODULE module;
void* moduleAddr;
int rowcount = 0;
int len;
/* FIXME: we assume that a module is never removed from memory */
/* FIXME: this is (currently plain wrong when debugger is started by
* attaching to an existing program => the 16 bit modules will
* not be shared... not much to do on debugger side... sigh
*/
if (ModuleFirst16(&entry)) do {
if (DEBUG_FindModuleByName(entry.szModule, DM_TYPE_UNKNOWN) ||
!(moduleAddr = NE_GetPtr(entry.hModule)) ||
!DEBUG_READ_MEM_VERBOSE(moduleAddr, &module, sizeof(module)) ||
(module.flags & NE_FFLAGS_WIN32) /* NE module */)
continue;
if (!first) {
if (pfx) DEBUG_Printf(pfx);
DEBUG_Printf(" ");
rowcount = 3 + (pfx ? strlen(pfx) : 0);
first = 1;
}
len = strlen(entry.szModule);
if ((rowcount + len) > 76) {
DEBUG_Printf("\n ");
rowcount = 3;
}
DEBUG_Printf(" %s", entry.szModule);
rowcount += len + 1;
DEBUG_LoadModule16(entry.hModule, &module, moduleAddr, entry.szModule);
} while (ModuleNext16(&entry));
#endif
if (first) DEBUG_Printf("\n");
return first;
}
void DEBUG_ReportDIL(enum DbgInfoLoad dil, const char* pfx, const char* filename, void *load_addr)
{
const char* fmt;
switch (dil) {
case DIL_DEFERRED:
fmt = "Deferring debug information loading for %s '%s' (%p)\n";
break;
case DIL_LOADED:
fmt = "Loaded debug information from %s '%s' (%p)\n";
break;
case DIL_NOINFO:
fmt = "No debug information in %s '%s' (%p)\n";
break;
case DIL_NOT_SUPPORTED:
fmt = "Unsupported debug information in %s '%s' (%p)\n";
break;
case DIL_ERROR:
fmt = "Can't find file for %s '%s' (%p)\n";
break;
default:
WINE_ERR("Oooocch (%d)\n", dil);
return;
}
DEBUG_Printf(fmt, pfx, filename, load_addr);
}
static const char* DEBUG_GetModuleType(enum DbgModuleType type)
{
switch (type) {
case DMT_NE: return "NE";
case DMT_PE: return "PE";
case DMT_ELF: return "ELF";
default: return "???";
}
}
static const char* DEBUG_GetDbgInfo(enum DbgInfoLoad dil)
{
switch (dil) {
case DIL_LOADED: return "loaded";
case DIL_DEFERRED: return "deferred";
case DIL_NOINFO: return "none";
case DIL_NOT_SUPPORTED: return "not supported";
case DIL_ERROR: return "error";
default: return "?";
}
}
/***********************************************************************
* DEBUG_ModuleCompare
*
* returns -1 is p1 < p2, 0 is p1 == p2, +1 if p1 > p2
* order used is order on load_addr of a module
*/
static int DEBUG_ModuleCompare(const void* p1, const void* p2)
{
return (char*)(*((const DBG_MODULE**)p1))->load_addr -
(char*)(*((const DBG_MODULE**)p2))->load_addr;
}
/***********************************************************************
* DEBUG_IsContainer
*
* returns TRUE is wmod_child is contained (inside bounds) of wmod_cntnr
*/
static inline BOOL DEBUG_IsContainer(const DBG_MODULE* wmod_cntnr,
const DBG_MODULE* wmod_child)
{
return wmod_cntnr->load_addr <= wmod_child->load_addr &&
(DWORD)wmod_cntnr->load_addr + wmod_cntnr->size >=
(DWORD)wmod_child->load_addr + wmod_child->size;
}
static void DEBUG_InfoShareModule(const DBG_MODULE* module, int ident)
{
if (ident) DEBUG_Printf(" \\-");
DEBUG_Printf("%s\t0x%08lx-%08lx\t%s\n",
DEBUG_GetModuleType(module->type),
(DWORD)module->load_addr, (DWORD)module->load_addr + module->size,
module->module_name);
}
/***********************************************************************
* DEBUG_InfoShare
*
* Display shared libarary information.
*/
void DEBUG_InfoShare(void)
{
DBG_MODULE** ref;
int i, j;
ref = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
if (!ref) return;
DEBUG_Printf("Module\tAddress\t\t\tName\t%d modules\n",
DEBUG_CurrProcess->num_modules);
memcpy(ref, DEBUG_CurrProcess->modules,
sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
qsort(ref, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*),
DEBUG_ModuleCompare);
for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
switch (ref[i]->type) {
case DMT_ELF:
DEBUG_InfoShareModule(ref[i], 0);
for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) {
if (ref[j]->type != DMT_ELF && DEBUG_IsContainer(ref[i], ref[j]))
DEBUG_InfoShareModule(ref[j], 1);
}
break;
case DMT_NE:
case DMT_PE:
/* check module is not in ELF */
for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) {
if (ref[j]->type == DMT_ELF &&
DEBUG_IsContainer(ref[j], ref[i]))
break;
}
if (j >= DEBUG_CurrProcess->num_modules)
DEBUG_InfoShareModule(ref[i], 0);
break;
default:
WINE_ERR("Unknown type (%d)\n", ref[i]->type);
}
}
DBG_free(ref);
}
/***********************************************************************
* DEBUG_DumpModule
* Display information about a given module (DLL or EXE)
*/
void DEBUG_DumpModule(DWORD mod)
{
DBG_MODULE* wmod;
if (!(wmod = DEBUG_FindModuleByHandle((HANDLE)mod, DMT_UNKNOWN)) &&
!(wmod = DEBUG_FindModuleByAddr((void*)mod, DMT_UNKNOWN))) {
DEBUG_Printf("'0x%08lx' is not a valid module handle or address\n", mod);
return;
}
DEBUG_Printf("Module '%s' (handle=%p) 0x%08lx-0x%08lx (%s, debug info %s)\n",
wmod->module_name, wmod->handle, (DWORD)wmod->load_addr,
(DWORD)wmod->load_addr + wmod->size,
DEBUG_GetModuleType(wmod->type), DEBUG_GetDbgInfo(wmod->dil));
}
/***********************************************************************
* DEBUG_WalkModules
*
* Display information about all modules (DLLs and EXEs)
*/
void DEBUG_WalkModules(void)
{
DBG_MODULE** amod;
int i;
if (!DEBUG_CurrProcess)
{
DEBUG_Printf("Cannot walk classes while no process is loaded\n");
return;
}
DEBUG_Printf("Address\t\t\tModule\tName\n");
amod = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
if (!amod) return;
memcpy(amod, DEBUG_CurrProcess->modules,
sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
qsort(amod, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*),
DEBUG_ModuleCompare);
for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
if (amod[i]->type == DMT_ELF) continue;
DEBUG_Printf("0x%08lx-%08lx\t(%s)\t%s\n",
(DWORD)amod[i]->load_addr,
(DWORD)amod[i]->load_addr + amod[i]->size,
DEBUG_GetModuleType(amod[i]->type), amod[i]->module_name);
}
DBG_free(amod);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,513 +0,0 @@
/*
* File pe.c - handle PE module information
*
* Copyright (C) 1996, Eric Youngdale.
* Copyright (C) 1999, 2000, Ulrich Weigand.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "config.h"
#include "wine/port.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#include "wine/exception.h"
#include "wine/debug.h"
#include "excpt.h"
#include "debugger.h"
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
#define MAX_PATHNAME_LEN 1024
typedef struct
{
DWORD from;
DWORD to;
} OMAP_DATA;
typedef struct tagMSC_DBG_INFO
{
int nsect;
PIMAGE_SECTION_HEADER sectp;
int nomap;
OMAP_DATA* omapp;
} MSC_DBG_INFO;
/***********************************************************************
* DEBUG_LocateDebugInfoFile
*
* NOTE: dbg_filename must be at least MAX_PATHNAME_LEN bytes in size
*/
static void DEBUG_LocateDebugInfoFile(const char* filename, char* dbg_filename)
{
char* str1 = DBG_alloc(MAX_PATHNAME_LEN);
char* str2 = DBG_alloc(MAX_PATHNAME_LEN*10);
const char* file;
char* name_part;
file = strrchr(filename, '\\');
if (file == NULL) file = filename; else file++;
if ((GetEnvironmentVariable("_NT_SYMBOL_PATH", str1, MAX_PATHNAME_LEN) &&
(SearchPath(str1, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part))) ||
(GetEnvironmentVariable("_NT_ALT_SYMBOL_PATH", str1, MAX_PATHNAME_LEN) &&
(SearchPath(str1, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part))) ||
(SearchPath(NULL, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part)))
lstrcpyn(dbg_filename, str2, MAX_PATHNAME_LEN);
else
lstrcpyn(dbg_filename, filename, MAX_PATHNAME_LEN);
DBG_free(str1);
DBG_free(str2);
}
/***********************************************************************
* DEBUG_MapDebugInfoFile
*/
void* DEBUG_MapDebugInfoFile(const char* name, DWORD offset, DWORD size,
HANDLE* hFile, HANDLE* hMap)
{
DWORD g_offset; /* offset aligned on map granuality */
DWORD g_size; /* size to map, with offset aligned */
char* ret;
*hMap = 0;
if (name != NULL)
{
char filename[MAX_PATHNAME_LEN];
DEBUG_LocateDebugInfoFile(name, filename);
if ((*hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
}
if (!size)
{
DWORD file_size = GetFileSize(*hFile, NULL);
if (file_size == (DWORD)-1) return NULL;
size = file_size - offset;
}
g_offset = offset & ~0xFFFF; /* FIXME: is granularity portable ? */
g_size = offset + size - g_offset;
if ((*hMap = CreateFileMapping(*hFile, NULL, PAGE_READONLY, 0, 0, NULL)) == 0)
return NULL;
if ((ret = MapViewOfFile(*hMap, FILE_MAP_READ, 0, g_offset, g_size)) != NULL)
ret += offset - g_offset;
return ret;
}
/***********************************************************************
* DEBUG_UnmapDebugInfoFile
*/
void DEBUG_UnmapDebugInfoFile(HANDLE hFile, HANDLE hMap, const void* addr)
{
if (addr) UnmapViewOfFile((void*)addr);
if (hMap) CloseHandle(hMap);
if (hFile!=INVALID_HANDLE_VALUE) CloseHandle(hFile);
}
/*========================================================================
* Process DBG file.
*/
static enum DbgInfoLoad DEBUG_ProcessDBGFile(DBG_MODULE* module,
const char* filename, DWORD timestamp)
{
enum DbgInfoLoad dil = DIL_ERROR;
HANDLE hFile = INVALID_HANDLE_VALUE, hMap = 0;
const BYTE* file_map = NULL;
PIMAGE_SEPARATE_DEBUG_HEADER hdr;
PIMAGE_DEBUG_DIRECTORY dbg;
int nDbg;
WINE_TRACE("Processing DBG file %s\n", filename);
file_map = DEBUG_MapDebugInfoFile(filename, 0, 0, &hFile, &hMap);
if (!file_map)
{
WINE_ERR("-Unable to peruse .DBG file %s\n", filename);
goto leave;
}
hdr = (PIMAGE_SEPARATE_DEBUG_HEADER) file_map;
if (hdr->TimeDateStamp != timestamp)
{
WINE_ERR("Warning - %s has incorrect internal timestamp\n", filename);
/*
* Well, sometimes this happens to DBG files which ARE REALLY the right .DBG
* files but nonetheless this check fails. Anyway, WINDBG (debugger for
* Windows by Microsoft) loads debug symbols which have incorrect timestamps.
*/
}
dbg = (PIMAGE_DEBUG_DIRECTORY)
(file_map + sizeof(*hdr) + hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
+ hdr->ExportedNamesSize);
nDbg = hdr->DebugDirectorySize / sizeof(*dbg);
dil = DEBUG_ProcessDebugDirectory(module, file_map, dbg, nDbg);
leave:
DEBUG_UnmapDebugInfoFile(hFile, hMap, file_map);
return dil;
}
/*========================================================================
* Process MSC debug information in PE file.
*/
enum DbgInfoLoad DEBUG_RegisterMSCDebugInfo(DBG_MODULE* module, HANDLE hFile,
void* _nth, unsigned long nth_ofs)
{
enum DbgInfoLoad dil = DIL_ERROR;
PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth;
PIMAGE_DATA_DIRECTORY dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
PIMAGE_DEBUG_DIRECTORY dbg = NULL;
int nDbg;
MSC_DBG_INFO extra_info = { 0, NULL, 0, NULL };
HANDLE hMap = 0;
const BYTE* file_map = NULL;
/* Read in section data */
module->msc_dbg_info = &extra_info;
extra_info.nsect = nth->FileHeader.NumberOfSections;
extra_info.sectp = DBG_alloc(extra_info.nsect * sizeof(IMAGE_SECTION_HEADER));
if (!extra_info.sectp)
goto leave;
if (!DEBUG_READ_MEM_VERBOSE((char*)module->load_addr +
nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
nth->FileHeader.SizeOfOptionalHeader,
extra_info.sectp,
extra_info.nsect * sizeof(IMAGE_SECTION_HEADER)))
goto leave;
/* Read in debug directory */
nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY);
if (!nDbg)
goto leave;
dbg = (PIMAGE_DEBUG_DIRECTORY) DBG_alloc(nDbg * sizeof(IMAGE_DEBUG_DIRECTORY));
if (!dbg)
goto leave;
if (!DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + dir->VirtualAddress,
dbg, nDbg * sizeof(IMAGE_DEBUG_DIRECTORY)))
goto leave;
/* Map in PE file */
file_map = DEBUG_MapDebugInfoFile(NULL, 0, 0, &hFile, &hMap);
if (!file_map)
goto leave;
/* Parse debug directory */
if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
{
/* Debug info is stripped to .DBG file */
PIMAGE_DEBUG_MISC misc = (PIMAGE_DEBUG_MISC)(file_map + dbg->PointerToRawData);
if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC
|| misc->DataType != IMAGE_DEBUG_MISC_EXENAME)
{
WINE_ERR("-Debug info stripped, but no .DBG file in module %s\n",
module->module_name);
goto leave;
}
dil = DEBUG_ProcessDBGFile(module, misc->Data, nth->FileHeader.TimeDateStamp);
}
else
{
/* Debug info is embedded into PE module */
/* FIXME: the nDBG information we're manipulating comes from the debuggee
* address space. However, the following code will be made against the
* version mapped in the debugger address space. There are cases (for example
* when the PE sections are compressed in the file and become decompressed
* in the debuggee address space) where the two don't match.
* Therefore, redo the DBG information lookup with the mapped data
*/
PIMAGE_NT_HEADERS mpd_nth = (PIMAGE_NT_HEADERS)(file_map + nth_ofs);
PIMAGE_DATA_DIRECTORY mpd_dir;
PIMAGE_DEBUG_DIRECTORY mpd_dbg = NULL;
/* sanity checks */
if (mpd_nth->Signature != IMAGE_NT_SIGNATURE ||
mpd_nth->FileHeader.NumberOfSections != nth->FileHeader.NumberOfSections ||
(mpd_nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) != 0)
goto leave;
mpd_dir = mpd_nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
if ((mpd_dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY)) != nDbg)
goto leave;
mpd_dbg = (PIMAGE_DEBUG_DIRECTORY)(file_map + mpd_dir->VirtualAddress);
dil = DEBUG_ProcessDebugDirectory(module, file_map, mpd_dbg, nDbg);
}
leave:
module->msc_dbg_info = NULL;
DEBUG_UnmapDebugInfoFile(0, hMap, file_map);
if (extra_info.sectp) DBG_free(extra_info.sectp);
if (dbg) DBG_free(dbg);
return dil;
}
/*========================================================================
* look for stabs information in PE header (it's how mingw compiler provides its
* debugging information), and also wine PE <-> ELF linking through .wsolnk sections
*/
enum DbgInfoLoad DEBUG_RegisterStabsDebugInfo(DBG_MODULE* module, HANDLE hFile,
void* _nth, unsigned long nth_ofs)
{
IMAGE_SECTION_HEADER pe_seg;
unsigned long pe_seg_ofs;
int i, stabsize = 0, stabstrsize = 0;
unsigned int stabs = 0, stabstr = 0;
PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth;
enum DbgInfoLoad dil = DIL_ERROR;
pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
nth->FileHeader.SizeOfOptionalHeader;
for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg))
{
if (!DEBUG_READ_MEM_VERBOSE((void*)((char*)module->load_addr + pe_seg_ofs),
&pe_seg, sizeof(pe_seg)))
continue;
if (!strcasecmp(pe_seg.Name, ".stab"))
{
stabs = pe_seg.VirtualAddress;
stabsize = pe_seg.SizeOfRawData;
}
else if (!strncasecmp(pe_seg.Name, ".stabstr", 8))
{
stabstr = pe_seg.VirtualAddress;
stabstrsize = pe_seg.SizeOfRawData;
}
}
if (stabstrsize && stabsize)
{
char* s1 = DBG_alloc(stabsize+stabstrsize);
if (s1)
{
if (DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabs, s1, stabsize) &&
DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabstr,
s1 + stabsize, stabstrsize))
{
dil = DEBUG_ParseStabs(s1, 0, 0, stabsize, stabsize, stabstrsize);
}
else
{
DEBUG_Printf("couldn't read data block\n");
}
DBG_free(s1);
}
else
{
DEBUG_Printf("couldn't alloc %d bytes\n", stabsize + stabstrsize);
}
}
else
{
dil = DIL_NOINFO;
}
return dil;
}
/***********************************************************************
* DEBUG_RegisterPEDebugInfo
*/
enum DbgInfoLoad DEBUG_RegisterPEDebugInfo(DBG_MODULE* wmod, HANDLE hFile,
void* _nth, unsigned long nth_ofs)
{
DBG_VALUE value;
char buffer[512];
char bufstr[256];
unsigned int i;
IMAGE_SECTION_HEADER pe_seg;
DWORD pe_seg_ofs;
IMAGE_DATA_DIRECTORY dir;
DWORD dir_ofs;
const char* prefix;
IMAGE_NT_HEADERS* nth = (PIMAGE_NT_HEADERS)_nth;
void* base = wmod->load_addr;
value.type = NULL;
value.cookie = DV_TARGET;
value.addr.seg = 0;
value.addr.off = 0;
/* Add start of DLL */
value.addr.off = (unsigned long)base;
if ((prefix = strrchr(wmod->module_name, '\\'))) prefix++;
else prefix = wmod->module_name;
DEBUG_AddSymbol(prefix, &value, NULL, SYM_WIN32 | SYM_FUNC);
/* Add entry point */
snprintf(buffer, sizeof(buffer), "%s.EntryPoint", prefix);
value.addr.off = (unsigned long)base + nth->OptionalHeader.AddressOfEntryPoint;
DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
/* Add start of sections */
pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
nth->FileHeader.SizeOfOptionalHeader;
for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg))
{
if (!DEBUG_READ_MEM_VERBOSE((char*)base + pe_seg_ofs, &pe_seg, sizeof(pe_seg)))
continue;
snprintf(buffer, sizeof(buffer), "%s.%s", prefix, pe_seg.Name);
value.addr.off = (unsigned long)base + pe_seg.VirtualAddress;
DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
}
/* Add exported functions */
dir_ofs = nth_ofs +
OFFSET_OF(IMAGE_NT_HEADERS,
OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
if (DEBUG_READ_MEM_VERBOSE((char*)base + dir_ofs, &dir, sizeof(dir)) && dir.Size)
{
IMAGE_EXPORT_DIRECTORY exports;
WORD* ordinals = NULL;
void** functions = NULL;
DWORD* names = NULL;
unsigned int j;
if (DEBUG_READ_MEM_VERBOSE((char*)base + dir.VirtualAddress,
&exports, sizeof(exports)) &&
((functions = DBG_alloc(sizeof(functions[0]) * exports.NumberOfFunctions))) &&
DEBUG_READ_MEM_VERBOSE((char*)base + exports.AddressOfFunctions,
functions, sizeof(functions[0]) * exports.NumberOfFunctions) &&
((ordinals = DBG_alloc(sizeof(ordinals[0]) * exports.NumberOfNames))) &&
DEBUG_READ_MEM_VERBOSE((char*)base + (DWORD)exports.AddressOfNameOrdinals,
ordinals, sizeof(ordinals[0]) * exports.NumberOfNames) &&
((names = DBG_alloc(sizeof(names[0]) * exports.NumberOfNames))) &&
DEBUG_READ_MEM_VERBOSE((char*)base + (DWORD)exports.AddressOfNames,
names, sizeof(names[0]) * exports.NumberOfNames))
{
for (i = 0; i < exports.NumberOfNames; i++)
{
if (!names[i] ||
!DEBUG_READ_MEM_VERBOSE((char*)base + names[i], bufstr, sizeof(bufstr)))
continue;
bufstr[sizeof(bufstr) - 1] = 0;
snprintf(buffer, sizeof(buffer), "%s.%s", prefix, bufstr);
value.addr.off = (unsigned long)base + (DWORD)functions[ordinals[i]];
DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
}
for (i = 0; i < exports.NumberOfFunctions; i++)
{
if (!functions[i]) continue;
/* Check if we already added it with a name */
for (j = 0; j < exports.NumberOfNames; j++)
if ((ordinals[j] == i) && names[j]) break;
if (j < exports.NumberOfNames) continue;
snprintf(buffer, sizeof(buffer), "%s.%ld", prefix, i + exports.Base);
value.addr.off = (unsigned long)base + (DWORD)functions[i];
DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
}
}
DBG_free(functions);
DBG_free(ordinals);
DBG_free(names);
}
/* no real debug info, only entry points */
return DIL_NOINFO;
}
/***********************************************************************
* DEBUG_LoadPEModule
*/
void DEBUG_LoadPEModule(const char* name, HANDLE hFile, void* base)
{
IMAGE_NT_HEADERS pe_header;
DWORD nth_ofs;
DBG_MODULE* wmod = NULL;
int i;
IMAGE_SECTION_HEADER pe_seg;
DWORD pe_seg_ofs;
DWORD size = 0;
enum DbgInfoLoad dil = DIL_ERROR;
/* grab PE Header */
if (!DEBUG_READ_MEM_VERBOSE((char*)base + OFFSET_OF(IMAGE_DOS_HEADER, e_lfanew),
&nth_ofs, sizeof(nth_ofs)) ||
!DEBUG_READ_MEM_VERBOSE((char*)base + nth_ofs, &pe_header, sizeof(pe_header)))
return;
pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
pe_header.FileHeader.SizeOfOptionalHeader;
for (i = 0; i < pe_header.FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg))
{
if (!DEBUG_READ_MEM_VERBOSE((char*)base + pe_seg_ofs, &pe_seg, sizeof(pe_seg)))
continue;
if (size < pe_seg.VirtualAddress + pe_seg.SizeOfRawData)
size = pe_seg.VirtualAddress + pe_seg.SizeOfRawData;
}
/* FIXME: we make the assumption that hModule == base */
wmod = DEBUG_AddModule(name, DMT_PE, base, size, (HMODULE)base);
if (wmod)
{
dil = DEBUG_RegisterStabsDebugInfo(wmod, hFile, &pe_header, nth_ofs);
if (dil != DIL_LOADED)
dil = DEBUG_RegisterMSCDebugInfo(wmod, hFile, &pe_header, nth_ofs);
if (dil != DIL_LOADED)
dil = DEBUG_RegisterPEDebugInfo(wmod, hFile, &pe_header, nth_ofs);
wmod->dil = dil;
}
DEBUG_ReportDIL(dil, "32bit DLL", name, base);
}

View File

@ -1,186 +0,0 @@
/*
* Debugger register handling
*
* Copyright 1995 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <string.h>
#include "debugger.h"
/***********************************************************************
* DEBUG_Flags
*
* Return Flag String.
*/
static char *DEBUG_Flags( DWORD flag, char *buf )
{
#ifdef __i386__
char *pt;
strcpy( buf, " - 00 - - - " );
pt = buf + strlen( buf );
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000001 ) *pt = 'C'; /* Carry Falg */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000002 ) *pt = '1';
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000004 ) *pt = 'P'; /* Parity Flag */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000008 ) *pt = '-';
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000010 ) *pt = 'A'; /* Auxiliary Carry Flag */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000020 ) *pt = '-';
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000040 ) *pt = 'Z'; /* Zero Flag */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000080 ) *pt = 'S'; /* Sign Flag */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000100 ) *pt = 'T'; /* Trap/Trace Flag */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000200 ) *pt = 'I'; /* Interupt Enable Flag */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000400 ) *pt = 'D'; /* Direction Indicator */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00000800 ) *pt = 'O'; /* Overflow Flag */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00001000 ) *pt = '1'; /* I/O Privilege Level */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00002000 ) *pt = '1'; /* I/O Privilege Level */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00004000 ) *pt = 'N'; /* Nested Task Flag */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00008000 ) *pt = '-';
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00010000 ) *pt = 'R'; /* Resume Flag */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00020000 ) *pt = 'V'; /* Vritual Mode Flag */
if ( buf >= pt-- ) return( buf );
if ( flag & 0x00040000 ) *pt = 'a'; /* Alignment Check Flag */
if ( buf >= pt-- ) return( buf );
return( buf );
#else
strcpy(buf, "unknown CPU");
return buf;
#endif
}
/***********************************************************************
* DEBUG_InfoRegisters
*
* Display registers information.
*/
void DEBUG_InfoRegisters(const CONTEXT* ctx)
{
DEBUG_Printf("Register dump:\n");
#ifdef __i386__
/* First get the segment registers out of the way */
DEBUG_Printf(" CS:%04x SS:%04x DS:%04x ES:%04x FS:%04x GS:%04x",
(WORD)ctx->SegCs, (WORD)ctx->SegSs,
(WORD)ctx->SegDs, (WORD)ctx->SegEs,
(WORD)ctx->SegFs, (WORD)ctx->SegGs);
if (DEBUG_CurrThread->dbg_mode != MODE_32)
{
char flag[33];
DEBUG_Printf("\n IP:%04x SP:%04x BP:%04x FLAGS:%04x(%s)\n",
LOWORD(ctx->Eip), LOWORD(ctx->Esp),
LOWORD(ctx->Ebp), LOWORD(ctx->EFlags),
DEBUG_Flags(LOWORD(ctx->EFlags), flag));
DEBUG_Printf(" AX:%04x BX:%04x CX:%04x DX:%04x SI:%04x DI:%04x\n",
LOWORD(ctx->Eax), LOWORD(ctx->Ebx),
LOWORD(ctx->Ecx), LOWORD(ctx->Edx),
LOWORD(ctx->Esi), LOWORD(ctx->Edi));
}
else /* 32-bit mode */
{
char flag[33];
DEBUG_Printf("\n EIP:%08lx ESP:%08lx EBP:%08lx EFLAGS:%08lx(%s)\n",
ctx->Eip, ctx->Esp,
ctx->Ebp, ctx->EFlags,
DEBUG_Flags(ctx->EFlags, flag));
DEBUG_Printf(" EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n",
ctx->Eax, ctx->Ebx,
ctx->Ecx, ctx->Edx );
DEBUG_Printf(" ESI:%08lx EDI:%08lx\n",
ctx->Esi, ctx->Edi );
}
#endif
}
/***********************************************************************
* DEBUG_ValidateRegisters
*
* Make sure all registers have a correct value for returning from
* the signal handler.
*/
BOOL DEBUG_ValidateRegisters(void)
{
DBG_ADDR addr;
char ch;
#ifdef __i386__
if (DEBUG_context.EFlags & V86_FLAG) return TRUE;
#if 0
/* Check that a selector is a valid ring-3 LDT selector, or a NULL selector */
#define CHECK_SEG(seg,name) \
if (((seg) & ~3) && ((((seg) & 7) != 7) || !DEBUG_IsSelector(seg))) { \
DEBUG_Printf("*** Invalid value for %s register: %04x\n", \
(name), (WORD)(seg) ); \
return FALSE; \
}
cs = __get_cs();
ds = __get_ds();
if (DEBUG_context.SegCs != cs) CHECK_SEG(DEBUG_context.SegCs, "CS");
if (DEBUG_context.SegSs != ds) CHECK_SEG(DEBUG_context.SegSs, "SS");
if (DEBUG_context.SegDs != ds) CHECK_SEG(DEBUG_context.SegDs, "DS");
if (DEBUG_context.SegEs != ds) CHECK_SEG(DEBUG_context.SegEs, "ES");
if (DEBUG_context.SegFs != ds) CHECK_SEG(DEBUG_context.SegFs, "FS");
if (DEBUG_context.SegGs != ds) CHECK_SEG(DEBUG_context.SegGs, "GS");
#endif
/* Check that CS and SS are not NULL */
if (!(DEBUG_context.SegCs & ~3))
{
DEBUG_Printf("*** Invalid value for CS register: %04x\n",
(WORD)DEBUG_context.SegCs );
return FALSE;
}
if (!(DEBUG_context.SegSs & ~3))
{
DEBUG_Printf("*** Invalid value for SS register: %04x\n",
(WORD)DEBUG_context.SegSs );
return FALSE;
}
#undef CHECK_SEG
#else
/* to be written */
#endif
/* check if PC is correct */
DEBUG_GetCurrentAddress(&addr);
return DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear(&addr), &ch, 1);
}

View File

@ -22,93 +22,76 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#include <fcntl.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#include "debugger.h"
#include "wine/debug.h"
struct searchlist
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
struct search_list
{
char * path;
struct searchlist * next;
char* path;
struct search_list* next;
};
struct open_filelist
struct open_file_list
{
char * path;
char * real_path;
struct open_filelist * next;
unsigned int size;
signed int nlines;
unsigned int * linelist;
char* path;
char* real_path;
struct open_file_list* next;
unsigned int size;
signed int nlines;
unsigned int* linelist;
};
static struct open_filelist * ofiles;
static struct open_file_list* source_ofiles;
static struct searchlist * listhead;
static char DEBUG_current_sourcefile[PATH_MAX];
static int DEBUG_start_sourceline = -1;
static int DEBUG_end_sourceline = -1;
static struct search_list* source_list_head;
static char source_current_file[PATH_MAX];
static int source_start_line = -1;
static int source_end_line = -1;
void
DEBUG_ShowDir(void)
void source_show_path(void)
{
struct searchlist * sl;
struct search_list* sl;
DEBUG_Printf("Search list :\n");
for(sl = listhead; sl; sl = sl->next)
{
DEBUG_Printf("\t%s\n", sl->path);
}
DEBUG_Printf("\n");
dbg_printf("Search list:\n");
for (sl = source_list_head; sl; sl = sl->next) dbg_printf("\t%s\n", sl->path);
dbg_printf("\n");
}
void
DEBUG_AddPath(const char * path)
void source_add_path(const char* path)
{
struct searchlist * sl;
struct search_list* sl;
sl = (struct searchlist *) DBG_alloc(sizeof(struct searchlist));
if( sl == NULL )
{
return;
}
if (!(sl = HeapAlloc(GetProcessHeap(), 0, sizeof(struct search_list))))
return;
sl->next = listhead;
sl->path = DBG_strdup(path);
listhead = sl;
sl->next = source_list_head;
sl->path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(path) + 1), path);
source_list_head = sl;
}
void
DEBUG_NukePath(void)
void source_nuke_path(void)
{
struct searchlist * sl;
struct searchlist * nxt;
struct search_list* sl;
struct search_list* nxt;
for(sl = listhead; sl; sl = nxt)
for (sl = source_list_head; sl; sl = nxt)
{
nxt = sl->next;
DBG_free(sl->path);
DBG_free(sl);
nxt = sl->next;
HeapFree(GetProcessHeap(), 0, sl->path);
HeapFree(GetProcessHeap(), 0, sl);
}
listhead = NULL;
source_list_head = NULL;
}
static void* DEBUG_MapFile(const char* name, HANDLE* hMap, unsigned* size)
static void* source_map_file(const char* name, HANDLE* hMap, unsigned* size)
{
HANDLE hFile;
@ -122,35 +105,33 @@ static void* DEBUG_MapFile(const char* name, HANDLE* hMap, unsigned* size)
return MapViewOfFile(*hMap, FILE_MAP_READ, 0, 0, 0);
}
static void DEBUG_UnmapFile(void* addr, HANDLE hMap)
static void source_unmap_file(void* addr, HANDLE hMap)
{
UnmapViewOfFile(addr);
CloseHandle(hMap);
}
static struct open_filelist* DEBUG_SearchOpenFile(const char* name)
static struct open_file_list* source_search_open_file(const char* name)
{
struct open_filelist* ol;
struct open_file_list* ol;
for (ol = ofiles; ol; ol = ol->next)
for (ol = source_ofiles; ol; ol = ol->next)
{
if (strcmp(ol->path, name) == 0) break;
}
return ol;
}
static
int
DEBUG_DisplaySource(char * sourcefile, int start, int end)
static int source_display(const char* sourcefile, int start, int end)
{
char* addr;
int i;
struct open_filelist* ol;
struct open_file_list* ol;
int nlines;
char* basename = NULL;
const char* basename = NULL;
char* pnt;
int rtn;
struct searchlist* sl;
struct search_list* sl;
HANDLE hMap;
DWORD status;
char tmppath[PATH_MAX];
@ -159,44 +140,41 @@ DEBUG_DisplaySource(char * sourcefile, int start, int end)
* First see whether we have the file open already. If so, then
* use that, otherwise we have to try and open it.
*/
ol = DEBUG_SearchOpenFile(sourcefile);
ol = source_search_open_file(sourcefile);
if ( ol == NULL )
if (ol == NULL)
{
/*
* Try again, stripping the path from the opened file.
*/
basename = strrchr(sourcefile, '\\' );
if ( !basename )
basename = strrchr(sourcefile, '/' );
if ( !basename )
basename = sourcefile;
else
basename++;
basename = strrchr(sourcefile, '\\');
if (!basename) basename = strrchr(sourcefile, '/');
if (!basename) basename = sourcefile;
else basename++;
ol = DEBUG_SearchOpenFile(basename);
ol = source_search_open_file(basename);
}
if ( ol == NULL )
if (ol == NULL)
{
/*
* Crapola. We need to try and open the file.
*/
status = GetFileAttributes(sourcefile);
if ( status != INVALID_FILE_ATTRIBUTES )
if (status != INVALID_FILE_ATTRIBUTES)
{
strcpy(tmppath, sourcefile);
}
else if ( (status = GetFileAttributes(basename)) != INVALID_FILE_ATTRIBUTES )
else if ((status = GetFileAttributes(basename)) != INVALID_FILE_ATTRIBUTES)
{
strcpy(tmppath, basename);
}
else
{
for (sl = listhead; sl; sl = sl->next)
for (sl = source_list_head; sl; sl = sl->next)
{
strcpy(tmppath, sl->path);
if ( tmppath[strlen(tmppath)-1] != '/' && tmppath[strlen(tmppath)-1] != '\\' )
if (tmppath[strlen(tmppath) - 1] != '/' && tmppath[strlen(tmppath) - 1] != '\\')
{
strcat(tmppath, "/");
}
@ -206,21 +184,21 @@ DEBUG_DisplaySource(char * sourcefile, int start, int end)
strcat(tmppath, basename);
status = GetFileAttributes(tmppath);
if ( status != INVALID_FILE_ATTRIBUTES ) break;
if (status != INVALID_FILE_ATTRIBUTES) break;
}
if ( sl == NULL )
if (sl == NULL)
{
if (DEBUG_InteractiveP)
if (dbg_interactiveP)
{
char zbuf[256];
/*
* Still couldn't find it. Ask user for path to add.
*/
snprintf(zbuf, sizeof(zbuf), "Enter path to file '%s': ", sourcefile);
DEBUG_ReadLine(zbuf, tmppath, sizeof(tmppath));
input_read_line(zbuf, tmppath, sizeof(tmppath));
if ( tmppath[strlen(tmppath)-1] != '/' )
if (tmppath[strlen(tmppath) - 1] != '/')
{
strcat(tmppath, "/");
}
@ -237,20 +215,20 @@ DEBUG_DisplaySource(char * sourcefile, int start, int end)
strcpy(tmppath, sourcefile);
}
if ( status == INVALID_FILE_ATTRIBUTES )
if (status == INVALID_FILE_ATTRIBUTES)
{
/*
* OK, I guess the user doesn't really want to see it
* after all.
*/
ol = (struct open_filelist *) DBG_alloc(sizeof(*ol));
ol->path = DBG_strdup(sourcefile);
ol = HeapAlloc(GetProcessHeap(), 0, sizeof(*ol));
ol->path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(sourcefile) + 1), sourcefile);
ol->real_path = NULL;
ol->next = ofiles;
ol->next = source_ofiles;
ol->nlines = 0;
ol->linelist = NULL;
ofiles = ol;
DEBUG_Printf("Unable to open file %s\n", tmppath);
source_ofiles = ol;
dbg_printf("Unable to open file %s\n", tmppath);
return FALSE;
}
}
@ -258,56 +236,44 @@ DEBUG_DisplaySource(char * sourcefile, int start, int end)
/*
* Create header for file.
*/
ol = (struct open_filelist *) DBG_alloc(sizeof(*ol));
ol->path = DBG_strdup(sourcefile);
ol->real_path = DBG_strdup(tmppath);
ol->next = ofiles;
ol = HeapAlloc(GetProcessHeap(), 0, sizeof(*ol));
ol->path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(sourcefile) + 1), sourcefile);
ol->real_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(tmppath) + 1), tmppath);
ol->next = source_ofiles;
ol->nlines = 0;
ol->linelist = NULL;
ol->size = 0;
ofiles = ol;
source_ofiles = ol;
addr = DEBUG_MapFile(tmppath, &hMap, &ol->size);
if ( addr == (char *) -1 )
{
return FALSE;
}
addr = source_map_file(tmppath, &hMap, &ol->size);
if (addr == (char*)-1) return FALSE;
/*
* Now build up the line number mapping table.
*/
ol->nlines = 1;
pnt = addr;
while (pnt < addr + ol->size )
while (pnt < addr + ol->size)
{
if ( *pnt++ == '\n' )
{
ol->nlines++;
}
if (*pnt++ == '\n') ol->nlines++;
}
ol->nlines++;
ol->linelist = (unsigned int*) DBG_alloc( ol->nlines * sizeof(unsigned int) );
ol->linelist = HeapAlloc(GetProcessHeap(), 0, ol->nlines * sizeof(unsigned int));
nlines = 0;
pnt = addr;
ol->linelist[nlines++] = 0;
while(pnt < addr + ol->size )
while (pnt < addr + ol->size)
{
if( *pnt++ == '\n' )
{
ol->linelist[nlines++] = pnt - addr;
}
if (*pnt++ == '\n') ol->linelist[nlines++] = pnt - addr;
}
ol->linelist[nlines++] = pnt - addr;
}
else
{
addr = DEBUG_MapFile(ol->real_path, &hMap, NULL);
if ( addr == (char *) -1 )
{
return FALSE;
}
addr = source_map_file(ol->real_path, &hMap, NULL);
if (addr == (char*)-1) return FALSE;
}
/*
* All we need to do is to display the source lines here.
@ -317,176 +283,92 @@ DEBUG_DisplaySource(char * sourcefile, int start, int end)
{
char buffer[1024];
if (i < 0 || i >= ol->nlines - 1)
{
continue;
}
if (i < 0 || i >= ol->nlines - 1) continue;
rtn = TRUE;
memset(&buffer, 0, sizeof(buffer));
if ( ol->linelist[i+1] != ol->linelist[i] )
if (ol->linelist[i+1] != ol->linelist[i])
{
memcpy(&buffer, addr + ol->linelist[i],
(ol->linelist[i+1] - ol->linelist[i]) - 1);
}
DEBUG_Printf("%d\t%s\n", i + 1, buffer);
dbg_printf("%d\t%s\n", i + 1, buffer);
}
DEBUG_UnmapFile(addr, hMap);
source_unmap_file(addr, hMap);
return rtn;
}
void
DEBUG_List(struct list_id * source1, struct list_id * source2,
int delta)
void source_list(IMAGEHLP_LINE* src1, IMAGEHLP_LINE* src2, int delta)
{
int end;
int rtn;
int start;
char * sourcefile;
int end;
int start;
const char* sourcefile;
/*
* We need to see what source file we need. Hopefully we only have
* one specified, otherwise we might as well punt.
*/
if( source1 != NULL
&& source2 != NULL
&& source1->sourcefile != NULL
&& source2->sourcefile != NULL
&& strcmp(source1->sourcefile, source2->sourcefile) != 0 )
/*
* We need to see what source file we need. Hopefully we only have
* one specified, otherwise we might as well punt.
*/
if (src1 && src2 && src1->FileName && src2->FileName &&
strcmp(src1->FileName, src2->FileName) != 0)
{
DEBUG_Printf("Ambiguous source file specification.\n");
return;
dbg_printf("Ambiguous source file specification.\n");
return;
}
sourcefile = NULL;
if( source1 != NULL && source1->sourcefile != NULL )
{
sourcefile = source1->sourcefile;
}
sourcefile = NULL;
if (src1 && src1->FileName) sourcefile = src1->FileName;
if (!sourcefile && src2 && src2->FileName) sourcefile = src2->FileName;
if (!sourcefile) sourcefile = source_current_file;
if( sourcefile == NULL
&& source2 != NULL
&& source2->sourcefile != NULL )
{
sourcefile = source2->sourcefile;
}
/*
* Now figure out the line number range to be listed.
*/
start = end = -1;
if( sourcefile == NULL )
if (src1) start = src1->LineNumber;
if (src2) end = src2->LineNumber;
if (start == -1 && end == -1)
{
sourcefile = (char *) &DEBUG_current_sourcefile;
}
if( sourcefile == NULL )
{
DEBUG_Printf("No source file specified.\n");
return;
}
/*
* Now figure out the line number range to be listed.
*/
start = -1;
end = -1;
if( source1 != NULL )
{
start = source1->line;
}
if( source2 != NULL )
{
end = source2->line;
}
if( start == -1 && end == -1 )
{
if( delta < 0 )
if (delta < 0)
{
end = DEBUG_start_sourceline;
start = end + delta;
end = source_start_line;
start = end + delta;
}
else
else
{
start = DEBUG_end_sourceline;
end = start + delta;
start = source_end_line;
end = start + delta;
}
}
else if( start == -1 )
{
start = end + delta;
}
else if (end == -1)
{
end = start + delta;
}
else if (start == -1) start = end + delta;
else if (end == -1) end = start + delta;
/*
* Now call this function to do the dirty work.
*/
rtn = DEBUG_DisplaySource(sourcefile, start, end);
/*
* Now call this function to do the dirty work.
*/
source_display(sourcefile, start, end);
if( sourcefile != (char *) &DEBUG_current_sourcefile )
{
strcpy(DEBUG_current_sourcefile, sourcefile);
}
DEBUG_start_sourceline = start;
DEBUG_end_sourceline = end;
if (sourcefile != source_current_file)
strcpy(source_current_file, sourcefile);
source_start_line = start;
source_end_line = end;
}
DBG_ADDR DEBUG_LastDisassemble={0,0};
BOOL DEBUG_DisassembleInstruction(DBG_ADDR *addr)
void source_list_from_addr(const ADDRESS* addr, int nlines)
{
char ch;
BOOL ret = TRUE;
IMAGEHLP_LINE il;
DWORD lin;
DEBUG_PrintAddress(addr, DEBUG_CurrThread->dbg_mode, TRUE);
DEBUG_Printf(": ");
if (!DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear(addr), &ch, sizeof(ch))) {
DEBUG_Printf("-- no code --");
ret = FALSE;
} else {
DEBUG_Disasm(addr, TRUE);
}
DEBUG_Printf("\n");
return ret;
}
void
DEBUG_Disassemble(const DBG_VALUE *xstart,const DBG_VALUE *xend,int offset)
{
int i;
DBG_ADDR last;
DBG_VALUE end,start;
if (xstart) {
start = *xstart;
DEBUG_GrabAddress(&start, TRUE);
}
if (xend) {
end = *xend;
DEBUG_GrabAddress(&end, TRUE);
}
if (!xstart && !xend) {
last = DEBUG_LastDisassemble;
if (!last.seg && !last.off)
DEBUG_GetCurrentAddress( &last );
for (i=0;i<offset;i++)
if (!DEBUG_DisassembleInstruction(&last)) break;
DEBUG_LastDisassemble = last;
return;
}
last = start.addr;
if (!xend) {
for (i=0;i<offset;i++)
if (!DEBUG_DisassembleInstruction(&last)) break;
DEBUG_LastDisassemble = last;
return;
}
while (last.off <= end.addr.off)
if (!DEBUG_DisassembleInstruction(&last)) break;
DEBUG_LastDisassemble = last;
return;
if (!addr)
{
ADDRESS la;
memory_get_current_pc(&la);
lin = (unsigned long)memory_to_linear_addr(&la);
}
else lin = (unsigned long)memory_to_linear_addr(addr);
il.SizeOfStruct = sizeof(il);
if (SymGetLineFromAddr(dbg_curr_process->handle, lin, NULL, &il))
source_list(&il, NULL, nlines);
}

File diff suppressed because it is too large Load Diff

View File

@ -27,450 +27,146 @@
#include "debugger.h"
#include "stackframe.h"
#include "winbase.h"
#include "wine/debug.h"
#ifdef __i386__
/*
* We keep this info for each frame, so that we can
* find local variable information correctly.
*/
struct bt_info
{
unsigned int cs;
unsigned int eip;
unsigned int ss;
unsigned int ebp;
struct symbol_info frame;
};
static int nframe;
static struct bt_info * frames = NULL;
typedef struct
{
WORD bp;
WORD ip;
WORD cs;
} FRAME16;
typedef struct
{
DWORD bp;
DWORD ip;
WORD cs;
} FRAME32;
#endif
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
static int nframe;
static IMAGEHLP_STACK_FRAME* frames = NULL;
/***********************************************************************
* DEBUG_InfoStack
* stack_info
*
* Dump the top of the stack
*/
void DEBUG_InfoStack(void)
void stack_info(void)
{
#ifdef __i386__
DBG_VALUE value;
struct dbg_lvalue lvalue;
value.type = NULL;
value.cookie = DV_TARGET;
value.addr.seg = DEBUG_context.SegSs;
value.addr.off = DEBUG_context.Esp;
lvalue.typeid = dbg_itype_none;
lvalue.cookie = DLV_TARGET;
/* FIXME: we assume stack grows the same way as on i386 */
if (!memory_get_current_stack(&lvalue.addr))
dbg_printf("Bad segment (%d)\n", lvalue.addr.Segment);
DEBUG_Printf("Stack dump:\n");
switch (DEBUG_GetSelectorType(value.addr.seg))
dbg_printf("Stack dump:\n");
switch (lvalue.addr.Mode)
{
case MODE_32: /* 32-bit mode */
DEBUG_ExamineMemory( &value, 24, 'x' );
break;
case MODE_16: /* 16-bit mode */
case MODE_VM86:
value.addr.off &= 0xffff;
DEBUG_ExamineMemory( &value, 24, 'w' );
case AddrModeFlat: /* 32-bit mode */
case AddrMode1632: /* 32-bit mode */
memory_examine(&lvalue, 24, 'x');
break;
case AddrModeReal: /* 16-bit mode */
case AddrMode1616:
memory_examine(&lvalue, 24, 'w');
break;
default:
DEBUG_Printf("Bad segment (%ld)\n", value.addr.seg);
}
DEBUG_Printf("\n");
#endif
dbg_printf("\n");
}
#ifdef __i386__
static void DEBUG_ForceFrame(DBG_ADDR *stack, DBG_ADDR *code, int frameno, enum dbg_mode mode,
int noisy, const char *caveat)
int stack_set_frame(int newframe)
{
int theframe = nframe++;
frames = (struct bt_info *)DBG_realloc(frames,
nframe*sizeof(struct bt_info));
if (noisy)
DEBUG_Printf("%s%d ", (theframe == curr_frame ? "=>" : " "),
frameno);
frames[theframe].cs = code->seg;
frames[theframe].eip = code->off;
if (noisy)
frames[theframe].frame = DEBUG_PrintAddressAndArgs( code, mode, stack->off, TRUE );
else
DEBUG_FindNearestSymbol( code, TRUE,
&frames[theframe].frame.sym, stack->off,
&frames[theframe].frame.list);
frames[theframe].ss = stack->seg;
frames[theframe].ebp = stack->off;
if (noisy) {
DEBUG_Printf((mode != MODE_32) ? " (bp=%04lx%s)\n" : " (ebp=%08lx%s)\n",
stack->off, caveat ? caveat : "");
}
}
ADDRESS addr;
static BOOL DEBUG_Frame16(DBG_THREAD* thread, DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
{
unsigned int possible_cs = 0;
FRAME16 frame;
void* p = (void*)DEBUG_ToLinear(addr);
DBG_ADDR code;
dbg_curr_frame = newframe;
if (dbg_curr_frame >= nframe) dbg_curr_frame = nframe - 1;
if (dbg_curr_frame < 0) dbg_curr_frame = 0;
if (!p) return FALSE;
if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
if (noisy) DEBUG_InvalAddr(addr);
return FALSE;
}
if (!frame.bp) return FALSE;
if (frame.bp & 1) *cs = frame.cs;
else {
/* not explicitly marked as far call,
* but check whether it could be anyway */
if (((frame.cs&7)==7) && (frame.cs != *cs)) {
LDT_ENTRY le;
if (GetThreadSelectorEntry( thread->handle, frame.cs, &le) &&
(le.HighWord.Bits.Type & 0x08)) { /* code segment */
/* it is very uncommon to push a code segment cs as
* a parameter, so this should work in most cases */
*cs = possible_cs = frame.cs;
}
}
}
code.seg = *cs;
code.off = frame.ip;
addr->off = frame.bp & ~1;
DEBUG_ForceFrame(addr, &code, frameno, MODE_16, noisy,
possible_cs ? ", far call assumed" : NULL );
addr.Mode = AddrModeFlat;
addr.Offset = frames[dbg_curr_frame].InstructionOffset;
source_list_from_addr(&addr, 0);
return TRUE;
}
static BOOL DEBUG_Frame32(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
int stack_get_frame(SYMBOL_INFO* symbol, IMAGEHLP_STACK_FRAME* ihsf)
{
FRAME32 frame;
void* p = (void*)DEBUG_ToLinear(addr);
DBG_ADDR code;
DWORD old_bp = addr->off;
if (!p) return FALSE;
if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
if (noisy) DEBUG_InvalAddr(addr);
return FALSE;
}
if (!frame.ip) return FALSE;
code.seg = *cs;
code.off = frame.ip;
addr->off = frame.bp;
DEBUG_ForceFrame(addr, &code, frameno, MODE_32, noisy, NULL);
if (addr->off == old_bp) return FALSE;
return TRUE;
}
#endif
/***********************************************************************
* DEBUG_BackTrace
*
* Display a stack back-trace.
*/
void DEBUG_BackTrace(DWORD tid, BOOL noisy)
{
#ifdef __i386
DBG_ADDR addr, sw_addr, code, tmp;
unsigned int ss, cs;
int frameno = 0, is16, ok;
DWORD next_switch, cur_switch, p;
STACK16FRAME frame16;
STACK32FRAME frame32;
char ch;
CONTEXT ctx;
DBG_THREAD* thread;
int copy_nframe = 0;
int copy_curr_frame = 0;
struct bt_info* copy_frames = NULL;
if (noisy) DEBUG_Printf("Backtrace:\n");
if (tid == DEBUG_CurrTid)
{
ctx = DEBUG_context;
thread = DEBUG_CurrThread;
if (frames) DBG_free( frames );
/* frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) ); */
}
else
{
thread = DEBUG_GetThread(DEBUG_CurrProcess, tid);
if (!thread)
{
DEBUG_Printf("Unknown thread id (0x%08lx) in current process\n", tid);
return;
}
memset(&ctx, 0, sizeof(ctx));
ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_SEGMENTS;
if ( SuspendThread( thread->handle ) == -1 ||
!GetThreadContext( thread->handle, &ctx ))
{
DEBUG_Printf("Can't get context for thread id (0x%08lx) in current process\n", tid);
return;
}
/* need to avoid trashing stack frame for current thread */
copy_nframe = nframe;
copy_frames = frames;
copy_curr_frame = curr_frame;
curr_frame = 0;
}
nframe = 0;
frames = NULL;
cs = ctx.SegCs;
ss = ctx.SegSs;
if (DEBUG_IsSelectorSystem(ss)) ss = 0;
if (DEBUG_IsSelectorSystem(cs)) cs = 0;
/* first stack frame from registers */
switch (DEBUG_GetSelectorType(ss))
{
case MODE_32:
code.seg = cs;
code.off = ctx.Eip;
addr.seg = ss;
addr.off = ctx.Ebp;
DEBUG_ForceFrame( &addr, &code, frameno, MODE_32, noisy, NULL );
if (!(code.seg || code.off)) {
/* trying to execute a null pointer... yuck...
* if it was a call to null, the return EIP should be
* available at SS:ESP, so let's try to retrieve it */
tmp.seg = ss;
tmp.off = ctx.Esp;
if (DEBUG_READ_MEM((void *)DEBUG_ToLinear(&tmp), &code.off, sizeof(code.off))) {
DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_32, noisy, ", null call assumed" );
}
}
is16 = FALSE;
break;
case MODE_16:
case MODE_VM86:
code.seg = cs;
code.off = LOWORD(ctx.Eip);
addr.seg = ss;
addr.off = LOWORD(ctx.Ebp);
DEBUG_ForceFrame( &addr, &code, frameno, MODE_16, noisy, NULL );
is16 = TRUE;
break;
default:
if (noisy) DEBUG_Printf("Bad segment '%x'\n", ss);
return;
}
/* cur_switch holds address of curr_stack's field in TEB in debuggee
* address space
/*
* If we don't have a valid backtrace, then just return.
*/
cur_switch = (DWORD)thread->teb + OFFSET_OF(TEB, cur_stack);
if (!DEBUG_READ_MEM((void*)cur_switch, &next_switch, sizeof(next_switch))) {
if (noisy) DEBUG_Printf("Can't read TEB:cur_stack\n");
return;
if (frames == NULL) return FALSE;
/*
* If we don't know what the current function is, then we also have
* nothing to report here.
*/
SymFromAddr(dbg_curr_process->handle, frames[dbg_curr_frame].InstructionOffset,
NULL, symbol);
if (ihsf) *ihsf = frames[dbg_curr_frame];
return TRUE;
}
void stack_backtrace(DWORD tid, BOOL noisy)
{
STACKFRAME sf;
CONTEXT ctx;
struct dbg_thread* thread;
unsigned nf;
if (tid == dbg_curr_tid)
{
ctx = dbg_context; /* as StackWalk may modify it... */
thread = dbg_curr_thread;
if (frames) HeapFree(GetProcessHeap(), 0, frames);
frames = NULL;
}
else
{
thread = dbg_get_thread(dbg_curr_process, tid);
if (!thread)
{
dbg_printf("Unknown thread id (0x%08lx) in current process\n", tid);
return;
}
memset(&ctx, 0, sizeof(ctx));
ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_SEGMENTS;
if (SuspendThread(thread->handle) == -1 ||
!GetThreadContext(thread->handle, &ctx))
{
dbg_printf("Can't get context for thread 0x%lx in current process\n",
tid);
return;
}
}
if (is16) {
if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
(unsigned long)(STACK32FRAME*)next_switch );
return;
}
cur_switch = (DWORD)frame32.frame16;
sw_addr.seg = SELECTOROF(cur_switch);
sw_addr.off = OFFSETOF(cur_switch);
} else {
tmp.seg = SELECTOROF(next_switch);
tmp.off = OFFSETOF(next_switch);
p = DEBUG_ToLinear(&tmp);
nf = 0;
memset(&sf, 0, sizeof(sf));
memory_get_current_frame(&sf.AddrFrame);
memory_get_current_pc(&sf.AddrPC);
if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
(unsigned long)(STACK16FRAME*)p );
return;
}
cur_switch = (DWORD)frame16.frame32;
sw_addr.seg = ss;
sw_addr.off = cur_switch;
}
if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
sw_addr.seg = (DWORD)-1;
sw_addr.off = (DWORD)-1;
}
for (ok = TRUE; ok;) {
if ((frames[frameno].ss == sw_addr.seg) &&
sw_addr.off && (frames[frameno].ebp >= sw_addr.off))
if (noisy) dbg_printf("Backtrace:\n");
while (StackWalk(IMAGE_FILE_MACHINE_I386, dbg_curr_process->handle,
thread->handle, &sf, &ctx, NULL, SymFunctionTableAccess,
SymGetModuleBase, NULL))
{
if (tid == dbg_curr_tid)
{
/* 16<->32 switch...
* yes, I know this is confusing, it gave me a headache too */
if (is16) {
frames = dbg_heap_realloc(frames,
(nf + 1) * sizeof(IMAGEHLP_STACK_FRAME));
if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
(unsigned long)(STACK32FRAME*)next_switch );
return;
}
code.seg = 0;
code.off = frame32.retaddr;
cs = 0;
addr.seg = 0;
addr.off = frame32.ebp;
DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_32, noisy, NULL );
next_switch = cur_switch;
tmp.seg = SELECTOROF(next_switch);
tmp.off = OFFSETOF(next_switch);
p = DEBUG_ToLinear(&tmp);
if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
(unsigned long)(STACK16FRAME*)p );
return;
}
cur_switch = (DWORD)frame16.frame32;
sw_addr.seg = 0;
sw_addr.off = cur_switch;
is16 = FALSE;
} else {
tmp.seg = SELECTOROF(next_switch);
tmp.off = OFFSETOF(next_switch);
p = DEBUG_ToLinear(&tmp);
if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
(unsigned long)(STACK16FRAME*)p );
return;
}
code.seg = frame16.cs;
code.off = frame16.ip;
cs = frame16.cs;
addr.seg = SELECTOROF(next_switch);
addr.off = frame16.bp;
DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_16, noisy, NULL );
next_switch = cur_switch;
if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
(unsigned long)(STACK32FRAME*)next_switch );
return;
}
cur_switch = (DWORD)frame32.frame16;
sw_addr.seg = SELECTOROF(cur_switch);
sw_addr.off = OFFSETOF(cur_switch);
is16 = TRUE;
}
if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
sw_addr.seg = (DWORD)-1;
sw_addr.off = (DWORD)-1;
}
} else {
/* ordinary stack frame */
ok = is16 ? DEBUG_Frame16( thread, &addr, &cs, ++frameno, noisy)
: DEBUG_Frame32( &addr, &cs, ++frameno, noisy);
}
frames[nf].InstructionOffset = (unsigned long)memory_to_linear_addr(&sf.AddrPC);
frames[nf].FrameOffset = (unsigned long)memory_to_linear_addr(&sf.AddrFrame);
}
if (noisy)
{
dbg_printf("%s%d ",
(tid == dbg_curr_tid && nf == dbg_curr_frame ? "=>" : " "),
nf + 1);
print_addr_and_args(&sf.AddrPC, &sf.AddrFrame);
dbg_printf(" (");
print_bare_address(&sf.AddrFrame);
dbg_printf(")\n");
}
nf++;
}
if (noisy) DEBUG_Printf("\n");
if (tid != DEBUG_CurrTid)
if (tid == dbg_curr_tid)
{
ResumeThread( thread->handle );
/* restore stack frame for current thread */
if (frames) DBG_free( frames );
frames = copy_frames;
nframe = copy_nframe;
curr_frame = copy_curr_frame;
nframe = nf;
}
else
{
ResumeThread(thread->handle);
}
#endif
}
int
DEBUG_SetFrame(int newframe)
{
#ifdef __i386__
int rtn = FALSE;
curr_frame = newframe;
if( curr_frame >= nframe )
{
curr_frame = nframe - 1;
}
if( curr_frame < 0 )
{
curr_frame = 0;
}
if( frames && frames[curr_frame].frame.list.sourcefile != NULL )
{
DEBUG_List(&frames[curr_frame].frame.list, NULL, 0);
}
rtn = TRUE;
return (rtn);
#else /* __i386__ */
return FALSE;
#endif /* __i386__ */
}
int
DEBUG_GetCurrentFrame(struct name_hash ** name, unsigned int * eip,
unsigned int * ebp)
{
#ifdef __i386__
/*
* If we don't have a valid backtrace, then just return.
*/
if( frames == NULL )
{
return FALSE;
}
/*
* If we don't know what the current function is, then we also have
* nothing to report here.
*/
if( frames[curr_frame].frame.sym == NULL )
{
return FALSE;
}
*name = frames[curr_frame].frame.sym;
*eip = frames[curr_frame].eip;
*ebp = frames[curr_frame].ebp;
return TRUE;
#else /* __i386__ */
return FALSE;
#endif /* __i386__ */
}

560
programs/winedbg/symbol.c Normal file
View File

@ -0,0 +1,560 @@
/*
* Generate hash tables for Wine debugger symbols
*
* Copyright (C) 1993, Eric Youngdale.
* 2004, Eric Pouech.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "debugger.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
static BOOL symbol_get_debug_start(DWORD mod_base, DWORD typeid, DWORD* start)
{
DWORD count, tag;
char buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
TI_FINDCHILDREN_PARAMS* fcp = (TI_FINDCHILDREN_PARAMS*)buffer;
int i;
if (!types_get_info(mod_base, typeid, TI_GET_CHILDRENCOUNT, &count)) return FALSE;
fcp->Start = 0;
while (count)
{
fcp->Count = min(count, 256);
if (types_get_info(mod_base, typeid, TI_FINDCHILDREN, fcp))
{
for (i = 0; i < min(fcp->Count, count); i++)
{
types_get_info(mod_base, fcp->ChildId[i], TI_GET_SYMTAG, &tag);
if (tag != SymTagFuncDebugStart) continue;
return types_get_info(mod_base, fcp->ChildId[i], TI_GET_ADDRESS, start);
}
count -= min(count, 256);
fcp->Start += 256;
}
}
return FALSE;
}
struct sgv_data
{
#define NUMDBGV 100
struct {
/* FIXME: NUMDBGV should be made variable */
struct dbg_lvalue lvalue;
DWORD flags;
} syms[NUMDBGV]; /* out : will be filled in with various found symbols */
int num; /* out : number of found symbols */
int num_thunks; /* out : number of thunks found */
const char* name; /* in : name of symbol to look up */
const char* filename; /* in (opt): filename where to look up symbol */
int lineno; /* in (opt): line number in filename where to look up symbol */
unsigned bp_disp : 1, /* in : whether if we take into account func address or func first displayable insn */
do_thunks : 1; /* in : whether we return thunks tags */
IMAGEHLP_STACK_FRAME ihsf; /* in : frame for local & parameter variables look up */
};
static BOOL CALLBACK sgv_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
{
struct sgv_data* sgv = (struct sgv_data*)ctx;
DWORD addr;
IMAGEHLP_LINE il;
unsigned cookie = DLV_TARGET, insp;
if (sym->Flags & SYMFLAG_REGISTER)
{
const struct dbg_internal_var* div;
if (dbg_curr_frame != 0)
{
dbg_printf(" %s (register): << cannot display, not in correct frame\n",
sym->Name);
return TRUE;
}
for (div = dbg_context_vars; div->name && div->val != sym->Register; div++);
if (!div->name)
{
dbg_printf(" %s (register): couldn't find register %lu\n",
sym->Name, sym->Register);
return TRUE;
}
addr = (DWORD)div->pval;
cookie = DLV_HOST;
}
else if (sym->Flags & SYMFLAG_FRAMEREL)
{
ULONG offset;
types_get_info(sym->ModBase, sym->TypeIndex, TI_GET_OFFSET, &offset);
addr = sgv->ihsf.FrameOffset + offset;
}
else if (sym->Flags & SYMFLAG_THUNK)
{
if (!sgv->do_thunks) return TRUE;
sgv->num_thunks++;
addr = sym->Address;
}
else
{
il.SizeOfStruct = sizeof(il);
SymGetLineFromAddr(dbg_curr_process->handle, sym->Address, NULL, &il);
if (sgv->filename && strcmp(sgv->filename, il.FileName))
{
WINE_FIXME("File name mismatch (%s / %s)\n", sgv->filename, il.FileName);
return TRUE;
}
if (sgv->lineno == -1)
{
if (!sgv->bp_disp ||
!symbol_get_debug_start(sym->ModBase, sym->TypeIndex, &addr))
addr = sym->Address;
}
else
{
addr = 0;
do
{
if (sgv->lineno == il.LineNumber)
{
addr = il.Address;
break;
}
} while (SymGetLineNext(dbg_curr_process->handle, &il));
if (!addr)
{
WINE_FIXME("No line (%d) found for %s (setting to symbol)\n",
sgv->lineno, sgv->name);
addr = sym->Address;
}
}
}
if (sgv->num >= NUMDBGV)
{
dbg_printf("Too many addresses for symbol '%s', limiting the first %d\n",
sgv->name, NUMDBGV);
return FALSE;
}
WINE_TRACE("==> %s %s%s%s%s%s%s\n",
sym->Name,
(sym->Flags & SYMFLAG_FUNCTION) ? "func " : "",
(sym->Flags & SYMFLAG_FRAMEREL) ? "framerel " : "",
(sym->Flags & SYMFLAG_REGISTER) ? "register " : "",
(sym->Flags & SYMFLAG_REGREL) ? "regrel " : "",
(sym->Flags & SYMFLAG_PARAMETER) ? "param " : "",
(sym->Flags & SYMFLAG_THUNK) ? "thunk " : "");
/* always keep the thunks at end of the array */
insp = sgv->num;
if (sgv->num_thunks && !(sym->Flags & SYMFLAG_THUNK))
{
insp -= sgv->num_thunks;
memmove(&sgv->syms[insp + 1], &sgv->syms[insp],
sizeof(sgv->syms[0]) * sgv->num_thunks);
}
sgv->syms[insp].lvalue.addr.Mode = AddrModeFlat;
sgv->syms[insp].lvalue.addr.Offset = addr;
types_get_info(sym->ModBase, sym->TypeIndex, TI_GET_TYPE,
&sgv->syms[insp].lvalue.typeid);
sgv->syms[insp].lvalue.cookie = cookie;
sgv->syms[insp].flags = sym->Flags;
sgv->num++;
return TRUE;
}
/***********************************************************************
* symbol_get_lvalue
*
* Get the address of a named symbol.
* Return values:
* sglv_found: if the symbol is found
* sglv_unknown: if the symbol isn't found
* sglv_aborted: some error occurred (likely, many symbols of same name exist,
* and user didn't pick one of them)
*/
enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno,
struct dbg_lvalue* rtn, BOOL bp_disp)
{
struct sgv_data sgv;
int i = 0;
char tmp[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* si = (SYMBOL_INFO*)tmp;
char buffer[512];
if (strlen(name) + 4 > sizeof(buffer))
{
WINE_WARN("Too long symbol (%s)\n", name);
return sglv_unknown;
}
sgv.num = 0;
sgv.num_thunks = 0;
sgv.name = &buffer[2];
sgv.filename = NULL;
sgv.lineno = lineno;
sgv.bp_disp = bp_disp ? TRUE : FALSE;
sgv.do_thunks = DBG_IVAR(AlwaysShowThunks);
buffer[0] = '*';
buffer[1] = '!';
strcpy(&buffer[2], name);
if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
return sglv_unknown;
if (!sgv.num && (name[0] != '_'))
{
buffer[2] = '_';
strcpy(&buffer[3], name);
if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
return sglv_unknown;
}
/* now grab local symbols */
si->SizeOfStruct = sizeof(*si);
si->MaxNameLen = 256;
if (stack_get_frame(si, &sgv.ihsf) && sgv.num < NUMDBGV)
{
if (SymSetContext(dbg_curr_process->handle, &sgv.ihsf, NULL))
SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv);
}
if (!sgv.num)
{
dbg_printf("No symbols found for %s\n", name);
return sglv_unknown;
}
if (dbg_interactiveP)
{
if (sgv.num - sgv.num_thunks > 1 || /* many symbols non thunks (and showing only non thunks) */
(sgv.num > 1 && DBG_IVAR(AlwaysShowThunks)) || /* many symbols (showing symbols & thunks) */
(sgv.num == sgv.num_thunks && sgv.num_thunks > 1))
{
dbg_printf("Many symbols with name '%s', "
"choose the one you want (<cr> to abort):\n", name);
for (i = 0; i < sgv.num; i++)
{
if (sgv.num - sgv.num_thunks > 1 && (sgv.syms[i].flags & SYMFLAG_THUNK) && !DBG_IVAR(AlwaysShowThunks))
continue;
dbg_printf("[%d]: ", i + 1);
if (sgv.syms[i].flags & SYMFLAG_LOCAL)
{
dbg_printf("local variable of %s\n", si->Name);
}
else if (sgv.syms[i].flags & SYMFLAG_PARAMETER)
{
dbg_printf("parameter of %s\n", si->Name);
}
else if (sgv.syms[i].flags & SYMFLAG_THUNK)
{
print_address(&sgv.syms[i].lvalue.addr, TRUE);
/* FIXME: should display where the thunks points to */
dbg_printf(" thunk %s\n", name);
}
else
{
print_address(&sgv.syms[i].lvalue.addr, TRUE);
dbg_printf("\n");
}
}
do
{
i = 0;
if (input_read_line("=> ", buffer, sizeof(buffer)))
{
if (buffer[0] == '\0') return sglv_aborted;
i = atoi(buffer);
if (i < 1 || i > sgv.num)
dbg_printf("Invalid choice %d\n", i);
}
} while (i < 1 || i > sgv.num);
/* The array is 0-based, but the choices are 1..n,
* so we have to subtract one before returning.
*/
i--;
}
}
else
{
dbg_printf("More than one symbol named %s, picking the first one\n", name);
i = 0;
}
*rtn = sgv.syms[i].lvalue;
return sglv_found;
}
/***********************************************************************
* symbol_read_symtable
*
* Read a symbol file into the hash table.
*/
void symbol_read_symtable(const char* filename, unsigned long offset)
{
dbg_printf("No longer supported\n");
#if 0
/* FIXME: have to implement SymAddSymbol in dbghelp, but likely to link this with
* a loaded module !!
*/
FILE* symbolfile;
unsigned addr;
char type;
char* cpnt;
char buffer[256];
char name[256];
if (!(symbolfile = fopen(filename, "r")))
{
WINE_WARN("Unable to open symbol table %s\n", filename);
return;
}
dbg_printf("Reading symbols from file %s\n", filename);
while (1)
{
fgets(buffer, sizeof(buffer), symbolfile);
if (feof(symbolfile)) break;
/* Strip any text after a # sign (i.e. comments) */
cpnt = strchr(buffer, '#');
if (cpnt) *cpnt = '\0';
/* Quietly ignore any lines that have just whitespace */
for (cpnt = buffer; *cpnt; cpnt++)
{
if (*cpnt != ' ' && *cpnt != '\t') break;
}
if (!*cpnt || *cpnt == '\n') continue;
if (sscanf(buffer, "%lx %c %s", &addr, &type, name) == 3)
{
if (value.addr.off + offset < value.addr.off)
WINE_WARN("Address wrap around\n");
value.addr.off += offset;
SymAddSymbol(current_process->handle, BaseOfDll,
name, addr, 0, 0);
}
}
fclose(symbolfile);
#endif
}
/***********************************************************************
* symbol_get_function_line_status
*
* Find the symbol nearest to a given address.
*/
enum dbg_line_status symbol_get_function_line_status(const ADDRESS* addr)
{
IMAGEHLP_LINE il;
DWORD disp, start, size;
DWORD lin = (DWORD)memory_to_linear_addr(addr);
char buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* sym = (SYMBOL_INFO*)buffer;
il.SizeOfStruct = sizeof(il);
sym->SizeOfStruct = sizeof(SYMBOL_INFO);
sym->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
/* do we have some info for lin address ? */
if (!SymFromAddr(dbg_curr_process->handle, lin, NULL, sym))
return dbg_no_line_info;
switch (sym->Tag)
{
case SymTagThunk:
/* FIXME: so far dbghelp doesn't return the 16 <=> 32 thunks
* and furthermore, we no longer take care of them !!!
*/
return dbg_in_a_thunk;
case SymTagFunction:
case SymTagPublicSymbol: break;
default:
WINE_FIXME("Unexpected sym-tag 0x%08lx\n", sym->Tag);
case SymTagData:
return dbg_no_line_info;
}
/* we should have a function now */
if (!SymGetLineFromAddr(dbg_curr_process->handle, lin, &disp, &il))
return dbg_no_line_info;
if (symbol_get_debug_start(sym->ModBase, sym->TypeIndex, &start) && lin < start)
return dbg_not_on_a_line_number;
if (!types_get_info(sym->ModBase, sym->TypeIndex, TI_GET_LENGTH, &size) || size == 0)
size = 0x100000;
if (il.FileName && il.FileName[0] && disp < size)
return (disp == 0) ? dbg_on_a_line_number : dbg_not_on_a_line_number;
return dbg_no_line_info;
}
/***********************************************************************
* symbol_get_line
*
* Find the symbol nearest to a given address.
* Returns sourcefile name and line number in a format that the listing
* handler can deal with.
*/
BOOL symbol_get_line(const char* filename, const char* name, IMAGEHLP_LINE* line)
{
struct sgv_data sgv;
char buffer[512];
sgv.num = 0;
sgv.num_thunks = 0;
sgv.name = &buffer[2];
sgv.filename = filename;
sgv.lineno = -1;
sgv.bp_disp = FALSE;
sgv.do_thunks = FALSE;
buffer[0] = '*';
buffer[1] = '!';
strcpy(&buffer[2], name);
if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
return sglv_unknown;
if (!sgv.num && (name[0] != '_'))
{
buffer[2] = '_';
strcpy(&buffer[3], name);
if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
return sglv_unknown;
}
switch (sgv.num)
{
case 0:
if (filename) dbg_printf("No such function %s in %s\n", name, filename);
else dbg_printf("No such function %s\n", name);
return FALSE;
default:
WINE_FIXME("Several found, returning first (may not be what you want)...\n");
case 1:
return SymGetLineFromAddr(dbg_curr_process->handle,
(DWORD)memory_to_linear_addr(&sgv.syms[0].lvalue.addr),
NULL, line);
}
return TRUE;
}
static BOOL CALLBACK info_locals_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
{
DWORD tid;
ULONG v, val;
const char* explain = NULL;
char buf[128];
dbg_printf("\t");
types_get_info(sym->ModBase, sym->TypeIndex, TI_GET_TYPE, &tid);
types_print_type(sym->ModBase, tid, FALSE);
if (sym->Flags & SYMFLAG_LOCAL) explain = "local";
else if (sym->Flags & SYMFLAG_PARAMETER) explain = "parameter";
else if (sym->Flags & SYMFLAG_REGISTER) explain = buf;
if (sym->Flags & SYMFLAG_REGISTER)
{
const struct dbg_internal_var* div;
if (dbg_curr_frame != 0)
{
dbg_printf(" %s (register): << cannot display, not in correct frame\n",
sym->Name);
return TRUE;
}
for (div = dbg_context_vars; div->name; div++)
{
if (div->val == sym->Register)
{
val = *div->pval;
sprintf(buf, "local in register %s", div->name);
break;
}
}
}
else if (sym->Flags & SYMFLAG_FRAMEREL)
{
types_get_info(sym->ModBase, sym->TypeIndex, TI_GET_OFFSET, &v);
v += ((IMAGEHLP_STACK_FRAME*)ctx)->FrameOffset;
dbg_read_memory_verbose((void*)v, &val, sizeof(val));
}
dbg_printf(" %s = 0x%8.8lx (%s)\n", sym->Name, val, explain);
return TRUE;
}
int symbol_info_locals(void)
{
IMAGEHLP_STACK_FRAME ihsf;
char buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* si = (SYMBOL_INFO*)buffer;
si->SizeOfStruct = sizeof(*si);
si->MaxNameLen = 256;
if (stack_get_frame(si, &ihsf))
{
dbg_printf("%s:\n", si->Name);
if (SymSetContext(dbg_curr_process->handle, &ihsf, NULL))
SymEnumSymbols(dbg_curr_process->handle, 0, NULL, info_locals_cb, &ihsf);
}
return TRUE;
}
static BOOL CALLBACK symbols_info_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
{
DWORD type;
dbg_printf("%08lx: %s (", sym->Address, sym->Name);
if (sym->TypeIndex != dbg_itype_none && sym->TypeIndex != 0 &&
types_get_info(sym->ModBase, sym->TypeIndex, TI_GET_TYPE, &type))
{
types_print_type(sym->ModBase, type, FALSE);
}
dbg_printf(")\n");
return TRUE;
}
void symbol_info(const char* str)
{
char buffer[512];
if (strlen(str) + 3 >= sizeof(buffer))
{
dbg_printf("Symbol too long (%s)\n", str);
return;
}
buffer[0] = '*';
buffer[1] = '!';
strcpy(&buffer[2], str);
SymEnumSymbols(dbg_curr_process->handle, 0, buffer, symbols_info_cb, NULL);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,370 @@
.TH WINEDBG 1 "May 2004" "Wine Manpage" "Wine Developers Manual"
.SH NAME
winedbg \- Wine's debugger
.SH SYNOPSIS
.BR "winedbg " [ " --auto" " |"
.BI "--gdb"
.RI "[" " options " "] ] ["
.BI "program name"
.RI "["
.BI "program arguments"
.RI "] |"
.BI "pid"
.RI "]"
.SH DESCRIPTION
.B winedbg
is a debugger for Wine. It allows:
.RS 4
+ debugging native Win32 applications
.nf
+ debugging Winelib applications.
.nf
+ being a drop-in replacement for Dr Watson
.RE
.PP
.SH MODES
\fBwinedbg\fR can be used in three modes. The first argument to the
program determines the mode winedbg will run in.
.IP \fBdefault\fR
Without any explicit mode, this is standard \fBwinedbg\fR operating
mode. \fBwinedbg\fR will act as the front end for the user.
.IP \fB--auto\fR
This mode is used when \fBwinedbg\fR is setup in \fIAeDebug\fR
registry entry as the default debugger. \fBwinedbg will then will
display basic information about a\fR crash. This is usefull for users
who don't want to debug a crash, but rather gather relevant
information about the crash to be sent to developers.
.IP \fB--gdb\fR
\fBwinedbg\fR will be used as a proxy for \fBgdb\fR. \fBgdb\fR will be
the front end for command handling, and \fBwinedbg\fR will proxy all
debugging requests from \fBgdb\fR to the Win32 APIs.
.SH OPTIONS
Only the \fBgdb\fR proxy mode allows some options:
.PP
.IP \fI--no-start\fR \fBgdb\fR will not be automatically
started. Relevant information for starting \fBgdb\fR are printed on
screen. This is somehow usefull when not directly using \fBgdb\fR but
some graphical front-ends, like \fBddd\fR or \fBkgbd\fR.
.IP \fI--with-xterm\fR
This will run \fBgdb\fR in its own xterm instead of using the current
Unix console for textual display.
.PP
The rest of the command line, when passed, is used to identify which
programs, if any, has to debugged:
.IP \fBprogram\ name\fR
This is the name of an executable to start for a debugging
session. \fBwinedbg\fR will actually create a process with this
executable. If \fBprograms arguments\fR are also given, they will be
used as arguments for creating the process to be debugged.
.IP \fBpid\fR
\fBgdb\fR will attach to the process which pid is \fBpid\fR (pids
refer to Win32 pids, not Unix pids). Use the \fIinfo proc\fR
\fBwinedbg\fR command to list running processes and their Win32 pids.
.IP \fBdefaut\fR
If nothing is specified, you will enter the debugger without any run
nor attached process. You'll have to do the job yourself.
.SH COMMANDS
.SS Default mode:
.PP
Most of commands used in \fBwinedbg\fR are similar to the ones from
\fBgdb\fR. Please refer to the \fBgdb\fR documentations for some more
details. See the \fIgdb\ differences\fR section later on to get a list
of variations from \fBgdb\fR commands.
.PP
\fIMisc. commands\fR
.IP \fBabort\fR
Aborts the debugger.
.IP \fBquit\fR
Exits the debugger.
.IP \fBattach\ N\fR
Attach to a Wine-process (\fBN\fR is its ID, numeric or hexadecimal).
IDs can be obtained using the \fBinfo\ process\fR command. Note the
\fBinfo\ process\fR command returns hexadecimal values
.IP
.IP \fBdetach\fR
Detach from a Wine-process.
.PP
\fIHelp commands\fR
.IP \fBhelp\fR
Prints some help on the commands.
.IP \fBhelp\ info\fR
Prints some help on info commands
.PP
\fIFlow control commands\fR
.IP \fBcont\fR
Continue execution until next breakpoint or exception.
.IP \fBpass\fR
Pass the exception event up to the filter chain.
.IP \fBstep\fR
Continue execution until next C line of code (enters function call)
.IP \fBnext\fR
Continue execution until next C line of code (doesn't enter function
call)
.IP \fBstepi\fR
Execute next assembly instruction (enters function call)
.IP \fBnexti\fR
Execute next assembly instruction (doesn't enter function call)
.IP \fBfinish\fR
Excute until return of current function is reached.
.PP
\fBcont\fR, \fBstep\fR, \fBnext\fR, \fBstepi\fR, \fBnexti\fR can be
postfixed by a number (N), meaning that the command must be executed N
times before control is returned to the user.
.PP
\fIBreakpoints, watchpoints
.IP \fBenable\ N\fR
Enables (break|watch)-point #\fBN\fR
.IP \fBdisable\fR
Disables (break|watch)-point \fB#N\fR
.IP \fBdelete\fR
Deletes (break|watch)-point #\fBN\fR
.IP \fBcond\ N\fR
Removes any existing condition to (break|watch)-point \fBN\fR
.IP \fBcond\ N\ <expr>\fR
Adds condition \fB<expr>\fR to (break|watch)-point
#\fBN\fR. \fB<expr>\fR will be evaluated each time the
(break|watch)-point is hit. If the result is a zero value, the
breakpoint isn't triggered.
.IP \fBbreak\ *\ N\fR
Adds a breakpoint at address \fBN\fR
.IP \fBbreak\ <id>\fR
Adds a breakpoint at the address of symbol \fB<id>\fR
.IP \fBbreak <id> N\fR
Adds a breakpoint at the line \fBN\fR inside symbol \fB<id>\fR.
.IP \fBbreak\ N\fR
Adds a breakpoint at line \fBN\fR of current source file.
.IP \fBbreak\fR
Adds a breakpoint at current \f$PC\fR address.
.IP \fBwatch\ *\ N\fR
Adds a watch command (on write) at address \fBN\fR (on 4 bytes).
.IP \fBwatch\ <id>\fR
Adds a watch command (on write) at the address of symbol
\fB<id>\fR. Size depends on size of \fB<id>\fR.
.IP \fBinfo\ break\fR
Lists all (break|watch)-points (with their state).
.PP
You can use the symbol \fBEntryPoint\fR to stand for the entry point of the Dll.
.PP
When setting a (break|watch)-point by \fB<id>\fR, if the symbol cannot
be found (for example, the symbol is contained in a not yet loaded
module), \fBwinedbg\fR will recall the name of the symbol and will try
to set the breakpoint each time a new module is loaded (until it succeeds).
.PP
\fIStack manipulation\fR
.IP \fBbt\fR
Print calling stack of current thread.
.IP \fBbt\ N\fR
Print calling stack of thread of ID \fBN\fR. Note: this doesn't change
the position of the current frame as manipulated by the \fBup\fR &
\fBdn\fR commands).
.IP \fBup\fR
Goes up one frame in current thread's stack
.IP \fBup\ N\fR
Goes up \fBN\fR frames in current thread's stack
.IP \fBdn\fR
Goes down one frame in current thread's stack
.IP \fBdn\ N\fR
Goes down \fBN\fR frames in current thread's stack
.IP \fBframe N\fR
Sets \fBN\fR as the current frame for current thread's stack.
.IP \fBinfo\ locals\fR
Prints information on local variables for current function frame.
.PP
\fIDirectory & source file manipulation\fR
.IP \fBshow\ dir\fR
Prints the list of dir:s where source files are looked for.
.IP \fBdir\ <pathname>\fR
Adds \fB<pathname>\fR to the list of dir:s where to look for source
files
.IP \fBdir\fR
Deletes the list of dir:s where to look for source files
.IP \fBsymbolfile\ <pathname>\fR
Loads external symbol definition symbolfile \fB<pathname>\fR
.IP \fBsymbolfile\ <pathname>\ N\fR
Loads external symbol definition symbolfile \fB<pathname>\fR (applying
an offset of \fBN\fR to addresses)
.IP \fBlist\fR
Lists 10 source lines forwards from current position.
.IP \fBlist\ -\fR
Lists 10 source lines backwards from current position
.IP \fBlist\ N\fR
Lists 10 source lines from line #\fBN\fR in current file
.IP \fBlist\ <pathname>:N\fR
Lists 10 source lines from line #\fBN\fR in file \fB<pathname>\fR
.IP \fBlist\ <id>\fR
Lists 10 source lines of function \fB<id>\fR
.IP \fBlist\ *\ N\fR
Lists 10 source lines from address \fBN\fR
.PP
You can specify the end target (to change the 10 lines value) using
the ',' separator. For example:
.nf
.IP \fBlist\ 123,\ 234\fR
lists source lines from line 123 up to line 234 in current file
.nf
.IP \fBlist\ foo.c:1,56\fR
lists source lines from line 1 up to 56 in file foo.c
.PP
\fIDisplaying\fR
.PP
A display is an expression that's evaluated and printed after the
execution of any \fBwinedbg\fR's command.
.IP \fBdisplay\fR
.IP \fBinfo\ display\fR
Lists the active displays
.IP \fBdisplay\ <expr>\fR
Adds a display for expression \f<expr>\fR
.IP \fBdisplay\ /fmt\ <expr>\fR
Adds a display for expression \fB<expr>\fR. Printing evaluated
\fB<expr>\fR is done using the given format (see \fBprint\ command\fR
for more on formats)
.IP \fBdel\ display\ N\fR
.IP \fBundisplay\ N\fR
Deletes display #\fBN\fR
.PP
\fIDisassembly\fR
.IP \fBdisas\fR
Disassemble from current position
.IP \fBdisas\ <expr>\fR
Disassemble from address \fB<expr>\fR
.IP \fBdisas\ <expr>,<expr>\fR
Disassembles code between addresses specified by the two \fB<expr>\fR:s
.PP
\fIMemory\ (reading,\ writing,\ typing)\fR
.IP \fBx\ <expr>\fR
Examines memory at \fB<expr>\fR address
.IP \fBx\ /fmt\ <expr>\fR
Examines memory at \fB<expr>\fR address using format \fI/fmt\fR
.IP \fBprint\ <expr>\fR
Prints the value of \fB<expr>\fR (possibly using its type)
.IP \fBprint\ /fmt\ <expr>\fR
Prints the value of \fB<expr>\fR (possibly using its type)
.IP \fBset\ <var>\ =\ <expr>\fR
Writes the value of \fB<expr>\fR in \fB<var>\fR variable.
.IP \fBwhatis\ <expr>\fR
Prints the C type of expression \fB<expr>\fR
.PP
.IP \fI/fmt\fR
is either \fI/<letter>\fR or \fI/<count><letter>\fR. \fI<letter>\fR
can be:
.RS 4
.IP s
an ASCII string
.IP u
an Unicode UTF16 string
.IP i
instructions (disassemble)
.IP x
32 bit unsigned hexadecimal integer
.IP d
32 bit signed decimal integer
.IP w
16 bit unsigned hexadecimal integer
.IP c
character (only printable 0x20-0x7f are actually printed)
.IP b
8 bit unsigned hexadecimal integer
.IP g
Win32 GUID
.RE
.PP
\fIExpressions\fR
.PP
Expressions in Wine Debugger are mostly written in a C form. However,
there are a few discrepancies:
.PP
.RS 4
Identifiers can take a '!' in their names. This allows mainly to
specify a module where to look the module from: \fIUSER32!CreateWindowExA\fR.
.PP
In cast operation, when specifying a structure or an union, you must
use the struct or union key word (even if your program uses a typedef).
.RE
.PP
When specifying an identifier \fB<id>\fR, if several symbols with
this name exist, the debugger will prompt for the symbol you want to
use. Pick up the one you want from its number.
.PP
\fIInformation on Wine's internals\fR
.IP \fBinfo\ class\fR
Lists all Windows' class registered in Wine
.IP \fBinfo\ class\ <id>\fR
Prints information on Windows's class \fB<id>\fR
.IP \fBinfo\ share\fR
Lists all the dynamic libraries loaded in the debugged program
(including .so files, NE and PE DLLs)
.IP \fBinfo\ share\ N\fR
Prints information on module at address \fBN\fR
.IP \fBinfo\ regs\fR
Prints the value of the CPU registers
.IP \fBinfo\ segment\fR
Lists all allocated segments (i386 only)
.IP \fBinfo\ segment N\fR
Prints information on segment \fBN\fR (i386 only)
.IP \fBinfo\ stack\fR
Prints the values on top of the stack
.IP \fBinfo\ map\fR
Lists all virtual mappings used by the debugged program
.IP \fBinfo\ map\ N\fR
Lists all virtual mappings used by the program of pid \fBN\fR
.IP \fBinfo\ wnd\fR
Lists all the window hierarchy starting from the desktop window
.IP \fBinfo\ wnd\ N\fR
Prints information of Window of handle \fBN\fR
.IP \fBinfo\ process\fR
Lists all w-processes in Wine session
.IP \fBinfo\ thread\fR
Lists all w-threads in Wine session
.IP \fBinfo\ exception\fR
Lists the exception frames (starting from current stack frame)
.PP
It is possible to turn on and off Wine's debug messages as you are
debugging using the \fBset\fR command.
.IP \fBset\ +\ warn\ win\fR
Turns on warn on \fB'win'\fR channel
.IP \fBset\ +\ win\fR
Turns on warn/fixme/err/trace on \fB'win'\fR channel
.IP \fBset\ -\ win\fR
Turns off warn/fixme/err/trace on \fB'win'\fR channel
.IP \fBset\ -\ fixme\fR
Turns off the 'fixme' class on all channels
.PP
.SS Gdb mode:
.PP
See the \fBgdb\fR documentation for all the \fBgdb\fR commands.
.PP
However, a few Wine's extension are available, through the
\fBmonitor\fR command:
.IP \fBmonitor\ wnd\fR
Lists all window in the Wine session
.IP \fBmonitor proc\fR
Lists all processes in the Wine session
.IP \fBmonitor mem \fR
Displays memory mapping of debugged process
.PP
.SS Auto mode:
.PP
Since no user input is possible, no commands are available.
.SH ENVIRONMENT
.IP \fBWINE_GDB\fR
When used in \fBgdb\fR proxy mode, \fBWINE_GDB\fR specifies the name
(and the path) of the executable to be used for \fBgdb\fR. \fB"gdb"\fR
is used by default.
.SH FILES
No specific files are used (yet).
.SH BUGS
A lot.
.SH AUTHORS
The first version was written by Eric Youngdale.
.PP
See Wine developer's list for the rest of contributors.
.SH "SEE ALSO"
.BR winedbg "'s README file"
.nf
The Winelib User Guide
.nf
The Wine Developers Guide