Commit deca2502 authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

- 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
parent 9f33a4b1
...@@ -220,14 +220,22 @@ HANDLE32 WINAPI YourFunc(LPCSTR s) ...@@ -220,14 +220,22 @@ HANDLE32 WINAPI YourFunc(LPCSTR s)
</sect1> </sect1>
<sect1 id="dbg-control"> <sect1 id="dbg-control">
<title>Controlling the debugging output</title> <title>Controlling the debugging output</title>
<para> <para>
It is possible to turn on and off debugging output from It is possible to turn on and off debugging output from
within the debugger using the set command. Please see the within the debugger using the set command. Please see the
WineDbg Command Reference section for how to do this. WineDbg Command Reference section
</para> (<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> <para>
Another way to conditionally log debug output (e.g. in case of Another way to conditionally log debug output (e.g. in case of
......
...@@ -4,26 +4,21 @@ SRCDIR = @srcdir@ ...@@ -4,26 +4,21 @@ SRCDIR = @srcdir@
VPATH = @srcdir@ VPATH = @srcdir@
MODULE = winedbg.exe MODULE = winedbg.exe
APPMODE = -mconsole APPMODE = -mconsole
IMPORTS = advapi32 kernel32 ntdll IMPORTS = dbghelp advapi32 kernel32 ntdll
DELAYIMPORTS = user32 DELAYIMPORTS = user32
C_SRCS = \ C_SRCS = \
be_i386.c \
be_ppc.c \
break.c \ break.c \
db_disasm.c \ db_disasm.c \
display.c \ display.c \
elf.c \
expr.c \ expr.c \
ext_debugger.c \
gdbproxy.c \ gdbproxy.c \
hash.c \
info.c \ info.c \
memory.c \ memory.c \
module.c \
msc.c \
pe.c \
registers.c \
source.c \ source.c \
stabs.c \ symbol.c \
stack.c \ stack.c \
types.c \ types.c \
winedbg.c winedbg.c
...@@ -45,4 +40,11 @@ y.tab.o: y.tab.h ...@@ -45,4 +40,11 @@ y.tab.o: y.tab.h
@LEX_OUTPUT_ROOT@.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: ### Dependencies:
/*
* 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);
/*
* 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
/*
* 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");
}
...@@ -20,52 +20,16 @@ ...@@ -20,52 +20,16 @@
*/ */
/* break handling */ /* break handling */
INTERNAL_VAR(BreakAllThreadsStartup, FALSE, NULL, DT_BASIC_CONST_INT) INTERNAL_VAR(BreakAllThreadsStartup, FALSE, NULL, dbg_itype_unsigned_int)
INTERNAL_VAR(BreakOnCritSectTimeOut, FALSE, NULL, DT_BASIC_CONST_INT) INTERNAL_VAR(BreakOnCritSectTimeOut, FALSE, NULL, dbg_itype_unsigned_int)
INTERNAL_VAR(BreakOnAttach, FALSE, NULL, DT_BASIC_CONST_INT) INTERNAL_VAR(BreakOnAttach, FALSE, NULL, dbg_itype_unsigned_int)
INTERNAL_VAR(BreakOnFirstChance, TRUE, NULL, DT_BASIC_CONST_INT) INTERNAL_VAR(BreakOnFirstChance, TRUE, NULL, dbg_itype_unsigned_int)
INTERNAL_VAR(BreakOnDllLoad, FALSE, NULL, DT_BASIC_CONST_INT) INTERNAL_VAR(BreakOnDllLoad, FALSE, NULL, dbg_itype_unsigned_int)
INTERNAL_VAR(CanDeferOnBPByAddr, FALSE, NULL, DT_BASIC_CONST_INT) INTERNAL_VAR(CanDeferOnBPByAddr, FALSE, NULL, dbg_itype_unsigned_int)
/* debugging debugger */
INTERNAL_VAR(ExtDbgOnInvalidAddress, FALSE, NULL, DT_BASIC_CONST_INT)
INTERNAL_VAR(ExtDbgOnInternalException, FALSE, NULL, DT_BASIC_CONST_INT)
/* current process/thread */ /* current process/thread */
INTERNAL_VAR(ThreadId, FALSE, &DEBUG_CurrTid, DT_BASIC_CONST_INT) INTERNAL_VAR(ThreadId, FALSE, &dbg_curr_tid, dbg_itype_unsigned_int)
INTERNAL_VAR(ProcessId, FALSE, &DEBUG_CurrPid, DT_BASIC_CONST_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) /* symbol manipulation */
#endif INTERNAL_VAR(AlwaysShowThunks, FALSE, NULL, dbg_itype_unsigned_int)
/*
* 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment