From deca2502d63cacff018c211b7314349994d24ad6 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Fri, 4 Jun 2004 00:59:16 +0000 Subject: [PATCH] - 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 --- documentation/debugger.sgml | 1309 ++++++++++---- documentation/debugging.sgml | 22 +- programs/winedbg/Makefile.in | 20 +- programs/winedbg/be_cpu.h | 116 ++ programs/winedbg/be_i386.c | 549 ++++++ programs/winedbg/be_ppc.c | 192 +++ programs/winedbg/break.c | 1326 +++++++------- programs/winedbg/db_disasm.c | 344 ++-- programs/winedbg/dbg.y | 661 +++---- programs/winedbg/debug.l | 229 +-- programs/winedbg/debugger.h | 795 ++++----- programs/winedbg/display.c | 305 ++-- programs/winedbg/elf.c | 610 ------- programs/winedbg/expr.c | 1466 ++++++++-------- programs/winedbg/ext_debugger.c | 161 -- programs/winedbg/gdbproxy.c | 753 +++----- programs/winedbg/hash.c | 1392 --------------- programs/winedbg/info.c | 932 +++++----- programs/winedbg/intvar.h | 56 +- programs/winedbg/memory.c | 816 +++++---- programs/winedbg/module.c | 479 ------ programs/winedbg/msc.c | 2855 ------------------------------- programs/winedbg/pe.c | 513 ------ programs/winedbg/registers.c | 186 -- programs/winedbg/source.c | 400 ++--- programs/winedbg/stabs.c | 1201 ------------- programs/winedbg/stack.c | 524 ++---- programs/winedbg/symbol.c | 560 ++++++ programs/winedbg/types.c | 1669 +++++++----------- programs/winedbg/winedbg.c | 1167 ++++++------- programs/winedbg/winedbg.man | 370 ++++ 31 files changed, 7837 insertions(+), 14141 deletions(-) create mode 100644 programs/winedbg/be_cpu.h create mode 100644 programs/winedbg/be_i386.c create mode 100644 programs/winedbg/be_ppc.c delete mode 100644 programs/winedbg/elf.c delete mode 100644 programs/winedbg/ext_debugger.c delete mode 100644 programs/winedbg/hash.c delete mode 100644 programs/winedbg/module.c delete mode 100644 programs/winedbg/msc.c delete mode 100644 programs/winedbg/pe.c delete mode 100644 programs/winedbg/registers.c delete mode 100644 programs/winedbg/stabs.c create mode 100644 programs/winedbg/symbol.c create mode 100644 programs/winedbg/winedbg.man diff --git a/documentation/debugger.sgml b/documentation/debugger.sgml index 687fbb03114..43d97efef19 100644 --- a/documentation/debugger.sgml +++ b/documentation/debugger.sgml @@ -97,7 +97,7 @@ - the Wine integrated debugger, dubbed WineDbg. + the Wine integrated debugger, dubbed winedbg. @@ -109,9 +109,16 @@ W-process. - WineDbg is a Winelib application making - use of this API to allow debugging both any Wine or Winelib - applications as well as Wine itself (kernel and all DLLs). + Wine also implements DBGHELP.DLL which + allows to look into symbols and types from any module (if + the module has been compiled with the proper options). + + + winedbg is a Winelib application making + use of these APIs (KERNEL32.DLL's + debugging API and DBGHELP.DLL) to allow + debugging both any Wine or Winelib applications as well as + Wine itself (kernel and all DLLs). @@ -126,7 +133,7 @@ Any application (either a Windows' native executable, or a Winelib application) can be run through - WineDbg. Command line options and tricks + winedbg. Command line options and tricks are the same as for wine: @@ -139,11 +146,11 @@ winedbg "hl.exe -windowed" Attaching - WineDbg can also be launched without any - command line argument: WineDbg is started + winedbg can also be launched without any + command line argument: winedbg is started without any attached process. You can get a list of running W-processes (and their - wpid's) using the walk + wpid's) using the info process command, and then, with the attach command, pick up the wpid of the W-process @@ -161,15 +168,16 @@ winedbg "hl.exe -windowed" stack overflow, division by zero, etc. - When an exception occurs, Wine checks if the W-process is - debugged. If so, the exception event is sent to the - debugger, which takes care of it: end of the story. This - mechanism is part of the standard Windows' debugging API. + When an exception occurs, Wine checks if the + W-process is debugged. If so, the + exception event is sent to the debugger, which takes care of + it: end of the story. This mechanism is part of the standard + Windows' debugging API. If the W-process is not debugged, Wine tries to launch a debugger. This debugger (normally - WineDbg, see III Configuration for more + winedbg, see III Configuration for more details), at startup, attaches to the W-process which generated the exception event. In this case, you are able to look at the causes of @@ -178,7 +186,7 @@ winedbg "hl.exe -windowed" wrong. - If WineDbg is the standard debugger, the + If winedbg is the standard debugger, the pass and cont commands are the two ways to let the process go further for the handling of the exception event. @@ -221,7 +229,7 @@ winedbg "hl.exe -windowed" since some of Wine's code uses exceptions and try/catch blocks to provide some - functionality, WineDbg can be entered + functionality, winedbg can be entered in such cases with segv exceptions. This happens, for example, with IsBadReadPtr function. In that case, the pass command shall be @@ -248,10 +256,7 @@ winedbg "hl.exe -windowed" Wine supports the new XP APIs, allowing for a debugger to detach from a program being debugged (see - detach command). Unfortunately, as the - debugger cannot, for now, neither clear its internal - information, nor restart a new process, the debugger, after - detaching itself, cannot do much except being quitted. + detach command). @@ -423,7 +428,7 @@ winedbg "hl.exe -windowed" Start the program with winedbg instead of wine. When the program locks up switch to the - winedbg terminal and press + winedbg's terminal and press CtrlC. this will stop the program and let you debug the program as you would for a crash. @@ -829,7 +834,7 @@ wine -debug myprog.exe starting point. Then you can set breakpoints: - b RoutineName (by outine name) OR + b RoutineName (by routine name) OR b *0x812575 (by address) @@ -971,7 +976,7 @@ wine -debug myprog.exe (%ld) to pass context dependent information to the debugger). You should put here a complete path to your debugger - (WineDbg can of course be used, but + (winedbg can of course be used, but any other Windows' debugging API aware debugger will do). The path to the debugger you chose to use must be reachable @@ -1031,7 +1036,7 @@ wine -debug myprog.exe WineDbg configuration - WineDbg can be configured through a number + winedbg can be configured through a number of options. Those options are stored in the registry, on a per user basis. The key is (in my registry) @@ -1040,7 +1045,7 @@ wine -debug myprog.exe Those options can be read/written while inside - WineDbg, as part of the debugger + winedbg, as part of the debugger expressions. To refer to one of these options, its name must be prefixed by a $ sign. For example, @@ -1053,104 +1058,139 @@ set $BreakAllThreadsStartup = 1 All the options are read from the registry when - WineDbg starts (if no corresponding value + winedbg starts (if no corresponding value is found, a default value is used), and are written back to - the registry when WineDbg exits (hence, + the registry when winedbg exits (hence, all modifications to those options are automatically saved - when WineDbg terminates). + when winedbg terminates). Here's the list of all options: - - Controlling when the debugger is entered + + + BreakAllThreadsStartup + + + Set to TRUE if at all threads + start-up the debugger stops set to + FALSE if only at the first thread + startup of a given process the debugger + stops. FALSE by default. + + + + + BreakOnCritSectTimeOut + + + Set to TRUE if the debugger stops + when a critical section times out (5 minutes); + TRUE by default. + + + + + BreakOnAttach + + + Set to TRUE if when + winedbg attaches to an existing + process after an unhandled exception, + winedbg shall be entered on the + first attach event. Since the attach event is + meaningless in the context of an exception event (the + next event which is the exception event is of course + relevant), that option is likely to be + FALSE. + + + + + BreakOnFirstChance + + + An exception can generate two debug events. The first + one is passed to the debugger (known as a first + chance) just after the exception. The debugger can + then decide either to resume execution (see + winedbg's cont + command) or pass the exception up to the exception + handler chain in the program (if it exists) + (winedbg implements this through + the pass command). If none of the + exception handlers takes care of the exception, the + exception event is sent again to the debugger (known + as last chance exception). You cannot pass on a last + exception. When the + BreakOnFirstChance exception is + TRUE, then winedbg is entered for + both first and last chance execptions (to + FALSE, it's only entered for last + chance exceptions). + + + + + AlwaysShowThunk + + + Set to TRUE if the debugger, when + looking up for a symbol from its name, displays all + the thunks with that name. The default value + (FALSE) allows not to have to + choose between a symbol and all the import thunks + from all the DLLs using that symbols. + + + + + + + + WineDbg Expressions and Variables + + Expressions + + + Expressions in Wine Debugger are mostly written in a C + form. However, there are a few discrepancies: + + + + Identifiers can take a '!' in their names. This allow + mainly to access symbols from different DLLs like + USER32!CreateWindowExA. + + + + + In cast operation, when specifying a structure or an + union, you must use the struct or + union keyword (even if your program uses a typedef). + + + + + + When specifying an identifier by its name, if several + symbols with the same name exist, the debugger will prompt + for the symbol you want to use. Pick up the one you want + from its number. + + + In lots of cases, you can also use regular expressions for + looking for a symbol. + + + winedbg defines its own set of + variables. The configuration variables from above are part + of them. Some others include: - BreakAllThreadsStartup - - - Set to TRUE if at all threads - start-up the debugger stops set to - FALSE if only at the first thread - startup of a given process the debugger stops. - FALSE by default. - - - - - BreakOnCritSectTimeOut - - - Set to TRUE if the debugger stops - when a critical section times out (5 minutes); - TRUE by default. - - - - - BreakOnAttach - - - Set to TRUE if when - WineDbg attaches to an existing - process after an unhandled exception, - WineDbg shall be entered on the - first attach event. Since the attach event is - meaningless in the context of an exception event - (the next event which is the exception event is of - course relevant), that option is likely to be - FALSE. - - - - - BreakOnFirstChance - - - An exception can generate two debug events. The - first one is passed to the debugger (known as a - first chance) just after the exception. The debugger - can then decides either to resume execution (see - WineDbg's cont - command) or pass the exception up to the exception - handler chain in the program (if it exists) - (WineDbg implements this through the - pass command). If none of the - exception handlers takes care of the exception, the - exception event is sent again to the debugger (known - as last chance exception). You cannot pass on a last - exception. When the - BreakOnFirstChance exception is - TRUE, then winedbg is entered for - both first and last chance execptions (to - FALSE, it's only entered for last - chance exceptions). - - - - - BreakOnDllLoad - - - Set to TRUE if the debugger stops - when a DLL is loaded into memory; when the debugger - is invoked after a crash, the DLLs already mapped in - memory will not trigger this break. - FALSE by default. - - - - - - - - Context information - - - - ThreadId + $ThreadId ID of the W-thread currently @@ -1159,7 +1199,7 @@ set $BreakAllThreadsStartup = 1 - ProcessId + $ProcessId ID of the W-thread currently @@ -1171,159 +1211,461 @@ set $BreakAllThreadsStartup = 1 <registers> - All CPU registers are also available + All CPU registers are also available, using $ as a + prefix. You can use info regs to + get a list of avaible CPU registers - - - The ThreadId and - ProcessId variables can be handy to set - conditional breakpoints on a given thread or process. - - + + + The $ThreadId and + $ProcessId variables can be handy to set + conditional breakpoints on a given thread or process. + - WineDbg Command Reference Misc - -abort aborts the debugger -quit exits the debugger - -attach N attach to a W-process (N is its ID, numeric or hexadecimal(0xN)). - IDs can be obtained using the walk process command. Note the - walk process command returns hexadecimal values -detach detach from a W-process. WineDbg will exit (this may - be changed later on) - - -help prints some help on the commands -help info prints some help on info commands - - -mode 16 switch to 16 bit mode -mode 32 switch to 32 bit mode - + + + WineDbg's misc. commands + + + + abort + aborts the debugger + + + quit + exits the debugger + + + attach N + + attach to a W-process (N is its ID, numeric + or hexadecimal (0xN)). IDs can be obtained using + the info process command. Note the info process + command returns hexadecimal values. + + + + detach + detach from a W-process. + + + help + prints some help on the commands + + + help info + prints some help on info commands + + + +
+
Flow control - -cont continue execution until next breakpoint or exception. -pass pass the exception event up to the filter chain. -step continue execution until next C line of code (enters - function call) -next continue execution until next C line of code (doesn't - enter function call) -stepi execute next assembly instruction (enters function - call) -nexti execute next assembly instruction (doesn't enter - function call) -finish do nexti commands until current function is exited - + + + WineDbg's flow control commands + + + + + + + cont + c + + + + continue execution until next breakpoint or + exception. + + + pass + pass the exception event up to the filter + chain. + + + + + + step + s + + + + + continue execution until next 'C' line of code + (enters function call) + + + + + + + next + n + + + + + continue execution until next 'C' line of code + (doesn't enter function call) + + + + + + + stepi + si + + + + + execute next assembly instruction (enters function + call) + + + + + + + nexti + ni + + + + + execute next assembly instruction (doesn't enter + function call) + + + + + + + finish + f + + + + execute until current function is exited + + + +
+
- cont, step, next, stepi, nexti can be postfixed by a - number (N), meaning that the command must be executed N - times. + cont, step, + next, stepi, + nexti can be postfixed by a number (N), + meaning that the command must be executed N times.
Breakpoints, watch points - -enable N enables (break|watch)point #N -disable N disables (break|watch)point #N -delete N deletes (break|watch)point #N -cond N removes any a existing condition to (break|watch)point N -cond N <expr> adds condition <expr> to (break|watch)point N. <expr> - will be evaluated each time the breakpoint is hit. If - the result is a zero value, the breakpoint isn't - triggered -break * N adds a breakpoint at address N -break <id> adds a breakpoint at the address of symbol <id> -break <id> N adds a breakpoint at the address of symbol <id> (N ?) -break N adds a breakpoint at line N of current source file -break adds a breakpoint at current $pc address -watch * N adds a watch command (on write) at address N (on 4 bytes) -watch <id> adds a watch command (on write) at the address of - symbol <id> -info break lists all (break|watch)points (with state) - - When setting a breakpoint on an <id>, if several symbols with this - <id> exist, the debugger will prompt for the symbol you want to use. - Pick up the one you want from its number. + + WineDbg's break & watch points + + + + enable N + enables (break|watch)point #N + + + disable N + disables (break|watch)point #N + + + delete N + deletes (break|watch)point #N + + + cond N + + removes any existing condition to + (break|watch)point N + + + + + cond N <expr> + + + adds condition <expr> to (break|watch)point + N. <expr> will be evaluated each time the + breakpoint is hit. If the result is a zero value, + the breakpoint isn't triggered + + + + break * N + adds a breakpoint at address N + + + break <id> + + adds a breakpoint at the address of symbol + <id> + + + + break <id> N + + adds a breakpoint at the address of symbol + <id> (N ?) + + + + break N + + adds a breakpoint at line N of current source file + + + + break + + adds a breakpoint at current $PC address + + + + watch * N + + adds a watch command (on write) at address N (on 4 + bytes) + + + + watch <id> + + adds a watch command (on write) at the address of + symbol <id> + + + + info break + + lists all (break|watch)points (with state) + + + + +
- - Alternatively you can specify a DLL in the <id> (for example - MYDLL.DLL.myFunc for function myFunc of - G:\AnyPath\MyDll.dll). - You can use the symbol EntryPoint to stand for the entry point of the Dll. - When setting a break/watch-point by <id>, if the symbol cannot be found (for example, the symbol is contained in a not yet loaded module), winedbg will - recall the name of the symbol and will try to set the breakpoint each time a new module is loaded (until it succeeds). + When setting a break/watch-point by <id>, if the + symbol cannot be found (for example, the symbol is contained + in a not yet loaded module), winedbg will recall the name of + the symbol and will try to set the breakpoint each time a + new module is loaded (until it succeeds).
Stack manipulation - -bt print calling stack of current thread -bt N print calling stack of thread of ID N (note: this - doesn't change the position of the current frame as - manipulated by the up & dn commands) -up goes up one frame in current thread's stack -up N goes up N frames in current thread's stack -dn goes down one frame in current thread's stack -dn N goes down N frames in current thread's stack -frame N set N as the current frame for current thread's stack -info local prints information on local variables for current - function - + + + WineDbg's stack manipulation + + + + bt + print calling stack of current thread + + + bt N + + print calling stack of thread of ID N (note: this + doesn't change the position of the current frame + as manipulated by the up and + dn commands) + + + + up + + goes up one frame in current thread's stack + + + + up N + + goes up N frames in current thread's stack + + + + dn + + goes down one frame in current thread's stack + + + + dn N + + goes down N frames in current thread's stack + + + + frame N + + set N as the current frame for current thread's + stack + + + + info local + + prints information on local variables for current + function frame + + + + +
+
Directory & source file manipulation - -show dir -dir <pathname> -dir -symbolfile <pathname> loads external symbol definition -symbolfile <pathname> N loads external symbol definition - (applying an offset of N to addresses) - - -list lists 10 source lines from current position -list - lists 10 source lines before current position -list N lists 10 source lines from line N in current file -list <path>:N lists 10 source lines from line N in file <path> -list <id> lists 10 source lines of function <id> -list * N lists 10 source lines from address N - + + + WineDbg's directory & source file manipulation + + + + show dir + + prints the list of dir:s where source files are + looked for + + + + + dir <pathname> + + + adds <pathname> to the list of dir:s + where to look for source files + + + + dir + + deletes the list of dir:s where to look for source + files + + + + + + symbolfile <pathname> + + + loads external symbol definition + + + + + symbolfile <pathname> N + + + + loads external symbol definition (applying an + offset of N to addresses) + + + + list + + lists 10 source lines forwards from current + position + + + + list - + + lists 10 source lines backwards from current + position + + + + list N + + lists 10 source lines from line N in current file + + + + + list <path>:N + + + lists 10 source lines from line N in file + <path> + + + + list <id> + + lists 10 source lines of function <id> + + + + list * N + lists 10 source lines from address N + + + +
+
+ You can specify the end target (to change the 10 lines value) using the ','. For example: - - -list 123, 234 lists source lines from line 123 up to line 234 in - current file -list foo.c:1,56 lists source lines from line 1 up to 56 in file foo.c - + + WineDbg's list command examples + + + + list 123, 234 + + lists source lines from line 123 up to line 234 in + current file + + + + list foo.c:1, 56 + + lists source lines from line 1 up to 56 in file + foo.c + + + + +
+
@@ -1331,126 +1673,367 @@ list foo.c:1,56 lists source lines from line 1 up to 56 in file foo.c A display is an expression that's evaluated and printed - after the execution of any WineDbg + after the execution of any winedbg command. - -display lists the active displays -info display (same as above command) -display <expr> adds a display for expression <expr> -display /fmt <expr> adds a display for expression <expr>. Printing - evaluated <expr> is done using the given format (see - print command for more on formats) -del display N deletes display #N -undisplay N (same as del display) - + + + WineDbg's displays + + + + + + + display + + info display + + + + + lists the active displays + + + + display <expr> + + + adds a display for expression <expr> + + + + + + display /fmt <expr> + + + + adds a display for expression + <expr>. Printing evaluated <expr> is + done using the given format (see + print command for more on + formats) + + + + + + + + del display N + + + undisplay N + + + + + deletes display #N + + + +
+
Disassembly - -disas disassemble from current position -disas <expr> disassemble from address <expr> -disas <expr>,<expr>disassembles code between addresses specified by - the two <expr> - - - - - Information on Wine's internals - - -info class <id> prints information on Windows's class <id> -walk class lists all Windows' class registered in Wine -info share lists all the dynamic libraries loaded the debugged - program (including .so files, NE and PE DLLs) -info module <N> prints information on module of handle <N> -walk module lists all modules loaded by debugged program -info regs prints the value of CPU register -info segment <N>prints information on segment <N> -info segment lists all allocated segments -info stack prints the values on top of the stack -walk map lists all virtual mappings used by the debugged - program -walk map <N> lists all virtual mappings used by the program of pid <N> -info wnd <N> prints information of Window of handle <N> -walk wnd lists all the window hierarchy starting from the - desktop window -walk wnd <N> lists all the window hierarchy starting from the - window of handle <N> -walk process lists all w-processes in Wine session -walk thread lists all w-threads in Wine session -walk exception lists the exception frames (starting from current - stack frame) - + + + WineDbg's dissassembly + + + + disas + disassemble from current position + + + + disas <expr> + + + disassemble from address <expr> + + + + + + disas <expr>,<expr> + + + + disassembles code between addresses specified by + the two <expr> + + + + +
+
Memory (reading, writing, typing) - -x <expr> examines memory at <expr> address -x /fmt <expr> examines memory at <expr> address using format /fmt -print <expr> prints the value of <expr> (possibly using its type) -print /fmt <expr> prints the value of <expr> (possibly using its - type) -set <lval>=<expr> writes the value of <expr> in <lval> -whatis <expr> prints the C type of expression <expr> - + + + WineDbg's memory management + + + + + x <expr> + + + examines memory at <expr> address + + + + + + x /fmt <expr> + + + + examines memory at <expr> address using + format /fmt + + + + + + print <expr> + + + + prints the value of <expr> (possibly using + its type) + + + + + + print /fmt <expr> + + + prints the value of <expr> (possibly + using its type) + + + + + + set <lval> = <expr> + + + + writes the value of <expr> in <lval> + + + + + + whatis <expr> + + + + prints the C type of expression <expr> + + + + +
+
/fmt is either /<letter> or /<count><letter> letter can be - - -s => an ASCII string -u => an Unicode UTF16 string -i => instructions (disassemble) -x => 32 bit unsigned hexadecimal integer -d => 32 bit signed decimal integer -w => 16 bit unsigned hexadecimal integer -c => character (only printable 0x20-0x7f are actually printed) -b => 8 bit unsigned hexadecimal integer -g => GUID - -
- - - Expressions - - - Expressions in Wine Debugger are mostly written in a C form. However, there - are a few discrepancies: - - - - Identifiers can take a '.' in their names. This allow - mainly to access symbols from different DLLs like - USER32.DLL.CreateWindowA. - - - - - The debugger will try to distinguish this writing with structure operations. - Therefore, you can only use the previous writing in operations manipulating - symbols ({break|watch}points, type information command...). - - - + + san ASCII string + uan Unicode UTF16 string + iinstructions (disassemble) + x32 bit unsigned hexadecimal integer + d32 bit signed decimal integer + w16 bit unsigned hexadecimal integer + ccharacter (only printable 0x20-0x7f are actually printed) + b8 bit unsigned hexadecimal integer + gGUID + + - Debug channels - - It is possible to turn on and off debug messages as you are debugging using - the set command. - - -set + warn win => turn on warn on 'win' channel -set + win => turn on warn/fixme/err/trace on 'win' channel -set - win => turn off warn/fixme/err/trace on 'win' channel -set - fixme => turn off the 'fixme' class - + Information on Wine's internals + + + + WineDbg's Win32 objects management + + + + info class + + lists all Windows' classes registered in Wine + + + + + + info class <id> + + + + prints information on Windows's class <id> + + + + info share; + + lists all the dynamic libraries loaded in the + debugged program (including .so files, NE and PE + DLLs) + + + + + + info share <N>; + + + + prints information on module at address <N> + + + + info regs; + + prints the value of the CPU registers + + + + + info segment <N>; + + + prints information on segment <N> (i386 + only) + + + + + info segment; + + + lists all allocated segments (i386 only) + + + + info stack; + + prints the values on top of the stack + + + + info map; + + lists all virtual mappings used by the debugged + program + + + + + info map <N> + + + lists all virtual mappings used by the program of + pid <N> + + + + + info wnd <N> + + + prints information of Window of handle <N> + + + + info wnd + + lists all the window hierarchy starting from the + desktop window + + + + info process + + lists all w-processes in Wine session + + + + info thread + lists all w-threads in Wine session + + + info exception + + lists the exception frames (starting from current + stack frame) + + + + +
+
+
+ + + Debug channels + + It is possible to turn on and off debug messages as you + are debugging using the set command. + See for more details on debug + channels. + + + + + WineDbg's debug channels' management + + + + + set + warn win + + turn on warn on 'win' channel + + + + set + win + + + turn on warn/fixme/err/trace on 'win' channel + + + + + set - win + + + turn off warn/fixme/err/trace on 'win' channel + + + + + set - fixme + + turn off the 'fixme' class + + + +
+
@@ -1467,7 +2050,7 @@ set - fixme => turn off the 'fixme' class any Win32 application. To enable this mode, just add --gdb to winedbg command line. You'll end up on a GDB prompt. You'll have to use the GDB commands - (not the wine nes). + (not WineDbg's). @@ -1491,13 +2074,30 @@ set - fixme => turn off the 'fixme' class - A few wine extensions available through the monitor command. - -monitor wnd lists all window in the Wine session -monitor proc lists all processes in the Wine session -monitor mem displays memory mapping of debugged process - (doesn't work) - + A few Wine extensions available through the monitor command. + + WineDbg's debug channels' management + + + + monitor wnd + lists all window in the Wine session + + + monitor proc + + lists all processes in the Wine session + + + + monitor mem + + displays memory mapping of debugged process + + + + +
@@ -1505,7 +2105,7 @@ monitor mem displays memory mapping of debugged process Graphical frontends to gdb - This section will describe how you can debug wine using the + This section will describe how you can debug Wine using the GDB mode of winedbg and some graphical front ends to GDB for those of you who really like graphical debuggers. @@ -1515,15 +2115,14 @@ monitor mem displays memory mapping of debugged process Use the following steps, in this order: - + -Start the wine debugger with a command line -like: + Start the Wine debugger with a command line like: - winedbg -- --gdb --no-start <name_of_exe_to_debug.exe> + winedbg --gdb --no-start <name_of_exe_to_debug.exe> - + @@ -1533,23 +2132,25 @@ like: In ddd, use the 'Open File' or 'Open Program' to - point to the wine executable + point to the Wine executable (which is either + wine-pthread or wine-kthread depending on your + settings). -In the output of 1/, there's a line like + In the output of 1/, there's a line like target remote localhost:32878 -copy that line and paste into ddd command pane (the one with the (gdb) -prompt) - + copy that line and paste into ddd command pane (the + one with the (gdb) prompt) + -The program should now be loaded and up and running. If you want, you -can also add in 1/ after the name of the exec all the needed -parameters + The program should now be loaded and up and running. If + you want, you can also add in 1/ after the name of the + exec all the needed parameters @@ -1560,9 +2161,9 @@ parameters - Start the wine debugger with a command line like: + Start the Wine debugger with a command line like: - winedbg -- --gdb --no-start <name_of_exe_to_debug.exe> + winedbg --gdb --no-start <name_of_exe_to_debug.exe> @@ -1572,18 +2173,20 @@ parameters target remote localhost:32878 -Start kdbg with + Start kdbg with kdbg -r localhost:32878 wine -localhost:32878 is not a fixed value, but has been printed in step -1/. 'wine' should also be the full path to the wine executable. - + localhost:32878 is not a fixed value, but has been + printed in step 1/. 'wine' should also be the full + path to the Wine executable (which is either + wine-pthread or wine-kthread depending on your settings). + -The program should now be loaded and up and running. If you want, you -can also add in 1/ after the name of the exec all the needed -parameters + The program should now be loaded and up and running. If + you want, you can also add in 1/ after the name of the + exec all the needed parameters diff --git a/documentation/debugging.sgml b/documentation/debugging.sgml index 829d1e14f62..151af97e291 100644 --- a/documentation/debugging.sgml +++ b/documentation/debugging.sgml @@ -220,14 +220,22 @@ HANDLE32 WINAPI YourFunc(LPCSTR s) - - Controlling the debugging output + + Controlling the debugging output - - 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. - + + 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. + + + You can do the same using the task manager + (taskmgr) 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. + Another way to conditionally log debug output (e.g. in case of diff --git a/programs/winedbg/Makefile.in b/programs/winedbg/Makefile.in index 3631ad97bb0..0494338ecc3 100644 --- a/programs/winedbg/Makefile.in +++ b/programs/winedbg/Makefile.in @@ -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: diff --git a/programs/winedbg/be_cpu.h b/programs/winedbg/be_cpu.h new file mode 100644 index 00000000000..6d6a8f3c081 --- /dev/null +++ b/programs/winedbg/be_cpu.h @@ -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); diff --git a/programs/winedbg/be_i386.c b/programs/winedbg/be_i386.c new file mode 100644 index 00000000000..354d65392c7 --- /dev/null +++ b/programs/winedbg/be_i386.c @@ -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 */ + case 0xe8: /* call */ + case 0x9a: /* lcall : */ + return TRUE; + + case 0xff: /* call */ + 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 diff --git a/programs/winedbg/be_ppc.c b/programs/winedbg/be_ppc.c new file mode 100644 index 00000000000..b62f40d0c4f --- /dev/null +++ b/programs/winedbg/be_ppc.c @@ -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 diff --git a/programs/winedbg/break.c b/programs/winedbg/break.c index 55c1544a7d9..c78258b92ba 100644 --- a/programs/winedbg/break.c +++ b/programs/winedbg/break.c @@ -26,638 +26,497 @@ WINE_DEFAULT_DEBUG_CHANNEL(winedbg); -#ifdef __i386__ -#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)) -#define INT3 0xcc /* int 3 opcode */ -#endif - -#define MAX_BREAKPOINTS 100 - -static DBG_BREAKPOINT breakpoints[MAX_BREAKPOINTS]; - -static int next_bp = 1; /* breakpoint 0 is reserved for step-over */ - /*********************************************************************** - * DEBUG_IsStepOverInstr + * is_at_func_return * - * Determine if the instruction at CS:EIP is an instruction that - * we need to step over (like a call or a repetitive string move). - */ -static BOOL DEBUG_IsStepOverInstr(void) -{ -#ifdef __i386__ - BYTE* instr; - BYTE ch; - DBG_ADDR addr; - - addr.seg = DEBUG_context.SegCs; - addr.off = DEBUG_context.Eip; - /* FIXME: old code was using V86BASE(DEBUG_context) - * instead of passing through DOSMEM_MemoryBase - */ - instr = (BYTE*)DEBUG_ToLinear(&addr); - - for (;;) - { - if (!DEBUG_READ_MEM(instr, &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 */ - instr++; - continue; - - /* Handle call instructions */ - - case 0xcd: /* int */ - case 0xe8: /* call */ - case 0x9a: /* lcall : */ - return TRUE; - - case 0xff: /* call */ - if (!DEBUG_READ_MEM(instr + 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; - } - } -#else - return FALSE; -#endif -} - - -/*********************************************************************** - * DEBUG_IsFctReturn - * - * Determine if the instruction at CS:EIP is an instruction that + * Determine if the instruction at current PC is an instruction that * is a function return. */ -BOOL DEBUG_IsFctReturn(void) +static BOOL is_at_func_return(void) { -#ifdef __i386__ - BYTE* instr; - BYTE ch; - DBG_ADDR addr; + ADDRESS addr; - addr.seg = DEBUG_context.SegCs; - addr.off = DEBUG_context.Eip; - /* FIXME: old code was using V86BASE(DEBUG_context) - * instead of passing through DOSMEM_MemoryBase - */ - instr = (BYTE*)DEBUG_ToLinear(&addr); - - if (!DEBUG_READ_MEM(instr, &ch, sizeof(ch))) - return FALSE; - - return (ch == 0xc2) || (ch == 0xc3); -#else - return FALSE; -#endif + memory_get_current_pc(&addr); + return be_cpu->is_function_return(memory_to_linear_addr(&addr)); } - /*********************************************************************** - * DEBUG_SetBreakpoints + * break_set_xpoints * - * Set or remove all the breakpoints. + * Set or remove all the breakpoints & watchpoints */ -void DEBUG_SetBreakpoints( BOOL set ) +void break_set_xpoints(BOOL set) { - int i; + static BOOL last; /* = 0 = FALSE */ -#ifdef __i386__ - DEBUG_context.Dr7 &= ~DR7_LOCAL_ENABLE_MASK; -#endif + int i; + unsigned ret, size; + void* addr; + struct dbg_breakpoint* bp = dbg_curr_process->bp; - for (i = 0; i < next_bp; i++) - { - if (!(breakpoints[i].refcount && breakpoints[i].enabled)) - continue; + if (set == last) return; + last = set; - switch (breakpoints[i].type) { - case DBG_BREAK: - { -#ifdef __i386__ - char ch = set ? INT3 : breakpoints[i].u.b.opcode; + for (i = 0; i < dbg_curr_process->next_bp; i++) + { + if (!bp[i].refcount && !bp[i].enabled) + continue; - if (!DEBUG_WRITE_MEM( (void*)DEBUG_ToLinear(&breakpoints[i].addr), - &ch, sizeof(ch) )) - { - DEBUG_Printf("Invalid address for breakpoint %d, disabling it\n", i); - breakpoints[i].enabled = FALSE; - } -#endif - } - break; - case DBG_WATCH: - if (set) - { -#ifdef __i386__ - DWORD bits; - int reg = breakpoints[i].u.w.reg; - LPDWORD lpdr = NULL; + if (bp[i].xpoint_type == be_xpoint_break) + size = 0; + else + size = bp[i].w.len + 1; + addr = (void*)memory_to_linear_addr(&bp[i].addr); - switch (reg) - { - case 0: lpdr = &DEBUG_context.Dr0; break; - case 1: lpdr = &DEBUG_context.Dr1; break; - case 2: lpdr = &DEBUG_context.Dr2; break; - case 3: lpdr = &DEBUG_context.Dr3; break; - default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); - } - - *lpdr = DEBUG_ToLinear(&breakpoints[i].addr); - bits = (breakpoints[i].u.w.rw) ? DR7_RW_WRITE : DR7_RW_READ; - switch (breakpoints[i].u.w.len + 1) - { - case 4: bits |= DR7_LEN_4; break; - case 2: bits |= DR7_LEN_2; break; - case 1: bits |= DR7_LEN_1; break; - default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); - } - - DEBUG_context.Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg)); - DEBUG_context.Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg); - DEBUG_context.Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN; -#endif - } - break; - } - } + if (set) + ret = be_cpu->insert_Xpoint(dbg_curr_process->handle, &dbg_context, + bp[i].xpoint_type, addr, + &bp[i].info, size); + else + ret = be_cpu->remove_Xpoint(dbg_curr_process->handle, &dbg_context, + bp[i].xpoint_type, addr, + bp[i].info, size); + if (!ret) + { + dbg_printf("Invalid address (%p) for breakpoint %d, disabling it\n", + addr, i); + bp[i].enabled = FALSE; + } + } } /*********************************************************************** - * DEBUG_FindBreakpoint + * find_xpoint * * Find the breakpoint for a given address. Return the breakpoint * number or -1 if none. - * If type is DBG_BREAKPOINT, addr is a complete addr - * If type is DBG_WATCHPOINT, only addr.off is meaningful and contains - * linear address */ -static int DEBUG_FindBreakpoint( const DBG_ADDR *addr, int type ) +static int find_xpoint(const ADDRESS* addr, enum be_xpoint_type type) { - int i; + int i; + void* lin = memory_to_linear_addr(addr); + struct dbg_breakpoint* bp = dbg_curr_process->bp; - for (i = 0; i < next_bp; i++) - { - if (breakpoints[i].refcount && breakpoints[i].enabled && - breakpoints[i].type == type ) - { - if ((type == DBG_BREAK && - breakpoints[i].addr.seg == addr->seg && - breakpoints[i].addr.off == addr->off) || - (type == DBG_WATCH && - DEBUG_ToLinear(&breakpoints[i].addr) == addr->off)) - return i; - } - } - return -1; + for (i = 0; i < dbg_curr_process->next_bp; i++) + { + if (bp[i].refcount && bp[i].enabled && bp[i].xpoint_type == type && + memory_to_linear_addr(&bp[i].addr) == lin) + return i; + } + return -1; } /*********************************************************************** - * DEBUG_InitXPoint + * init_xpoint * * Find an empty slot in BP table to add a new break/watch point */ -static int DEBUG_InitXPoint(int type, const DBG_ADDR* addr) +static int init_xpoint(int type, const ADDRESS* addr) { - int num; + int num; + struct dbg_breakpoint* bp = dbg_curr_process->bp; - for (num = (next_bp < MAX_BREAKPOINTS) ? next_bp++ : 1; - num < MAX_BREAKPOINTS; num++) - { - if (breakpoints[num].refcount == 0) - { - breakpoints[num].refcount = 1; - breakpoints[num].enabled = TRUE; - breakpoints[num].type = type; - breakpoints[num].skipcount = 0; - breakpoints[num].addr = *addr; - switch (DEBUG_GetSelectorType( addr->seg )) - { - case MODE_32: - breakpoints[num].is32 = 1; - break; - case MODE_VM86: - case MODE_16: - breakpoints[num].is32 = 0; - break; - default: - RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); - } - return num; - } - } + for (num = (dbg_curr_process->next_bp < MAX_BREAKPOINTS) ? + dbg_curr_process->next_bp++ : 1; + num < MAX_BREAKPOINTS; num++) + { + if (bp[num].refcount == 0) + { + bp[num].refcount = 1; + bp[num].enabled = TRUE; + bp[num].xpoint_type = type; + bp[num].skipcount = 0; + bp[num].addr = *addr; + return num; + } + } - DEBUG_Printf("Too many breakpoints. Please delete some.\n"); - return -1; + dbg_printf("Too many bp. Please delete some.\n"); + return -1; } /*********************************************************************** - * DEBUG_GetWatchedValue + * get_watched_value * * Returns the value watched by watch point 'num'. */ -static BOOL DEBUG_GetWatchedValue( int num, LPDWORD val ) +static BOOL get_watched_value(int num, LPDWORD val) { - BYTE buf[4]; + BYTE buf[4]; - if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&breakpoints[num].addr), - buf, breakpoints[num].u.w.len + 1)) - return FALSE; + if (!dbg_read_memory(memory_to_linear_addr(&dbg_curr_process->bp[num].addr), + buf, dbg_curr_process->bp[num].w.len + 1)) + return FALSE; - switch (breakpoints[num].u.w.len + 1) - { - case 4: *val = *(DWORD*)buf; break; - case 2: *val = *(WORD*)buf; break; - case 1: *val = *(BYTE*)buf; break; - default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); - } - return TRUE; + switch (dbg_curr_process->bp[num].w.len + 1) + { + case 4: *val = *(DWORD*)buf; break; + case 2: *val = *(WORD*)buf; break; + case 1: *val = *(BYTE*)buf; break; + default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); + } + return TRUE; } /*********************************************************************** - * DEBUG_AddBreakpoint + * break_add_break * * Add a breakpoint. */ -BOOL DEBUG_AddBreakpoint( const DBG_VALUE *value, BOOL (*func)(void), BOOL verbose ) +BOOL break_add_break(const ADDRESS* addr, BOOL verbose) { - int num; - BYTE ch; + int num; + BYTE ch; + struct dbg_breakpoint* bp = dbg_curr_process->bp; - if ((num = DEBUG_FindBreakpoint(&value->addr, DBG_BREAK)) >= 1) + if ((num = find_xpoint(addr, be_xpoint_break)) >= 1) { - breakpoints[num].refcount++; + bp[num].refcount++; + dbg_printf("Breakpoint %d at ", num); + print_address(&bp[num].addr, TRUE); + dbg_printf(" (refcount=%d)\n", bp[num].refcount); return TRUE; } - if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear( &value->addr ), &ch, sizeof(ch))) + if (!dbg_read_memory(memory_to_linear_addr(addr), &ch, sizeof(ch))) { if (verbose) - DEBUG_Printf("Invalid address, can't set breakpoint\n"); + { + dbg_printf("Invalid address "); + print_bare_address(addr); + dbg_printf(", can't set breakpoint\n"); + } return FALSE; } - if ((num = DEBUG_InitXPoint(DBG_BREAK, &value->addr)) == -1) + if ((num = init_xpoint(be_xpoint_break, addr)) == -1) return FALSE; - breakpoints[num].u.b.opcode = ch; - breakpoints[num].u.b.func = func; - - DEBUG_Printf("Breakpoint %d at ", num); - DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].is32 ? MODE_32 : MODE_16, - TRUE ); - DEBUG_Printf("\n"); + dbg_printf("Breakpoint %d at ", num); + print_address(&bp[num].addr, TRUE); + dbg_printf("\n"); return TRUE; } /*********************************************************************** - * DEBUG_AddBreakpointFromValue + * break_add_break_from_lvalue * * Add a breakpoint. */ -BOOL DEBUG_AddBreakpointFromValue( const DBG_VALUE *_value ) +BOOL break_add_break_from_lvalue(const struct dbg_lvalue* lvalue) { - DBG_VALUE value = *_value; + ADDRESS addr; - if (value.type != NULL && value.type == DEBUG_GetBasicType(DT_BASIC_CONST_INT) && value.cookie == DV_HOST) - { - /* - * 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; - value.cookie = DV_TARGET; - } + addr.Mode = AddrModeFlat; + addr.Offset = types_extract_as_integer(lvalue); - if (!DEBUG_AddBreakpoint( &value, NULL, TRUE )) + if (!break_add_break(&addr, TRUE)) { if (!DBG_IVAR(CanDeferOnBPByAddr)) { - DEBUG_Printf("Invalid address, can't set breakpoint\n" - "You can turn on deferring breakpoints by address by setting $CanDeferOnBPByAddr to 1\n"); + dbg_printf("Invalid address, can't set breakpoint\n" + "You can turn on deferring bp by address by setting $CanDeferOnBPByAddr to 1\n"); return FALSE; } - DEBUG_Printf("Unable to add breakpoint, will check again any time a new DLL is loaded\n"); - DEBUG_CurrProcess->delayed_bp = DBG_realloc(DEBUG_CurrProcess->delayed_bp, - sizeof(DBG_DELAYED_BP) * ++DEBUG_CurrProcess->num_delayed_bp); + dbg_printf("Unable to add breakpoint, will check again any time a new DLL is loaded\n"); + dbg_curr_process->delayed_bp = + dbg_heap_realloc(dbg_curr_process->delayed_bp, + sizeof(struct dbg_delayed_bp) * ++dbg_curr_process->num_delayed_bp); - DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].is_symbol = FALSE; - DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].u.value = value; + dbg_curr_process->delayed_bp[dbg_curr_process->num_delayed_bp - 1].is_symbol = FALSE; + dbg_curr_process->delayed_bp[dbg_curr_process->num_delayed_bp - 1].u.addr = addr; return TRUE; } - - return TRUE; + return FALSE; } /*********************************************************************** - * DEBUG_AddBreakpointFromId + * break_add_break_from_id * * Add a breakpoint from a function name (and eventually a line #) */ -void DEBUG_AddBreakpointFromId(const char *name, int lineno) +void break_add_break_from_id(const char *name, int lineno) { - DBG_VALUE value; - int i; + struct dbg_lvalue lvalue; + int i; - switch (DEBUG_GetSymbolValue(name, lineno, &value, TRUE)) + switch (symbol_get_lvalue(name, lineno, &lvalue, TRUE)) { - case gsv_found: - DEBUG_AddBreakpoint(&value, NULL, TRUE); + case sglv_found: + break_add_break(&lvalue.addr, TRUE); return; - case gsv_unknown: + case sglv_unknown: break; - case gsv_aborted: /* user aborted symbol lookup */ + case sglv_aborted: /* user aborted symbol lookup */ return; } - DEBUG_Printf("Unable to add breakpoint, will check again when a new DLL is loaded\n"); - for (i = 0; i < DEBUG_CurrProcess->num_delayed_bp; i++) + dbg_printf("Unable to add breakpoint, will check again when a new DLL is loaded\n"); + for (i = 0; i < dbg_curr_process->num_delayed_bp; i++) { - if (DEBUG_CurrProcess->delayed_bp[i].is_symbol && - !strcmp(name, DEBUG_CurrProcess->delayed_bp[i].u.symbol.name) && - lineno == DEBUG_CurrProcess->delayed_bp[i].u.symbol.lineno) + if (dbg_curr_process->delayed_bp[i].is_symbol && + !strcmp(name, dbg_curr_process->delayed_bp[i].u.symbol.name) && + lineno == dbg_curr_process->delayed_bp[i].u.symbol.lineno) return; } - DEBUG_CurrProcess->delayed_bp = DBG_realloc(DEBUG_CurrProcess->delayed_bp, - sizeof(DBG_DELAYED_BP) * ++DEBUG_CurrProcess->num_delayed_bp); + dbg_curr_process->delayed_bp = dbg_heap_realloc(dbg_curr_process->delayed_bp, + sizeof(struct dbg_delayed_bp) * ++dbg_curr_process->num_delayed_bp); - DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].is_symbol = TRUE; - DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].u.symbol.name = strcpy(DBG_alloc(strlen(name) + 1), name); - DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].u.symbol.lineno = lineno; + dbg_curr_process->delayed_bp[dbg_curr_process->num_delayed_bp - 1].is_symbol = TRUE; + dbg_curr_process->delayed_bp[dbg_curr_process->num_delayed_bp - 1].u.symbol.name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(name) + 1), name); + dbg_curr_process->delayed_bp[dbg_curr_process->num_delayed_bp - 1].u.symbol.lineno = lineno; } /*********************************************************************** - * DEBUG_AddBreakpointFromLineno + * break_add_break_from_lineno * * Add a breakpoint from a line number in current file */ -void DEBUG_AddBreakpointFromLineno(int lineno) +void break_add_break_from_lineno(int lineno) { - DBG_VALUE value; + ADDRESS addr; - DEBUG_GetCurrentAddress(&value.addr); + memory_get_current_pc(&addr); if (lineno != -1) { - struct name_hash* nh; + IMAGEHLP_LINE il; + IMAGEHLP_LINE iil; + BOOL found = FALSE; - DEBUG_FindNearestSymbol(&value.addr, TRUE, &nh, 0, NULL); - if (nh == NULL) + il.SizeOfStruct = sizeof(il); + if (!SymGetLineFromAddr(dbg_curr_process->handle, + (DWORD)memory_to_linear_addr(&addr), NULL, &il)) { - DEBUG_Printf("Unable to add breakpoint\n"); + dbg_printf("Unable to add breakpoint (unknown address)\n"); return; } - if (!DEBUG_GetLineNumberAddr(nh, lineno, &value.addr, TRUE)) + + iil = il; + while (SymGetLinePrev(dbg_curr_process->handle, &iil)) { - DEBUG_Printf("Unknown line number\n" - "(either out of file, or no code at given line number)\n"); + if (lineno == iil.LineNumber && !strcmp(il.FileName, iil.FileName)) + { + addr.Mode = AddrModeFlat; + addr.Offset = iil.Address; + found = TRUE; + break; + } + } + iil = il; + if (!found) while (SymGetLineNext(dbg_curr_process->handle, &iil)) + { + if (lineno == iil.LineNumber && !strcmp(il.FileName, iil.FileName)) + { + addr.Mode = AddrModeFlat; + addr.Offset = iil.Address; + found = TRUE; + break; + } + } + if (!found) + { + dbg_printf("Unknown line number\n" + "(either out of file, or no code at given line number)\n"); return; } } - value.type = NULL; - value.cookie = DV_TARGET; - DEBUG_AddBreakpoint( &value, NULL, TRUE ); + break_add_break(&addr, TRUE); } /*********************************************************************** - * DEBUG_CheckDelayedBP + * break_check_delayed_bp * * Check is a registered delayed BP is now available. */ -void DEBUG_CheckDelayedBP(void) +void break_check_delayed_bp(void) { - DBG_VALUE value; - int i; - DBG_DELAYED_BP* dbp = DEBUG_CurrProcess->delayed_bp; + struct dbg_lvalue lvalue; + int i; + struct dbg_delayed_bp* dbp = dbg_curr_process->delayed_bp; - for (i = 0; i < DEBUG_CurrProcess->num_delayed_bp; i++) + for (i = 0; i < dbg_curr_process->num_delayed_bp; i++) { if (dbp[i].is_symbol) { - if (DEBUG_GetSymbolValue(dbp[i].u.symbol.name, dbp[i].u.symbol.lineno, &value, TRUE) != gsv_found) + if (symbol_get_lvalue(dbp[i].u.symbol.name, dbp[i].u.symbol.lineno, + &lvalue, TRUE) != sglv_found) continue; + if (lvalue.cookie != DLV_TARGET) continue; } else - value = dbp[i].u.value; + lvalue.addr = dbp[i].u.addr; WINE_TRACE("trying to add delayed %s-bp\n", dbp[i].is_symbol ? "S" : "A"); if (!dbp[i].is_symbol) - WINE_TRACE("\t%04x %04lx:%08lx\n", - dbp[i].u.value.cookie, - dbp[i].u.value.addr.seg, - dbp[i].u.value.addr.off); + WINE_TRACE("\t%04x:%08lx\n", + dbp[i].u.addr.Segment, dbp[i].u.addr.Offset); else - WINE_TRACE("\t'%s' @ %d\n", + WINE_TRACE("\t'%s' @ %d\n", dbp[i].u.symbol.name, dbp[i].u.symbol.lineno); - if (DEBUG_AddBreakpoint(&value, NULL, FALSE)) - memmove(&dbp[i], &dbp[i+1], (--DEBUG_CurrProcess->num_delayed_bp - i) * sizeof(*dbp)); + if (break_add_break(&lvalue.addr, FALSE)) + memmove(&dbp[i], &dbp[i+1], (--dbg_curr_process->num_delayed_bp - i) * sizeof(*dbp)); } } /*********************************************************************** - * DEBUG_AddWatchpoint + * break_add_watch * * Add a watchpoint. */ -void DEBUG_AddWatchpoint( const DBG_VALUE *_value, BOOL is_write ) +void break_add_watch(const struct dbg_lvalue* lvalue, BOOL is_write) { - DBG_VALUE value = *_value; - int num, reg = -1; - unsigned seg2; - DWORD mask = 0; + int num; + DWORD l = 4; - assert(_value->cookie == DV_TARGET || _value->cookie == DV_HOST); + num = init_xpoint((is_write) ? be_xpoint_watch_write : be_xpoint_watch_read, + &lvalue->addr); + if (num == -1) return; -#ifdef __i386__ - DEBUG_FixAddress( &value.addr, DEBUG_context.SegCs ); -#endif + if (lvalue->typeid != dbg_itype_none) + { + if (types_get_info((DWORD)memory_to_linear_addr(&lvalue->addr), + lvalue->typeid, TI_GET_LENGTH, &l)) + { + switch (l) + { + case 4: case 2: case 1: break; + default: + dbg_printf("Unsupported length (%lu) for watch-points, defaulting to 4\n", l); + break; + } + } + else dbg_printf("Cannot get watch size, defaulting to 4\n"); + } + dbg_curr_process->bp[num].w.len = l - 1; - if ( value.type != NULL && 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. - */ - seg2 = value.addr.seg; - value.addr.seg = 0; - value.addr.off = DEBUG_GetExprValue(&value, NULL); - value.addr.seg = seg2; - } - - for (num = 1; num < next_bp; num++) - { - if (breakpoints[num].refcount && breakpoints[num].enabled && - breakpoints[num].type == DBG_WATCH) { - mask |= (1 << breakpoints[num].u.w.reg); - } - } -#ifdef __i386__ - for (reg = 0; reg < 4 && (mask & (1 << reg)); reg++); - if (reg == 4) - { - DEBUG_Printf("All i386 hardware watchpoints have been set. Delete some\n"); - return; - } -#endif - - if ((num = DEBUG_InitXPoint(DBG_WATCH, &value.addr)) == -1) - return; - - breakpoints[num].u.w.len = 4 - 1; - if (_value->type && DEBUG_GetObjectSize(_value->type) < 4) - breakpoints[num].u.w.len = 2 - 1; - - if (!DEBUG_GetWatchedValue( num, &breakpoints[num].u.w.oldval)) - { - DEBUG_Printf("Bad address. Watchpoint not set\n"); - breakpoints[num].refcount = 0; - } - else - { - breakpoints[num].u.w.rw = (is_write) ? TRUE : FALSE; - breakpoints[reg].u.w.reg = reg; - - DEBUG_Printf("Watchpoint %d at ", num); - DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].is32 ? MODE_32 : MODE_16, TRUE ); - DEBUG_Printf("\n"); - } + if (!get_watched_value(num, &dbg_curr_process->bp[num].w.oldval)) + { + dbg_printf("Bad address. Watchpoint not set\n"); + dbg_curr_process->bp[num].refcount = 0; + return; + } + dbg_printf("Watchpoint %d at ", num); + print_address(&dbg_curr_process->bp[num].addr, TRUE); + dbg_printf("\n"); } /*********************************************************************** - * DEBUG_AddWathpointFromId + * break_add_watch_from_id * * Add a watchpoint from a symbol name (and eventually a line #) */ -void DEBUG_AddWatchpointFromId(const char *name) +void break_add_watch_from_id(const char *name) { - DBG_VALUE value; + struct dbg_lvalue lvalue; - switch (DEBUG_GetSymbolValue(name, -1, &value, TRUE)) - { - case gsv_found: - DEBUG_AddWatchpoint( &value, 1 ); - break; - case gsv_unknown: - DEBUG_Printf("Unable to add watchpoint\n"); - break; - case gsv_aborted: /* user aborted symbol lookup */ - break; - } + switch (symbol_get_lvalue(name, -1, &lvalue, TRUE)) + { + case sglv_found: + break_add_watch(&lvalue, 1); + break; + case sglv_unknown: + dbg_printf("Unable to add watchpoint\n"); + break; + case sglv_aborted: /* user aborted symbol lookup */ + break; + } } /*********************************************************************** - * DEBUG_DelBreakpoint + * break_delete_xpoint * * Delete a breakpoint. */ -void DEBUG_DelBreakpoint( int num ) +void break_delete_xpoint(int num) { - if ((num <= 0) || (num >= next_bp) || breakpoints[num].refcount == 0) + struct dbg_breakpoint* bp = dbg_curr_process->bp; + + if ((num <= 0) || (num >= dbg_curr_process->next_bp) || + bp[num].refcount == 0) { - DEBUG_Printf("Invalid breakpoint number %d\n", num); + dbg_printf("Invalid breakpoint number %d\n", num); return; } - if (--breakpoints[num].refcount > 0) - return; + if (--bp[num].refcount > 0) + return; - if (breakpoints[num].condition != NULL) + if (bp[num].condition != NULL) { - DEBUG_FreeExpr(breakpoints[num].condition); - breakpoints[num].condition = NULL; + expr_free(bp[num].condition); + bp[num].condition = NULL; } - breakpoints[num].enabled = FALSE; - breakpoints[num].refcount = 0; - breakpoints[num].skipcount = 0; + bp[num].enabled = FALSE; + bp[num].refcount = 0; + bp[num].skipcount = 0; +} + +static inline BOOL module_is_container(const IMAGEHLP_MODULE* wmod_cntnr, + const IMAGEHLP_MODULE* wmod_child) +{ + return wmod_cntnr->BaseOfImage <= wmod_child->BaseOfImage && + (DWORD)wmod_cntnr->BaseOfImage + wmod_cntnr->ImageSize >= + (DWORD)wmod_child->BaseOfImage + wmod_child->ImageSize; +} + +/****************************************************************** + * break_delete_xpoints_from_module + * + * Remove all Xpoints from module which base is 'base' + */ +void break_delete_xpoints_from_module(unsigned long base) +{ + IMAGEHLP_MODULE im, im_elf; + int i; + DWORD linear; + struct dbg_breakpoint* bp = dbg_curr_process->bp; + + /* FIXME: should do it also on the ELF sibbling if any */ + im.SizeOfStruct = sizeof(im); + im_elf.SizeOfStruct = sizeof(im_elf); + if (!SymGetModuleInfo(dbg_curr_process->handle, base, &im)) return; + + /* try to get in fact the underlying ELF module (if any) */ + if (SymGetModuleInfo(dbg_curr_process->handle, im.BaseOfImage - 1, &im_elf) && + im_elf.BaseOfImage <= im.BaseOfImage && + (DWORD)im_elf.BaseOfImage + im_elf.ImageSize >= (DWORD)im.BaseOfImage + im.ImageSize) + im = im_elf; + + for (i = 0; i < dbg_curr_process->next_bp; i++) + { + linear = (DWORD)memory_to_linear_addr(&bp[i].addr); + if (bp[i].refcount && bp[i].enabled && + im.BaseOfImage <= linear && linear < im.BaseOfImage + im.ImageSize) + { + break_delete_xpoint(i); + } + } } /*********************************************************************** - * DEBUG_EnableBreakpoint + * break_enable_xpoint * * Enable or disable a break point. */ -void DEBUG_EnableBreakpoint( int num, BOOL enable ) +void break_enable_xpoint(int num, BOOL enable) { - if ((num <= 0) || (num >= next_bp) || breakpoints[num].refcount == 0) + if ((num <= 0) || (num >= dbg_curr_process->next_bp) || + dbg_curr_process->bp[num].refcount == 0) { - DEBUG_Printf("Invalid breakpoint number %d\n", num); + dbg_printf("Invalid breakpoint number %d\n", num); return; } - breakpoints[num].enabled = (enable) ? TRUE : FALSE; - breakpoints[num].skipcount = 0; + dbg_curr_process->bp[num].enabled = (enable) ? TRUE : FALSE; + dbg_curr_process->bp[num].skipcount = 0; } /*********************************************************************** - * DEBUG_FindTriggeredWatchpoint + * find_triggered_watch * * Lookup the watchpoints to see if one has been triggered * Return >= (watch point index) if one is found and *oldval is set to @@ -669,211 +528,223 @@ void DEBUG_EnableBreakpoint( int num, BOOL enable ) * cause of the TRAP. * -EP */ -static int DEBUG_FindTriggeredWatchpoint(LPDWORD oldval) +static int find_triggered_watch(LPDWORD oldval) { - int found = -1; -#ifdef __i386__ - int i; + int found = -1; + int i; + struct dbg_breakpoint* bp = dbg_curr_process->bp; - /* Method 1 => get triggered watchpoint from context (doesn't work on Linux - * 2.2.x). This should be fixed in >= 2.2.16 - */ - for (i = 0; i < next_bp; i++) - { - DWORD val = 0; + /* Method 1 => get triggered watchpoint from context (doesn't work on Linux + * 2.2.x). This should be fixed in >= 2.2.16 + */ + for (i = 0; i < dbg_curr_process->next_bp; i++) + { + DWORD val = 0; - if (breakpoints[i].refcount && breakpoints[i].enabled && - breakpoints[i].type == DBG_WATCH && - (DEBUG_context.Dr6 & (1 << breakpoints[i].u.w.reg))) - { - DEBUG_context.Dr6 &= ~(1 << breakpoints[i].u.w.reg); + if (bp[i].refcount && bp[i].enabled && bp[i].xpoint_type != be_xpoint_break && + (be_cpu->is_watchpoint_set(&dbg_context, bp[i].info))) + { + be_cpu->clear_watchpoint(&dbg_context, bp[i].info); - *oldval = breakpoints[i].u.w.oldval; - if (DEBUG_GetWatchedValue(i, &val)) { - breakpoints[i].u.w.oldval = val; - return i; - } - } - } + *oldval = bp[i].w.oldval; + if (get_watched_value(i, &val)) + { + bp[i].w.oldval = val; + return i; + } + } + } - /* Method 1 failed, trying method 2 */ + /* Method 1 failed, trying method 2 */ - /* Method 2 => check if value has changed among registered watchpoints - * this really sucks, but this is how gdb 4.18 works on my linux box - * -EP - */ - for (i = 0; i < next_bp; i++) - { - DWORD val = 0; + /* Method 2 => check if value has changed among registered watchpoints + * this really sucks, but this is how gdb 4.18 works on my linux box + * -EP + */ + for (i = 0; i < dbg_curr_process->next_bp; i++) + { + DWORD val = 0; - if (breakpoints[i].refcount && breakpoints[i].enabled && - breakpoints[i].type == DBG_WATCH && - DEBUG_GetWatchedValue(i, &val)) - { - *oldval = breakpoints[i].u.w.oldval; - if (val != *oldval) - { - DEBUG_context.Dr6 &= ~(1 << breakpoints[i].u.w.reg); - breakpoints[i].u.w.oldval = val; - found = i; - /* cannot break, because two watch points may have been triggered on - * the same access - * only one will be reported to the user (FIXME ?) - */ - } - } - } -#endif - return found; + if (bp[i].refcount && bp[i].enabled && bp[i].xpoint_type != be_xpoint_break && + get_watched_value(i, &val)) + { + *oldval = bp[i].w.oldval; + if (val != *oldval) + { + be_cpu->clear_watchpoint(&dbg_context, bp[i].info); + bp[i].w.oldval = val; + found = i; + /* cannot break, because two watch points may have been triggered on + * the same access + * only one will be reported to the user (FIXME ?) + */ + } + } + } + return found; } /*********************************************************************** - * DEBUG_InfoBreakpoints + * break_info * - * Display break points information. + * Display break & watch points information. */ -void DEBUG_InfoBreakpoints(void) +void break_info(void) { - int i; + int i; + int nbp = 0, nwp = 0; + struct dbg_delayed_bp* dbp = dbg_curr_process->delayed_bp; + struct dbg_breakpoint* bp = dbg_curr_process->bp; - DEBUG_Printf("Breakpoints:\n"); - for (i = 1; i < next_bp; i++) + for (i = 1; i < dbg_curr_process->next_bp; i++) { - if (breakpoints[i].refcount && breakpoints[i].type == DBG_BREAK) + if (bp[i].refcount) { - DEBUG_Printf("%d: %c ", i, breakpoints[i].enabled ? 'y' : 'n'); - DEBUG_PrintAddress( &breakpoints[i].addr, - breakpoints[i].is32 ? MODE_32 : MODE_16, TRUE); - DEBUG_Printf(" (%u)\n", breakpoints[i].refcount ); - if( breakpoints[i].condition != NULL ) + if (bp[i].xpoint_type == be_xpoint_break) nbp++; else nwp++; + } + } + + if (nbp) + { + dbg_printf("Breakpoints:\n"); + for (i = 1; i < dbg_curr_process->next_bp; i++) + { + if (!bp[i].refcount || bp[i].xpoint_type != be_xpoint_break) + continue; + dbg_printf("%d: %c ", i, bp[i].enabled ? 'y' : 'n'); + print_address(&bp[i].addr, TRUE); + dbg_printf(" (%u)\n", bp[i].refcount); + if (bp[i].condition != NULL) { - DEBUG_Printf("\t\tstop when "); - DEBUG_DisplayExpr(breakpoints[i].condition); - DEBUG_Printf("\n"); + dbg_printf("\t\tstop when "); + expr_print(bp[i].condition); + dbg_printf("\n"); } } } - DEBUG_Printf("Watchpoints:\n"); - for (i = 1; i < next_bp; i++) + else dbg_printf("No breakpoints\n"); + if (nwp) { - if (breakpoints[i].refcount && breakpoints[i].type == DBG_WATCH) + dbg_printf("Watchpoints:\n"); + for (i = 1; i < dbg_curr_process->next_bp; i++) { - DEBUG_Printf("%d: %c ", i, breakpoints[i].enabled ? 'y' : 'n'); - DEBUG_PrintAddress( &breakpoints[i].addr, - breakpoints[i].is32 ? MODE_32 : MODE_16, TRUE); - DEBUG_Printf(" on %d byte%s (%c)\n", - breakpoints[i].u.w.len + 1, - breakpoints[i].u.w.len > 0 ? "s" : "", - breakpoints[i].u.w.rw ? 'W' : 'R'); - if( breakpoints[i].condition != NULL ) + if (!bp[i].refcount || bp[i].xpoint_type == be_xpoint_break) + continue; + dbg_printf("%d: %c ", i, bp[i].enabled ? 'y' : 'n'); + print_address(&bp[i].addr, TRUE); + dbg_printf(" on %d byte%s (%c)\n", + bp[i].w.len + 1, bp[i].w.len > 0 ? "s" : "", + bp[i].xpoint_type == be_xpoint_watch_write ? 'W' : 'R'); + if (bp[i].condition != NULL) { - DEBUG_Printf("\t\tstop when "); - DEBUG_DisplayExpr(breakpoints[i].condition); - DEBUG_Printf("\n"); + dbg_printf("\t\tstop when "); + expr_print(bp[i].condition); + dbg_printf("\n"); } } } + else dbg_printf("No watchpoints\n"); + if (dbg_curr_process->num_delayed_bp) + { + dbg_printf("Delayed breakpoints:\n"); + for (i = 0; i < dbg_curr_process->num_delayed_bp; i++) + { + if (dbp[i].is_symbol) + { + dbg_printf("%d: %s", i, dbp[i].u.symbol.name); + if (dbp[i].u.symbol.lineno != -1) + dbg_printf(" at line %u", dbp[i].u.symbol.lineno); + } + else + { + dbg_printf("%d: ", i); + print_address(&dbp[i].u.addr, FALSE); + } + dbg_printf("\n"); + } + } } /*********************************************************************** - * DEBUG_ShallBreak + * should_stop * * Check whether or not the condition (bp / skipcount) of a break/watch * point are met. */ -static BOOL DEBUG_ShallBreak( int bpnum ) +static BOOL should_stop(int bpnum) { - if ( breakpoints[bpnum].condition != NULL ) - { - DBG_VALUE value = DEBUG_EvalExpr(breakpoints[bpnum].condition); + struct dbg_breakpoint* bp = &dbg_curr_process->bp[bpnum]; - if ( value.type == NULL ) + if (bp->condition != NULL) + { + struct dbg_lvalue lvalue = expr_eval(bp->condition); + + if (lvalue.typeid == dbg_itype_none) { /* * Something wrong - unable to evaluate this expression. */ - DEBUG_Printf("Unable to evaluate expression "); - DEBUG_DisplayExpr(breakpoints[bpnum].condition); - DEBUG_Printf("\nTurning off condition\n"); - DEBUG_AddBPCondition(bpnum, NULL); + dbg_printf("Unable to evaluate expression "); + expr_print(bp->condition); + dbg_printf("\nTurning off condition\n"); + break_add_condition(bpnum, NULL); } - else if( !DEBUG_GetExprValue( &value, NULL) ) + else if (!types_extract_as_integer(&lvalue)) { return FALSE; } } - if ( breakpoints[bpnum].skipcount > 0 && --breakpoints[bpnum].skipcount > 0 ) - return FALSE; - - if ((breakpoints[bpnum].type == DBG_BREAK) && breakpoints[bpnum].u.b.func) - return breakpoints[bpnum].u.b.func(); - return TRUE; + if (bp->skipcount > 0) bp->skipcount--; + return bp->skipcount == 0; } /*********************************************************************** - * DEBUG_ShouldContinue + * break_should_continue * * Determine if we should continue execution after a SIGTRAP signal when * executing in the given mode. */ -BOOL DEBUG_ShouldContinue( DBG_ADDR *addr, DWORD code, int * count ) +BOOL break_should_continue(ADDRESS* addr, DWORD code, int* count) { int bpnum; DWORD oldval; int wpnum; - enum dbg_mode addr_mode; - struct symbol_info syminfo; - enum exec_mode mode = DEBUG_CurrThread->exec_mode; + enum dbg_exec_mode mode = dbg_curr_thread->exec_mode; -#ifdef __i386__ - /* If not single-stepping, back up over the int3 instruction */ + /* If not single-stepping, back up to the break instruction */ if (code == EXCEPTION_BREAKPOINT) + addr->Offset += be_cpu->adjust_pc_for_break(&dbg_context, TRUE); + + bpnum = find_xpoint(addr, be_xpoint_break); + dbg_curr_process->bp[0].enabled = FALSE; /* disable the step-over breakpoint */ + + if (bpnum > 0) { - DEBUG_context.Eip--; - addr->off--; - } -#endif + if (!should_stop(bpnum)) return TRUE; - bpnum = DEBUG_FindBreakpoint( addr, DBG_BREAK ); - breakpoints[0].enabled = FALSE; /* disable the step-over breakpoint */ - - if ((bpnum != 0) && (bpnum != -1)) - { - if (!DEBUG_ShallBreak(bpnum)) return TRUE; - - DEBUG_Printf("Stopped on breakpoint %d at ", bpnum); - syminfo = DEBUG_PrintAddress( &breakpoints[bpnum].addr, - breakpoints[bpnum].is32 ? MODE_32 : MODE_16, TRUE ); - DEBUG_Printf("\n"); - - if( syminfo.list.sourcefile != NULL ) - DEBUG_List(&syminfo.list, NULL, 0); + dbg_printf("Stopped on breakpoint %d at ", bpnum); + print_address(&dbg_curr_process->bp[bpnum].addr, TRUE); + dbg_printf("\n"); + source_list_from_addr(addr, 0); return FALSE; } - wpnum = DEBUG_FindTriggeredWatchpoint(&oldval); - if ((wpnum != 0) && (wpnum != -1)) + wpnum = find_triggered_watch(&oldval); + if (wpnum > 0) { - /* If not single-stepping, do not back up over the int3 instruction */ - if (code == EXCEPTION_BREAKPOINT) - { -#ifdef __i386__ - DEBUG_context.Eip++; - addr->off++; -#endif - } - if (!DEBUG_ShallBreak(wpnum)) return TRUE; + /* If not single-stepping, do not back up over the break instruction */ + if (code == EXCEPTION_BREAKPOINT) + addr->Offset += be_cpu->adjust_pc_for_break(&dbg_context, FALSE); - addr_mode = DEBUG_GetSelectorType( addr->seg ); - DEBUG_Printf("Stopped on watchpoint %d at ", wpnum); - syminfo = DEBUG_PrintAddress( addr, addr_mode, TRUE ); + if (!should_stop(wpnum)) return TRUE; - DEBUG_Printf(" values: old=%lu new=%lu\n", - oldval, breakpoints[wpnum].u.w.oldval); - if (syminfo.list.sourcefile != NULL) - DEBUG_List(&syminfo.list, NULL, 0); - return FALSE; + dbg_printf("Stopped on watchpoint %d at ", wpnum); + print_address(addr, TRUE); + dbg_printf(" values: old=%lu new=%lu\n", + oldval, dbg_curr_process->bp[wpnum].w.oldval); + source_list_from_addr(addr, 0); + return FALSE; } /* @@ -881,19 +752,19 @@ BOOL DEBUG_ShouldContinue( DBG_ADDR *addr, DWORD code, int * count ) * get the current function, and figure out if we are exactly * on a line number or not. */ - if( mode == EXEC_STEP_OVER || mode == EXEC_STEP_INSTR ) + if (mode == dbg_exec_step_over_line || mode == dbg_exec_step_into_line) { - if( DEBUG_CheckLinenoStatus(addr) == AT_LINENUMBER ) + if (symbol_get_function_line_status(addr) == dbg_on_a_line_number) { (*count)--; } } - else if( mode == EXEC_STEPI_OVER || mode == EXEC_STEPI_INSTR ) + else if (mode == dbg_exec_step_over_insn || mode == dbg_exec_step_into_insn) { (*count)--; } - if( *count > 0 || mode == EXEC_FINISH ) + if (*count > 0 || mode == dbg_exec_finish) { /* * We still need to execute more instructions. @@ -905,228 +776,189 @@ BOOL DEBUG_ShouldContinue( DBG_ADDR *addr, DWORD code, int * count ) * If we are about to stop, then print out the source line if we * have it. */ - if (mode != EXEC_CONT && mode != EXEC_FINISH) - { - DEBUG_FindNearestSymbol(addr, TRUE, NULL, 0, &syminfo.list); - if (syminfo.list.sourcefile != NULL) - { - DEBUG_List(&syminfo.list, NULL, 0); - } - } + if (mode != dbg_exec_cont && mode != dbg_exec_finish) + source_list_from_addr(addr, 0); -#ifdef __i386__ /* If there's no breakpoint and we are not single-stepping, then - * either we must have encountered an int3 in the Windows program + * either we must have encountered a break insn in the Windows program * or someone is trying to stop us - * If the later, (no int3 opcode at current address) then stop, - * otherwise, let's skip it. */ - if ((bpnum == -1) && code == EXCEPTION_BREAKPOINT) + if (bpnum == -1 && code == EXCEPTION_BREAKPOINT) { - unsigned char c; - - if (!DEBUG_READ_MEM(&addr, &c, 1)) c = 0xCC; - DEBUG_context.Eip++; - addr->off++; - if (c != 0xCC) return FALSE; + addr->Offset += be_cpu->adjust_pc_for_break(&dbg_context, FALSE); + return FALSE; } -#endif /* no breakpoint, continue if in continuous mode */ - return (mode == EXEC_CONT || mode == EXEC_FINISH); + return mode == dbg_exec_cont || mode == dbg_exec_finish; } /*********************************************************************** - * DEBUG_SuspendExecution + * break_suspend_execution * - * Remove all breakpoints before entering the debug loop + * Remove all bp before entering the debug loop */ -void DEBUG_SuspendExecution( void ) +void break_suspend_execution(void) { - DEBUG_SetBreakpoints( FALSE ); - breakpoints[0] = DEBUG_CurrThread->stepOverBP; + break_set_xpoints(FALSE); + dbg_curr_process->bp[0] = dbg_curr_thread->step_over_bp; } /*********************************************************************** - * DEBUG_RestartExecution + * break_restart_execution * - * Set the breakpoints to the correct state to restart execution + * Set the bp to the correct state to restart execution * in the given mode. */ -void DEBUG_RestartExecution( int count ) +void break_restart_execution(int count) { - DBG_ADDR addr; - DBG_ADDR addr2; - int bp; - int delta; - int status; - enum exec_mode mode, ret_mode; - DWORD instr; - unsigned char ch; + ADDRESS addr; + int bp; + enum dbg_line_status status; + enum dbg_exec_mode mode, ret_mode; + ADDRESS callee; - DEBUG_GetCurrentAddress( &addr ); + memory_get_current_pc(&addr); /* * This is the mode we will be running in after we finish. We would like * to be able to modify this in certain cases. */ - ret_mode = mode = DEBUG_CurrThread->exec_mode; + ret_mode = mode = dbg_curr_thread->exec_mode; - bp = DEBUG_FindBreakpoint( &addr, DBG_BREAK ); - if ( bp != -1 && bp != 0) - { + bp = find_xpoint(&addr, be_xpoint_break); + if (bp != -1 && bp != 0) + { /* * If we have set a new value, then save it in the BP number. */ - if( count != 0 && mode == EXEC_CONT ) - { - breakpoints[bp].skipcount = count; - } - mode = EXEC_STEPI_INSTR; /* If there's a breakpoint, skip it */ - } - else - { - if( mode == EXEC_CONT && count > 1 ) - { - DEBUG_Printf("Not stopped at any breakpoint; argument ignored.\n"); - } - } + if (count != 0 && mode == dbg_exec_cont) + { + dbg_curr_process->bp[bp].skipcount = count; + } + mode = dbg_exec_step_into_insn; /* If there's a breakpoint, skip it */ + } + else if (mode == dbg_exec_cont && count > 1) + { + dbg_printf("Not stopped at any breakpoint; argument ignored.\n"); + } - if( mode == EXEC_FINISH && DEBUG_IsFctReturn() ) - { - mode = ret_mode = EXEC_STEPI_INSTR; - } + if (mode == dbg_exec_finish && is_at_func_return()) + { + mode = ret_mode = dbg_exec_step_into_insn; + } - instr = DEBUG_ToLinear( &addr ); - DEBUG_READ_MEM((void*)instr, &ch, sizeof(ch)); /* * See if the function we are stepping into has debug info * and line numbers. If not, then we step over it instead. * FIXME - we need to check for things like thunks or trampolines, * as the actual function may in fact have debug info. */ - if ( ch == 0xe8 ) - { - DEBUG_READ_MEM((void*)(instr + 1), &delta, sizeof(delta)); - addr2 = addr; - DEBUG_Disasm(&addr2, FALSE); - addr2.off += delta; - - status = DEBUG_CheckLinenoStatus(&addr2); + if (be_cpu->is_function_call(memory_to_linear_addr(&addr), &callee)) + { + status = symbol_get_function_line_status(&callee); +#if 0 + /* FIXME: we need to get the thunk type */ /* * Anytime we have a trampoline, step over it. */ - if( ((mode == EXEC_STEP_OVER) || (mode == EXEC_STEPI_OVER)) - && status == FUNC_IS_TRAMPOLINE ) - { - WINE_TRACE("Not stepping into trampoline at %lx (no lines)\n", - addr2.off); + if ((mode == EXEC_STEP_OVER || mode == EXEC_STEPI_OVER) + && status == dbg_in_a_thunk) + { + WINE_WARN("Not stepping into trampoline at %p (no lines)\n", + memory_to_linear_addr(&callee)); mode = EXEC_STEP_OVER_TRAMPOLINE; - } - - if( mode == EXEC_STEP_INSTR && status == FUNC_HAS_NO_LINES ) - { - WINE_TRACE("Not stepping into function at %lx (no lines)\n", - addr2.off); - mode = EXEC_STEP_OVER; - } - } - - - if( mode == EXEC_STEP_INSTR ) - { - if( DEBUG_CheckLinenoStatus(&addr) == FUNC_HAS_NO_LINES ) - { - DEBUG_Printf("Single stepping until exit from function, \n" - "which has no line number information.\n"); - - ret_mode = mode = EXEC_FINISH; - } - } - - switch(mode) - { - case EXEC_CONT: /* Continuous execution */ -#ifdef __i386__ - DEBUG_context.EFlags &= ~STEP_FLAG; + } #endif - DEBUG_SetBreakpoints( TRUE ); + if (mode == dbg_exec_step_into_line && status == dbg_no_line_info) + { + WINE_WARN("Not stepping into function at %p (no lines)\n", + memory_to_linear_addr(&callee)); + mode = dbg_exec_step_over_line; + } + } + + if (mode == dbg_exec_step_into_line && + symbol_get_function_line_status(&addr) == dbg_no_line_info) + { + dbg_printf("Single stepping until exit from function, \n" + "which has no line number information.\n"); + ret_mode = mode = dbg_exec_finish; + } + + switch (mode) + { + case dbg_exec_cont: /* Continuous execution */ + be_cpu->single_step(&dbg_context, FALSE); + break_set_xpoints(TRUE); break; +#if 0 case EXEC_STEP_OVER_TRAMPOLINE: - /* - * This is the means by which we step over our conversion stubs - * in callfrom*.s and callto*.s. We dig the appropriate address - * off the stack, and we set the breakpoint there instead of the - * address just after the call. - */ -#ifdef __i386__ - DEBUG_READ_MEM((void*)(DEBUG_context.Esp + - 2 * sizeof(unsigned int)), - &addr.off, sizeof(addr.off)); - DEBUG_context.EFlags &= ~STEP_FLAG; + /* + * This is the means by which we step over our conversion stubs + * in callfrom*.s and callto*.s. We dig the appropriate address + * off the stack, and we set the breakpoint there instead of the + * address just after the call. + */ + be_cpu->get_addr(dbg_curr_thread->handle, &dbg_context, + be_cpu_addr_stack, &addr); + /* FIXME: we assume stack grows as on a i386 */ + addr.Offset += 2 * sizeof(unsigned int); + dbg_read_memory(memory_to_linear_addr(&addr), + &addr.Offset, sizeof(addr.Offset)); + dbg_curr_process->bp[0].addr = addr; + dbg_curr_process->bp[0].enabled = TRUE; + dbg_curr_process->bp[0].refcount = 1; + dbg_curr_process->bp[0].skipcount = 0; + be_cpu->single_step(&dbg_context, FALSE); + break_set_xpoints(TRUE); + break; #endif - breakpoints[0].addr = addr; - breakpoints[0].enabled = TRUE; - breakpoints[0].refcount = 1; - breakpoints[0].skipcount = 0; - DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr ), &breakpoints[0].u.b.opcode, - sizeof(char)); - DEBUG_SetBreakpoints( TRUE ); - break; - case EXEC_FINISH: - case EXEC_STEPI_OVER: /* Stepping over a call */ - case EXEC_STEP_OVER: /* Stepping over a call */ - if (DEBUG_IsStepOverInstr()) + case dbg_exec_finish: + case dbg_exec_step_over_insn: /* Stepping over a call */ + case dbg_exec_step_over_line: /* Stepping over a call */ + if (be_cpu->is_step_over_insn(memory_to_linear_addr(&addr))) { -#ifdef __i386__ - DEBUG_context.EFlags &= ~STEP_FLAG; -#endif - DEBUG_Disasm(&addr, FALSE); - breakpoints[0].addr = addr; - breakpoints[0].enabled = TRUE; - breakpoints[0].refcount = 1; - breakpoints[0].skipcount = 0; - DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr ), &breakpoints[0].u.b.opcode, - sizeof(char)); - DEBUG_SetBreakpoints( TRUE ); + be_cpu->single_step(&dbg_context, FALSE); + be_cpu->disasm_one_insn(&addr, FALSE); + dbg_curr_process->bp[0].addr = addr; + dbg_curr_process->bp[0].enabled = TRUE; + dbg_curr_process->bp[0].refcount = 1; + dbg_curr_process->bp[0].skipcount = 0; + be_cpu->single_step(&dbg_context, FALSE); + break_set_xpoints(TRUE); break; } /* else fall through to single-stepping */ - case EXEC_STEP_INSTR: /* Single-stepping an instruction */ - case EXEC_STEPI_INSTR: /* Single-stepping an instruction */ -#ifdef __i386__ - DEBUG_context.EFlags |= STEP_FLAG; -#endif + case dbg_exec_step_into_line: /* Single-stepping a line */ + case dbg_exec_step_into_insn: /* Single-stepping an instruction */ + be_cpu->single_step(&dbg_context, TRUE); break; - default: - RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); + default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); } - DEBUG_CurrThread->stepOverBP = breakpoints[0]; - DEBUG_CurrThread->exec_mode = ret_mode; + dbg_curr_thread->step_over_bp = dbg_curr_process->bp[0]; + dbg_curr_thread->exec_mode = ret_mode; } -int -DEBUG_AddBPCondition(int num, struct expr * exp) +int break_add_condition(int num, struct expr* exp) { - if ((num <= 0) || (num >= next_bp) || !breakpoints[num].refcount) + if (num <= 0 || num >= dbg_curr_process->next_bp || + !dbg_curr_process->bp[num].refcount) { - DEBUG_Printf("Invalid breakpoint number %d\n", num); + dbg_printf("Invalid breakpoint number %d\n", num); return FALSE; } - if( breakpoints[num].condition != NULL ) - { - DEBUG_FreeExpr(breakpoints[num].condition); - breakpoints[num].condition = NULL; - } + if (dbg_curr_process->bp[num].condition != NULL) + { + expr_free(dbg_curr_process->bp[num].condition); + dbg_curr_process->bp[num].condition = NULL; + } - if( exp != NULL ) - { - breakpoints[num].condition = DEBUG_CloneExpr(exp); - } + if (exp != NULL) dbg_curr_process->bp[num].condition = expr_clone(exp); - return TRUE; + return TRUE; } diff --git a/programs/winedbg/db_disasm.c b/programs/winedbg/db_disasm.c index f90c0b71986..3723374429b 100644 --- a/programs/winedbg/db_disasm.c +++ b/programs/winedbg/db_disasm.c @@ -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<ss); - DEBUG_Printf(")"); + dbg_printf(",%s,%d", addrp->index, 1<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(""); + dbg_printf(""); 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__ */ diff --git a/programs/winedbg/dbg.y b/programs/winedbg/dbg.y index 781740c7421..cc4677551d6 100644 --- a/programs/winedbg/dbg.y +++ b/programs/winedbg/dbg.y @@ -24,41 +24,36 @@ #include "config.h" #include "wine/port.h" -#include #include #include -#include #include #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 tPATH -%token tIDENTIFIER tSTRING tDEBUGSTR tINTVAR +%token tPATH tIDENTIFIER tSTRING tDEBUGSTR tINTVAR %token tNUM tFORMAT %token tSYMBOLFILE tRUN tATTACH tDETACH tNOPROCESS tMAINTENANCE tTYPE @@ -84,225 +79,239 @@ int yyerror(const char *); %left '.' '[' OP_DRF %nonassoc ':' -%type expr lval lvalue -%type type_expr -%type expr_addr lval_addr -%type expr_value +%type expr lvalue +%type expr_lvalue lvalue_addr +%type expr_rvalue %type pathname identifier - %type list_arg +%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 {} /* shall not barf anything */ - | tNOPROCESS tSTRING tEOL { DEBUG_Printf("No process loaded, cannot execute '%s'\n", $2); } + tNOPROCESS {} /* 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; } diff --git a/programs/winedbg/debug.l b/programs/winedbg/debug.l index b582a7f8cd4..f28d50536db 100644 --- a/programs/winedbg/debug.l +++ b/programs/winedbg/debug.l @@ -24,22 +24,46 @@ #include #include -#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);} <> { return tEOF; } <*>\n { BEGIN(INITIAL); syntax_error = 0; return tEOL; } @@ -92,17 +115,17 @@ STRING \"[^\n"]+\" {DIGIT}+ { sscanf(yytext, "%d", &yylval.integer); return tNUM; } "/"{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} { yylval.integer = (1 << 8) | yytext[1]; return tFORMAT; } -{STRING} { yylval.string = DEBUG_MakeSymbol(yytext); return tSTRING; } +{STRING} { yylval.string = lexeme_alloc(yytext); return tSTRING; } [^\n]+ { char* p = yytext; while (*p == ' ' || *p == '\t') p++; - yylval.string = DEBUG_MakeSymbol(p); return tSTRING; } + yylval.string = lexeme_alloc(p); return tSTRING; } -info|inf|in { BEGIN(INFO_CMD); return tINFO; } +info|inf|in { BEGIN(INFO_CMD); return tINFO; } up { BEGIN(NOCMD); return tUP; } down|dow|do { BEGIN(NOCMD); return tDOWN; } frame|fram|fra|fr { BEGIN(NOCMD); return tFRAME; } @@ -117,9 +140,8 @@ STRING \"[^\n"]+\" delete|delet|dele|del { BEGIN(BD_CMD); return tDELETE; } quit|qui|qu|q { BEGIN(NOCMD); return tQUIT; } set|se { BEGIN(NOCMD); return tSET; } -walk|w { BEGIN(WALK_CMD); return tWALK; } x { BEGIN(FORMAT_EXPECTED); return tEXAM; } -help|hel|he|"?" { BEGIN(HELP_CMD); return tHELP; } +help|hel|he|"?" { BEGIN(HELP_CMD); return tHELP; } backtrace|backtrac|backtra|backt|back|bac|ba|bt { BEGIN(NOCMD); return tBACKTRACE; } where|wher|whe { BEGIN(NOCMD); return tBACKTRACE; } @@ -150,17 +172,16 @@ STRING \"[^\n"]+\" attach|attac|atta|att { BEGIN(NOCMD); return tATTACH; } share|shar|sha { return tSHARE; } locals|local|loca|loc { return tLOCAL; } -class|clas|cla { return tCLASS; } -module|modul|modu|mod { return tMODULE; } -process|proces|proce|proc { return tPROCESS; } -threads|thread|threa|thre|thr|th { return tTHREAD; } -exception|except|exc|ex { return tEXCEPTION; } +class|clas|cla { return tCLASS; } +process|proces|proce|proc { return tPROCESS; } +threads|thread|threa|thre|thr|th { return tTHREAD; } +exception|except|exc|ex { return tEXCEPTION; } registers|regs|reg|re { return tREGS; } segments|segment|segm|seg|se { return tSEGMENTS; } stack|stac|sta|st { return tSTACK; } symbol|symbo|symb|sym { BEGIN(ASTRING_EXPECTED); return tSYMBOL; } -maps|map { return tMAPS; } -window|windo|wind|win|wnd { return tWND; } +maps|map { return tMAPS; } +window|windo|wind|win|wnd { return tWND; } info|inf|in { return tINFO; } vm86 { return tVM86; } 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; } -{PATHNAME} { yylval.string = DEBUG_MakeSymbol(yytext); return tPATH; } +{PATHNAME} { yylval.string = lexeme_alloc(yytext); return tPATH; } <*>[ \t]+ /* Eat up whitespace */ . { 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; } diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index c85d7f29166..c36e9785f39 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -24,162 +24,107 @@ #include #include +#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 */ diff --git a/programs/winedbg/display.c b/programs/winedbg/display.c index 279032cf665..e72f33eb03d 100644 --- a/programs/winedbg/display.c +++ b/programs/winedbg/display.c @@ -21,178 +21,229 @@ #include #include -#include -#include #include "debugger.h" +#include "wine/debug.h" -#include +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; } diff --git a/programs/winedbg/elf.c b/programs/winedbg/elf.c deleted file mode 100644 index fa29a537fde..00000000000 --- a/programs/winedbg/elf.c +++ /dev/null @@ -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 -#include -#include -#include -#ifdef HAVE_SYS_MMAN_H -#include -#endif -#ifdef HAVE_UNISTD_H -# include -#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 -#endif -#ifdef HAVE_SYS_ELF32_H -# include -#endif -#ifdef HAVE_SYS_EXEC_ELF_H -# include -#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 -#endif -#ifdef HAVE_SYS_LINK_H -# include -#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__ */ diff --git a/programs/winedbg/expr.c b/programs/winedbg/expr.c index 1f0bcfdb524..2fcf73348f4 100644 --- a/programs/winedbg/expr.c +++ b/programs/winedbg/expr.c @@ -24,889 +24,814 @@ #include #include -#include "windef.h" -#include "winbase.h" -#include "wine/winbase16.h" #include "debugger.h" #include "expr.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winedbg); struct expr { - unsigned int perm; - unsigned int type:31; - union - { - struct + unsigned int type; + union { - int value; - } constant; + struct + { + int value; + } s_const; - struct - { - const char * str; - } string; + struct + { + unsigned int value; + } u_const; - struct - { - unsigned int value; - } u_const; + struct + { + const char* str; + } string; - struct - { - const char * name; - } symbol; + struct + { + const char* name; + } symbol; - struct - { - const char * name; - } intvar; + struct + { + const char* name; + } intvar; - struct - { - int unop_type; - struct expr * exp1; - int result; - } unop; + struct + { + int unop_type; + struct expr* exp1; + long int result; + } unop; - struct - { - int binop_type; - int result; - struct expr * exp1; - struct expr * exp2; - } binop; + struct + { + int binop_type; + struct expr* exp1; + struct expr* exp2; + long int result; + } binop; - struct - { - struct datatype * cast; - struct expr * expr; - } cast; + struct + { + struct type_expr_t cast_to; + struct expr* expr; + } cast; - struct - { - struct expr * exp1; - const char * element_name; - int result; - } structure; + struct + { + struct expr* exp1; + const char* element_name; + long int result; + } structure; - struct - { - struct expr * base; - struct expr * index; - } array; + struct + { + const char* funcname; + int nargs; + struct expr* arg[5]; + long int result; + } call; - struct - { - const char * funcname; - int nargs; - int result; - struct expr * arg[5]; - } call; - - } un; + } un; }; -#define EXPR_TYPE_CONST 0 -#define EXPR_TYPE_US_CONST 1 +#define EXPR_TYPE_S_CONST 0 +#define EXPR_TYPE_U_CONST 1 #define EXPR_TYPE_SYMBOL 2 #define EXPR_TYPE_INTVAR 3 #define EXPR_TYPE_BINOP 4 #define EXPR_TYPE_UNOP 5 #define EXPR_TYPE_STRUCT 6 #define EXPR_TYPE_PSTRUCT 7 -#define EXPR_TYPE_ARRAY 8 -#define EXPR_TYPE_CALL 9 -#define EXPR_TYPE_STRING 10 -#define EXPR_TYPE_CAST 11 +#define EXPR_TYPE_CALL 8 +#define EXPR_TYPE_STRING 9 +#define EXPR_TYPE_CAST 10 static char expr_list[4096]; static unsigned int next_expr_free = 0; -/* - * This is how we turn an expression address into the actual value. - * This works well in the 32 bit domain - not sure at all about the - * 16 bit world. +static struct expr* expr_alloc(void) +{ + struct expr* rtn; + + rtn = (struct expr*)&expr_list[next_expr_free]; + + next_expr_free += sizeof(struct expr); + assert(next_expr_free < sizeof(expr_list)); + + return rtn; +} + +void expr_free_all(void) +{ + next_expr_free = 0; +} + +struct expr* expr_alloc_typecast(struct type_expr_t* tet, struct expr* exp) +{ + struct expr* ex; + + ex = expr_alloc(); + + ex->type = EXPR_TYPE_CAST; + ex->un.cast.cast_to = *tet; + ex->un.cast.expr = exp; + return ex; +} + +struct expr* expr_alloc_internal_var(const char* name) +{ + struct expr* ex; + + ex = expr_alloc(); + + ex->type = EXPR_TYPE_INTVAR; + ex->un.intvar.name = name; + return ex; +} + +struct expr* expr_alloc_symbol(const char* name) +{ + struct expr* ex; + + ex = expr_alloc(); + + ex->type = EXPR_TYPE_SYMBOL; + ex->un.symbol.name = name; + return ex; +} + +struct expr* expr_alloc_sconstant(int value) +{ + struct expr* ex; + + ex = expr_alloc(); + + ex->type = EXPR_TYPE_S_CONST; + ex->un.s_const.value = value; + return ex; +} + +struct expr* expr_alloc_uconstant(unsigned int value) +{ + struct expr* ex; + + ex = expr_alloc(); + + ex->type = EXPR_TYPE_U_CONST; + ex->un.u_const.value = value; + return ex; +} + +struct expr* expr_alloc_string(const char* str) +{ + struct expr* ex; + char* pnt; + + ex = expr_alloc(); + + ex->type = EXPR_TYPE_STRING; + ex->un.string.str = str + 1; + if ((pnt = strrchr(ex->un.string.str, '"'))) *pnt = '\0'; + return ex; +} + +struct expr* expr_alloc_binary_op(int op_type, struct expr* exp1, struct expr* exp2) +{ + struct expr* ex; + + ex = expr_alloc(); + + ex->type = EXPR_TYPE_BINOP; + ex->un.binop.binop_type = op_type; + ex->un.binop.exp1 = exp1; + ex->un.binop.exp2 = exp2; + return ex; +} + +struct expr* expr_alloc_unary_op(int op_type, struct expr* exp1) +{ + struct expr* ex; + + ex = expr_alloc(); + + ex->type = EXPR_TYPE_UNOP; + ex->un.unop.unop_type = op_type; + ex->un.unop.exp1 = exp1; + return ex; +} + +struct expr* expr_alloc_struct(struct expr* exp, const char* element) +{ + struct expr* ex; + + ex = expr_alloc(); + + ex->type = EXPR_TYPE_STRUCT; + ex->un.structure.exp1 = exp; + ex->un.structure.element_name = element; + return ex; +} + +struct expr* expr_alloc_pstruct(struct expr* exp, const char* element) +{ + struct expr* ex; + + ex = expr_alloc(); + + ex->type = EXPR_TYPE_PSTRUCT; + ex->un.structure.exp1 = exp; + ex->un.structure.element_name = element; + return ex; +} + +struct expr* expr_alloc_func_call(const char* funcname, int nargs, ...) +{ + struct expr* ex; + va_list ap; + int i; + + ex = expr_alloc(); + + ex->type = EXPR_TYPE_CALL; + ex->un.call.funcname = funcname; + ex->un.call.nargs = nargs; + + va_start(ap, nargs); + for (i = 0; i < nargs; i++) + { + ex->un.call.arg[i] = va_arg(ap, struct expr*); + } + va_end(ap); + return ex; +} + +/****************************************************************** + * expr_eval + * */ -#define VAL(_exp) DEBUG_GetExprValue(&_exp, NULL) - -static -struct expr * -DEBUG_GetFreeExpr(void) +struct dbg_lvalue expr_eval(struct expr* exp) { - struct expr * rtn; + struct dbg_lvalue rtn; + int i; + struct dbg_lvalue exp1; + struct dbg_lvalue exp2; + unsigned int cexp[5]; + DWORD scale1, scale2, scale3; + DWORD type1, type2; + DWORD linear1, linear2; + DWORD tag; + const struct dbg_internal_var* div; + + rtn.typeid = dbg_itype_none; + rtn.cookie = 0; + rtn.addr.Mode = AddrModeFlat; + rtn.addr.Offset = 0; + rtn.addr.Segment = 0; - rtn = (struct expr *) &expr_list[next_expr_free]; - - next_expr_free += sizeof(struct expr); - assert(next_expr_free < sizeof(expr_list)); - - return rtn; -} - -void -DEBUG_FreeExprMem(void) -{ - next_expr_free = 0; -} - -struct expr * -DEBUG_TypeCastExpr(struct datatype * dt, struct expr * exp) -{ - struct expr * ex; - - ex = DEBUG_GetFreeExpr(); - - ex->type = EXPR_TYPE_CAST; - ex->un.cast.cast = dt; - ex->un.cast.expr = exp; - return ex; -} - -struct expr * -DEBUG_IntVarExpr(const char* name) -{ - struct expr * ex; - - ex = DEBUG_GetFreeExpr(); - - ex->type = EXPR_TYPE_INTVAR; - ex->un.intvar.name = name; - return ex; -} - -struct expr * -DEBUG_SymbolExpr(const char * name) -{ - struct expr * ex; - - ex = DEBUG_GetFreeExpr(); - - ex->type = EXPR_TYPE_SYMBOL; - ex->un.symbol.name = name; - return ex; -} - -struct expr * -DEBUG_ConstExpr(int value) -{ - struct expr * ex; - - ex = DEBUG_GetFreeExpr(); - - ex->type = EXPR_TYPE_CONST; - ex->un.constant.value = value; - return ex; -} - -struct expr * -DEBUG_StringExpr(const char * str) -{ - struct expr * ex; - char * pnt; - ex = DEBUG_GetFreeExpr(); - - ex->type = EXPR_TYPE_STRING; - ex->un.string.str = str+1; - pnt = strrchr(ex->un.string.str, '"'); - if( pnt != NULL ) - { - *pnt = '\0'; - } - return ex; -} - -struct expr * -DEBUG_USConstExpr(unsigned int value) -{ - struct expr * ex; - - ex = DEBUG_GetFreeExpr(); - - ex->type = EXPR_TYPE_CONST; - ex->un.u_const.value = value; - return ex; -} - -struct expr * -DEBUG_BinopExpr(int operator_type, struct expr * exp1, struct expr * exp2) -{ - struct expr * ex; - - ex = DEBUG_GetFreeExpr(); - - ex->type = EXPR_TYPE_BINOP; - ex->un.binop.binop_type = operator_type; - ex->un.binop.exp1 = exp1; - ex->un.binop.exp2 = exp2; - return ex; -} - -struct expr * -DEBUG_UnopExpr(int operator_type, struct expr * exp1) -{ - struct expr * ex; - - ex = DEBUG_GetFreeExpr(); - - ex->type = EXPR_TYPE_UNOP; - ex->un.unop.unop_type = operator_type; - ex->un.unop.exp1 = exp1; - return ex; -} - -struct expr * -DEBUG_StructExpr(struct expr * exp, const char * element) -{ - struct expr * ex; - - ex = DEBUG_GetFreeExpr(); - - ex->type = EXPR_TYPE_STRUCT; - ex->un.structure.exp1 = exp; - ex->un.structure.element_name = element; - return ex; -} - -struct expr * -DEBUG_StructPExpr(struct expr * exp, const char * element) -{ - struct expr * ex; - - ex = DEBUG_GetFreeExpr(); - - ex->type = EXPR_TYPE_PSTRUCT; - ex->un.structure.exp1 = exp; - ex->un.structure.element_name = element; - return ex; -} - -struct expr * -DEBUG_CallExpr(const char * funcname, int nargs, ...) -{ - struct expr * ex; - va_list ap; - int i; - - ex = DEBUG_GetFreeExpr(); - - ex->type = EXPR_TYPE_CALL; - ex->un.call.funcname = funcname; - ex->un.call.nargs = nargs; - - va_start(ap, nargs); - for(i=0; i < nargs; i++) - { - ex->un.call.arg[i] = va_arg(ap, struct expr *); - } - va_end(ap); - return ex; -} - -DBG_VALUE DEBUG_EvalExpr(struct expr * exp) -{ - DBG_VALUE rtn; - int i; - DBG_VALUE exp1; - DBG_VALUE exp2; - unsigned int cexp[5]; - int scale1; - int scale2; - int scale3; - struct datatype * type1; - struct datatype * type2; - - rtn.type = NULL; - rtn.cookie = DV_INVALID; - rtn.addr.off = 0; - rtn.addr.seg = 0; - - switch(exp->type) + switch (exp->type) { case EXPR_TYPE_CAST: - if (!exp->un.cast.cast) - { - DEBUG_Printf("Can't cast to unknown type\n"); - RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); - } - rtn = DEBUG_EvalExpr(exp->un.cast.expr); - rtn.type = exp->un.cast.cast; - break; + /* this is really brute force, we simply change the type... without + * checking if this is right or not + */ + rtn = expr_eval(exp->un.cast.expr); + linear1 = (DWORD)memory_to_linear_addr(&rtn.addr); + switch (exp->un.cast.cast_to.type) + { + case type_expr_type_id: + if (exp->un.cast.cast_to.u.typeid == dbg_itype_none) + { + dbg_printf("Can't cast to unknown type\n"); + RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + } + rtn.typeid = exp->un.cast.cast_to.u.typeid; + break; + case type_expr_udt_class: + case type_expr_udt_struct: + case type_expr_udt_union: + rtn.typeid = types_find_type(linear1, exp->un.cast.cast_to.u.name, SymTagUDT); + if (rtn.typeid == dbg_itype_none) + { + dbg_printf("Can't cast to UDT %s\n", exp->un.cast.cast_to.u.name); + RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + } + break; + case type_expr_enumeration: + rtn.typeid = types_find_type(linear1, exp->un.cast.cast_to.u.name, SymTagEnum); + if (rtn.typeid == dbg_itype_none) + { + dbg_printf("Can't cast to enumeration %s\n", exp->un.cast.cast_to.u.name); + RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + } + break; + default: + dbg_printf("Unsupported cast type %u\n", exp->un.cast.cast_to.type); + RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + } + for (i = 0; i < exp->un.cast.cast_to.deref_count; i++) + { + rtn.typeid = types_find_pointer(linear1, rtn.typeid); + if (rtn.typeid == dbg_itype_none) + { + dbg_printf("Cannot find pointer type\n"); + RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + } + } + break; case EXPR_TYPE_STRING: - rtn.type = DEBUG_GetBasicType(DT_BASIC_STRING); - rtn.cookie = DV_HOST; - rtn.addr.off = (unsigned int) &exp->un.string.str; - rtn.addr.seg = 0; - break; - case EXPR_TYPE_CONST: - rtn.type = DEBUG_GetBasicType(DT_BASIC_CONST_INT); - rtn.cookie = DV_HOST; - rtn.addr.off = (unsigned int) &exp->un.constant.value; - rtn.addr.seg = 0; - break; - case EXPR_TYPE_US_CONST: - rtn.type = DEBUG_GetBasicType(DT_BASIC_USHORTINT); - rtn.cookie = DV_HOST; - rtn.addr.off = (unsigned int) &exp->un.u_const.value; - rtn.addr.seg = 0; - break; + rtn.typeid = dbg_itype_astring; + rtn.cookie = DLV_HOST; + rtn.addr.Offset = (unsigned int)&exp->un.string.str; + break; + case EXPR_TYPE_U_CONST: + rtn.typeid = dbg_itype_unsigned_int; + rtn.cookie = DLV_HOST; + rtn.addr.Offset = (unsigned int)&exp->un.u_const.value; + break; + case EXPR_TYPE_S_CONST: + rtn.typeid = dbg_itype_signed_int; + rtn.cookie = DLV_HOST; + rtn.addr.Offset = (unsigned int)&exp->un.s_const.value; + break; case EXPR_TYPE_SYMBOL: - switch (DEBUG_GetSymbolValue(exp->un.symbol.name, -1, &rtn, FALSE)) - { - case gsv_found: - break; - case gsv_unknown: - RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL); - /* should never be here */ - case gsv_aborted: - RaiseException(DEBUG_STATUS_ABORT, 0, 0, NULL); - /* should never be here */ - } - break; + switch (symbol_get_lvalue(exp->un.symbol.name, -1, &rtn, FALSE)) + { + case sglv_found: + break; + case sglv_unknown: + RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL); + /* should never be here */ + case sglv_aborted: + RaiseException(DEBUG_STATUS_ABORT, 0, 0, NULL); + /* should never be here */ + } + break; case EXPR_TYPE_PSTRUCT: - exp1 = DEBUG_EvalExpr(exp->un.structure.exp1); - if( exp1.type == NULL ) - { - RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); - } - rtn.cookie = DV_TARGET; - rtn.addr.off = DEBUG_TypeDerefPointer(&exp1, &rtn.type); - if( rtn.type == NULL ) - { - RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); - } - if (!DEBUG_FindStructElement(&rtn, exp->un.structure.element_name, - &exp->un.structure.result)) - { - DEBUG_Printf("%s\n", exp->un.structure.element_name); - RaiseException(DEBUG_STATUS_NO_FIELD, 0, 0, NULL); - } - - break; + exp1 = expr_eval(exp->un.structure.exp1); + if (exp1.typeid == dbg_itype_none || !types_deref(&exp1, &rtn) || + rtn.typeid == dbg_itype_none) + RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + if (!types_udt_find_element(&rtn, exp->un.structure.element_name, + &exp->un.structure.result)) + { + dbg_printf("%s\n", exp->un.structure.element_name); + RaiseException(DEBUG_STATUS_NO_FIELD, 0, 0, NULL); + } + break; case EXPR_TYPE_STRUCT: - exp1 = DEBUG_EvalExpr(exp->un.structure.exp1); - if( exp1.type == NULL ) - { - RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); - } - rtn = exp1; - if (!DEBUG_FindStructElement(&rtn, exp->un.structure.element_name, - &exp->un.structure.result)) - { - DEBUG_Printf("%s\n", exp->un.structure.element_name); - RaiseException(DEBUG_STATUS_NO_FIELD, 0, 0, NULL); - } - break; + exp1 = expr_eval(exp->un.structure.exp1); + if (exp1.typeid == dbg_itype_none) RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + rtn = exp1; + if (!types_udt_find_element(&rtn, exp->un.structure.element_name, + &exp->un.structure.result)) + { + dbg_printf("%s\n", exp->un.structure.element_name); + RaiseException(DEBUG_STATUS_NO_FIELD, 0, 0, NULL); + } + break; case EXPR_TYPE_CALL: - /* - * First, evaluate all of the arguments. If any of them are not - * evaluable, then bail. - */ - for(i=0; i < exp->un.call.nargs; i++) + /* + * First, evaluate all of the arguments. If any of them are not + * evaluable, then bail. + */ + for (i = 0; i < exp->un.call.nargs; i++) { - exp1 = DEBUG_EvalExpr(exp->un.call.arg[i]); - if( exp1.type == NULL ) - { - return rtn; - } - cexp[i] = DEBUG_GetExprValue(&exp1, NULL); + exp1 = expr_eval(exp->un.call.arg[i]); + if (exp1.typeid == dbg_itype_none) + RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + cexp[i] = types_extract_as_integer(&exp1); } - /* - * Now look up the address of the function itself. - */ - switch (DEBUG_GetSymbolValue(exp->un.call.funcname, -1, &rtn, FALSE )) - { - case gsv_found: - break; - case gsv_unknown: - RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL); - /* should never be here */ - case gsv_aborted: - RaiseException(DEBUG_STATUS_ABORT, 0, 0, NULL); - /* should never be here */ - } + /* + * Now look up the address of the function itself. + */ + switch (symbol_get_lvalue(exp->un.call.funcname, -1, &rtn, FALSE)) + { + case sglv_found: + break; + case sglv_unknown: + RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL); + /* should never be here */ + case sglv_aborted: + RaiseException(DEBUG_STATUS_ABORT, 0, 0, NULL); + /* should never be here */ + } #if 0 - /* FIXME: NEWDBG NIY */ - /* Anyway, I wonder how this could work depending on the calling order of - * the function (cdecl vs pascal for example) - */ - int (*fptr)(); + /* FIXME: NEWDBG NIY */ + /* Anyway, I wonder how this could work depending on the calling order of + * the function (cdecl vs pascal for example) + */ + int (*fptr)(); - fptr = (int (*)()) rtn.addr.off; - switch(exp->un.call.nargs) + fptr = (int (*)()) rtn.addr.off; + switch (exp->un.call.nargs) { case 0: - exp->un.call.result = (*fptr)(); - break; + exp->un.call.result = (*fptr)(); + break; case 1: - exp->un.call.result = (*fptr)(cexp[0]); - break; + exp->un.call.result = (*fptr)(cexp[0]); + break; case 2: - exp->un.call.result = (*fptr)(cexp[0], cexp[1]); - break; + exp->un.call.result = (*fptr)(cexp[0], cexp[1]); + break; case 3: - exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2]); - break; + exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2]); + break; case 4: - exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2], cexp[3]); - break; + exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2], cexp[3]); + break; case 5: - exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2], cexp[3], cexp[4]); - break; + exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2], cexp[3], cexp[4]); + break; } #else - DEBUG_Printf("Function call no longer implemented\n"); - /* would need to set up a call to this function, and then restore the current - * context afterwards... - */ - exp->un.call.result = 0; + dbg_printf("Function call no longer implemented\n"); + /* would need to set up a call to this function, and then restore the current + * context afterwards... + */ + exp->un.call.result = 0; #endif - rtn.type = DEBUG_GetBasicType(DT_BASIC_INT); - rtn.cookie = DV_HOST; - rtn.addr.off = (unsigned int) &exp->un.call.result; - - break; + linear1 = (DWORD)memory_to_linear_addr(&rtn.addr); + /* get function signature type */ + types_get_info(linear1, rtn.typeid, TI_GET_TYPE, &rtn.typeid); + /* and now, return type */ + types_get_info(linear1, rtn.typeid, TI_GET_TYPE, &rtn.typeid); + rtn.cookie = DLV_HOST; + rtn.addr.Mode = AddrModeFlat; + rtn.addr.Offset = (unsigned int)&exp->un.call.result; + break; case EXPR_TYPE_INTVAR: - { - - DBG_INTVAR* div = DEBUG_GetIntVar(exp->un.intvar.name); - - if (!div) RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL); - rtn.cookie = DV_HOST; - rtn.type = div->type; - rtn.addr.off = (unsigned int)div->pval; - /* EPP FIXME rtn.addr.seg = ?? */ - } - break; + if (!(div = dbg_get_internal_var(exp->un.intvar.name))) + RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL); + rtn.cookie = DLV_HOST; + rtn.typeid = div->typeid; + rtn.addr.Offset = (unsigned int)div->pval; + break; case EXPR_TYPE_BINOP: - exp1 = DEBUG_EvalExpr(exp->un.binop.exp1); - exp2 = DEBUG_EvalExpr(exp->un.binop.exp2); - rtn.cookie = DV_HOST; - if( exp1.type == NULL || exp2.type == NULL ) - { - RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); - } - if( exp1.type == DEBUG_GetBasicType(DT_BASIC_CONST_INT) && - exp2.type == DEBUG_GetBasicType(DT_BASIC_CONST_INT) ) - { - rtn.type = exp1.type; - } - else - { - rtn.type = DEBUG_GetBasicType(DT_BASIC_INT); - } - rtn.addr.seg = 0; - rtn.addr.off = (unsigned int) &exp->un.binop.result; - switch(exp->un.binop.binop_type) + exp1 = expr_eval(exp->un.binop.exp1); + exp2 = expr_eval(exp->un.binop.exp2); + rtn.cookie = DLV_HOST; + if (exp1.typeid == dbg_itype_none || exp2.typeid == dbg_itype_none) + RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + linear1 = (DWORD)memory_to_linear_addr(&exp1.addr); + linear2 = (DWORD)memory_to_linear_addr(&exp2.addr); + rtn.typeid = dbg_itype_signed_int; + rtn.addr.Offset = (unsigned int)&exp->un.binop.result; + switch (exp->un.binop.binop_type) { case EXP_OP_ADD: - type1 = DEBUG_GetPointerType(exp1.type); - type2 = DEBUG_GetPointerType(exp2.type); - scale1 = 1; - scale2 = 1; - if( type1 != NULL && type2 != NULL ) + if (!types_get_info(linear1, exp1.typeid, TI_GET_SYMTAG, &tag) || + tag != SymTagPointerType || + !types_get_info(linear1, exp1.typeid, TI_GET_TYPE, &type1)) + type1 = dbg_itype_none; + if (!types_get_info(linear1, exp2.typeid, TI_GET_SYMTAG, &tag) || + tag != SymTagPointerType || + !types_get_info(linear1, exp2.typeid, TI_GET_TYPE, &type2)) + type2 = dbg_itype_none; + scale1 = 1; + scale2 = 1; + if (type1 != dbg_itype_none && type2 != dbg_itype_none) + RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + if (type1 != dbg_itype_none) { - RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + types_get_info(linear1, type1, TI_GET_LENGTH, &scale2); + rtn.typeid = exp1.typeid; } - else if( type1 != NULL ) + else if (type2 != dbg_itype_none) { - scale2 = DEBUG_GetObjectSize(type1); - rtn.type = exp1.type; + types_get_info(linear2, type2, TI_GET_LENGTH, &scale1); + rtn.typeid = exp2.typeid; } - else if( type2 != NULL ) - { - scale1 = DEBUG_GetObjectSize(type2); - rtn.type = exp2.type; - } - exp->un.binop.result = (VAL(exp1) * scale1 + scale2 * VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) * scale1 + + scale2 * types_extract_as_integer(&exp2)); + break; case EXP_OP_SUB: - type1 = DEBUG_GetPointerType(exp1.type); - type2 = DEBUG_GetPointerType(exp2.type); - scale1 = 1; - scale2 = 1; - scale3 = 1; - if( type1 != NULL && type2 != NULL ) + if (!types_get_info(linear1, exp1.typeid, TI_GET_SYMTAG, &tag) || + tag != SymTagPointerType || + !types_get_info(linear1, exp1.typeid, TI_GET_TYPE, &type1)) + type1 = dbg_itype_none; + if (!types_get_info(linear2, exp2.typeid, TI_GET_SYMTAG, &tag) || + tag != SymTagPointerType || + !types_get_info(linear2, exp2.typeid, TI_GET_TYPE, &type2)) + type2 = dbg_itype_none; + scale1 = 1; + scale2 = 1; + scale3 = 1; + if (type1 != dbg_itype_none && type2 != dbg_itype_none) { - if( type1 != type2 ) - { - RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); - } - scale3 = DEBUG_GetObjectSize(type1); + if (type1 != type2) RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + types_get_info(linear1, type1, TI_GET_LENGTH, &scale3); } - else if( type1 != NULL ) + else if (type1 != dbg_itype_none) { - scale2 = DEBUG_GetObjectSize(type1); - rtn.type = exp1.type; + types_get_info(linear1, type1, TI_GET_LENGTH, &scale2); + rtn.typeid = exp1.typeid; } - - else if( type2 != NULL ) + else if (type2 != dbg_itype_none) { - scale1 = DEBUG_GetObjectSize(type2); - rtn.type = exp2.type; + types_get_info(linear2, type2, TI_GET_LENGTH, &scale1); + rtn.typeid = exp2.typeid; } - exp->un.binop.result = (VAL(exp1) - VAL(exp2)) / scale3; - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) * scale1 - + types_extract_as_integer(&exp2) * scale2) / scale3; + break; case EXP_OP_SEG: - rtn.cookie = DV_TARGET; - rtn.type = NULL; - rtn.addr.seg = VAL(exp1); - rtn.addr.off = VAL(exp2); - break; + rtn.cookie = DLV_TARGET; + rtn.typeid = dbg_itype_none; + rtn.addr.Mode = AddrMode1632; + rtn.addr.Segment = types_extract_as_integer(&exp1); + rtn.addr.Offset = types_extract_as_integer(&exp2); + break; case EXP_OP_LOR: - exp->un.binop.result = (VAL(exp1) || VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) || types_extract_as_integer(&exp2)); + break; case EXP_OP_LAND: - exp->un.binop.result = (VAL(exp1) && VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) && types_extract_as_integer(&exp2)); + break; case EXP_OP_OR: - exp->un.binop.result = (VAL(exp1) | VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) | types_extract_as_integer(&exp2)); + break; case EXP_OP_AND: - exp->un.binop.result = (VAL(exp1) & VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) & types_extract_as_integer(&exp2)); + break; case EXP_OP_XOR: - exp->un.binop.result = (VAL(exp1) ^ VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) ^ types_extract_as_integer(&exp2)); + break; case EXP_OP_EQ: - exp->un.binop.result = (VAL(exp1) == VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) == types_extract_as_integer(&exp2)); + break; case EXP_OP_GT: - exp->un.binop.result = (VAL(exp1) > VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) > types_extract_as_integer(&exp2)); + break; case EXP_OP_LT: - exp->un.binop.result = (VAL(exp1) < VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) < types_extract_as_integer(&exp2)); + break; case EXP_OP_GE: - exp->un.binop.result = (VAL(exp1) >= VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) >= types_extract_as_integer(&exp2)); + break; case EXP_OP_LE: - exp->un.binop.result = (VAL(exp1) <= VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) <= types_extract_as_integer(&exp2)); + break; case EXP_OP_NE: - exp->un.binop.result = (VAL(exp1) != VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) != types_extract_as_integer(&exp2)); + break; case EXP_OP_SHL: - exp->un.binop.result = ((unsigned) VAL(exp1) << VAL(exp2)); - break; + exp->un.binop.result = ((unsigned long)types_extract_as_integer(&exp1) << types_extract_as_integer(&exp2)); + break; case EXP_OP_SHR: - exp->un.binop.result = ((unsigned) VAL(exp1) >> VAL(exp2)); - break; + exp->un.binop.result = ((unsigned long)types_extract_as_integer(&exp1) >> types_extract_as_integer(&exp2)); + break; case EXP_OP_MUL: - exp->un.binop.result = (VAL(exp1) * VAL(exp2)); - break; + exp->un.binop.result = (types_extract_as_integer(&exp1) * types_extract_as_integer(&exp2)); + break; case EXP_OP_DIV: - if( VAL(exp2) == 0 ) - { - RaiseException(DEBUG_STATUS_DIV_BY_ZERO, 0, 0, NULL); - } - exp->un.binop.result = (VAL(exp1) / VAL(exp2)); - break; + if (types_extract_as_integer(&exp2) == 0) RaiseException(DEBUG_STATUS_DIV_BY_ZERO, 0, 0, NULL); + exp->un.binop.result = (types_extract_as_integer(&exp1) / types_extract_as_integer(&exp2)); + break; case EXP_OP_REM: - if( VAL(exp2) == 0 ) - { - RaiseException(DEBUG_STATUS_DIV_BY_ZERO, 0, 0, NULL); - } - exp->un.binop.result = (VAL(exp1) % VAL(exp2)); - break; + if (types_extract_as_integer(&exp2) == 0) RaiseException(DEBUG_STATUS_DIV_BY_ZERO, 0, 0, NULL); + exp->un.binop.result = (types_extract_as_integer(&exp1) % types_extract_as_integer(&exp2)); + break; case EXP_OP_ARR: - DEBUG_ArrayIndex(&exp1, &rtn, VAL(exp2)); - break; - default: - RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); - break; + if (!types_array_index(&exp1, types_extract_as_integer(&exp2), &rtn)) + RaiseException(DEBUG_STATUS_CANT_DEREF, 0, 0, NULL); + break; + default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); } - break; + break; case EXPR_TYPE_UNOP: - exp1 = DEBUG_EvalExpr(exp->un.unop.exp1); - rtn.cookie = DV_HOST; - if( exp1.type == NULL ) - { - RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); - } - rtn.addr.seg = 0; - rtn.addr.off = (unsigned int) &exp->un.unop.result; - if( exp1.type == DEBUG_GetBasicType(DT_BASIC_CONST_INT) ) - { - rtn.type = exp1.type; - } - else - { - rtn.type = DEBUG_GetBasicType(DT_BASIC_INT); - } - switch(exp->un.unop.unop_type) + exp1 = expr_eval(exp->un.unop.exp1); + if (exp1.typeid == dbg_itype_none) RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + rtn.cookie = DLV_HOST; + rtn.addr.Offset = (unsigned int)&exp->un.unop.result; + rtn.typeid = dbg_itype_signed_int; + switch (exp->un.unop.unop_type) { case EXP_OP_NEG: - exp->un.unop.result = -VAL(exp1); - break; + exp->un.unop.result = -types_extract_as_integer(&exp1); + break; case EXP_OP_NOT: - exp->un.unop.result = !VAL(exp1); - break; + exp->un.unop.result = !types_extract_as_integer(&exp1); + break; case EXP_OP_LNOT: - exp->un.unop.result = ~VAL(exp1); - break; + exp->un.unop.result = ~types_extract_as_integer(&exp1); + break; case EXP_OP_DEREF: - /* FIXME: this is currently buggy. - * there is no way to tell were the deref:ed value is... - * for example: - * x is a pointer to struct s, x being on the stack - * => exp1 is target, result is target - * x is a pointer to struct s, x being optimized into a reg - * => exp1 is host, result is target - * x is a pointer to internal variable x - * => exp1 is host, result is host - * so we force DV_TARGET, because dereferencing pointers to - * internal variables is very unlikely. a correct fix would be - * rather large. - */ - rtn.cookie = DV_TARGET; - rtn.addr.off = (unsigned int) DEBUG_TypeDerefPointer(&exp1, &rtn.type); - if (!rtn.type) - { - RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); - } - break; + /* FIXME: this is currently buggy. + * there is no way to tell were the deref:ed value is... + * for example: + * x is a pointer to struct s, x being on the stack + * => exp1 is target, result is target + * x is a pointer to struct s, x being optimized into a reg + * => exp1 is host, result is target + * x is a pointer to internal variable x + * => exp1 is host, result is host + * so we force DLV_TARGET, because dereferencing pointers to + * internal variables is very unlikely. a correct fix would be + * rather large. + */ + if (!types_deref(&exp1, &rtn)) + RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL); + break; case EXP_OP_FORCE_DEREF: - rtn.cookie = exp1.cookie; - rtn.addr.seg = exp1.addr.seg; - if (exp1.cookie == DV_TARGET) - DEBUG_READ_MEM((void*)exp1.addr.off, &rtn.addr.off, sizeof(rtn.addr.off)); - else - memcpy(&rtn.addr.off, (void*)exp1.addr.off, sizeof(rtn.addr.off)); - break; + rtn = exp1; + if (exp1.cookie == DLV_TARGET) + dbg_read_memory(memory_to_linear_addr(&exp1.addr), &rtn.addr.Offset, sizeof(rtn.addr.Offset)); + break; case EXP_OP_ADDR: - /* FIXME: even for a 16 bit entity ? */ - rtn.type = DEBUG_FindOrMakePointerType(exp1.type); - exp->un.unop.result = exp1.addr.off; - break; - default: - RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); + /* only do it on linear addresses */ + if (exp1.addr.Mode != AddrModeFlat) + RaiseException(DEBUG_STATUS_CANT_DEREF, 0, 0, NULL); + exp->un.unop.result = (unsigned int)memory_to_linear_addr(&exp1.addr); + rtn.typeid = types_find_pointer(exp->un.unop.result, exp1.typeid); + break; + default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); } - break; + break; default: - DEBUG_Printf("Unexpected expression (%d).\n", exp->type); - RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); - break; + WINE_FIXME("Unexpected expression (%d).\n", exp->type); + RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); + break; } - assert(rtn.cookie == DV_TARGET || rtn.cookie == DV_HOST); + assert(rtn.cookie == DLV_TARGET || rtn.cookie == DLV_HOST); - return rtn; + return rtn; } - -int -DEBUG_DisplayExpr(const struct expr * exp) +int expr_print(const struct expr* exp) { - int i; + int i; - switch(exp->type) + switch (exp->type) { case EXPR_TYPE_CAST: - DEBUG_Printf("(("); - DEBUG_PrintTypeCast(exp->un.cast.cast); - DEBUG_Printf(")"); - DEBUG_DisplayExpr(exp->un.cast.expr); - DEBUG_Printf(")"); - break; + WINE_FIXME("No longer supported (missing module base)\n"); + dbg_printf("(("); + switch (exp->un.cast.cast_to.type) + { + case type_expr_type_id: + types_print_type(0, exp->un.cast.cast_to.type, FALSE); break; + case type_expr_udt_class: + dbg_printf("class %s", exp->un.cast.cast_to.u.name); break; + case type_expr_udt_struct: + dbg_printf("struct %s", exp->un.cast.cast_to.u.name); break; + case type_expr_udt_union: + dbg_printf("union %s", exp->un.cast.cast_to.u.name); break; + case type_expr_enumeration: + dbg_printf("enum %s", exp->un.cast.cast_to.u.name); break; + } + for (i = 0; i < exp->un.cast.cast_to.deref_count; i++) + dbg_printf("*"); + dbg_printf(")"); + expr_print(exp->un.cast.expr); + dbg_printf(")"); + break; case EXPR_TYPE_INTVAR: - DEBUG_Printf("$%s", exp->un.intvar.name); - break; - case EXPR_TYPE_US_CONST: - DEBUG_Printf("%ud", exp->un.u_const.value); - break; - case EXPR_TYPE_CONST: - DEBUG_Printf("%d", exp->un.u_const.value); - break; + dbg_printf("$%s", exp->un.intvar.name); + break; + case EXPR_TYPE_U_CONST: + dbg_printf("%u", exp->un.u_const.value); + break; + case EXPR_TYPE_S_CONST: + dbg_printf("%d", exp->un.s_const.value); + break; case EXPR_TYPE_STRING: - DEBUG_Printf("\"%s\"", exp->un.string.str); - break; + dbg_printf("\"%s\"", exp->un.string.str); + break; case EXPR_TYPE_SYMBOL: - DEBUG_Printf("%s" , exp->un.symbol.name); - break; + dbg_printf("%s" , exp->un.symbol.name); + break; case EXPR_TYPE_PSTRUCT: - DEBUG_DisplayExpr(exp->un.structure.exp1); - DEBUG_Printf("->%s", exp->un.structure.element_name); - break; + expr_print(exp->un.structure.exp1); + dbg_printf("->%s", exp->un.structure.element_name); + break; case EXPR_TYPE_STRUCT: - DEBUG_DisplayExpr(exp->un.structure.exp1); - DEBUG_Printf(".%s", exp->un.structure.element_name); - break; + expr_print(exp->un.structure.exp1); + dbg_printf(".%s", exp->un.structure.element_name); + break; case EXPR_TYPE_CALL: - DEBUG_Printf("%s(",exp->un.call.funcname); - for(i=0; i < exp->un.call.nargs; i++) + dbg_printf("%s(",exp->un.call.funcname); + for (i = 0; i < exp->un.call.nargs; i++) { - DEBUG_DisplayExpr(exp->un.call.arg[i]); - if( i != exp->un.call.nargs - 1 ) - { - DEBUG_Printf(", "); - } + expr_print(exp->un.call.arg[i]); + if (i != exp->un.call.nargs - 1) dbg_printf(", "); } - DEBUG_Printf(")"); - break; + dbg_printf(")"); + break; case EXPR_TYPE_BINOP: - DEBUG_Printf("( "); - DEBUG_DisplayExpr(exp->un.binop.exp1); - switch(exp->un.binop.binop_type) + dbg_printf("("); + expr_print(exp->un.binop.exp1); + switch (exp->un.binop.binop_type) { - case EXP_OP_ADD: - DEBUG_Printf(" + "); - break; - case EXP_OP_SUB: - DEBUG_Printf(" - "); - break; - case EXP_OP_SEG: - DEBUG_Printf(":"); - break; - case EXP_OP_LOR: - DEBUG_Printf(" || "); - break; - case EXP_OP_LAND: - DEBUG_Printf(" && "); - break; - case EXP_OP_OR: - DEBUG_Printf(" | "); - break; - case EXP_OP_AND: - DEBUG_Printf(" & "); - break; - case EXP_OP_XOR: - DEBUG_Printf(" ^ "); - break; - case EXP_OP_EQ: - DEBUG_Printf(" == "); - break; - case EXP_OP_GT: - DEBUG_Printf(" > "); - break; - case EXP_OP_LT: - DEBUG_Printf(" < "); - break; - case EXP_OP_GE: - DEBUG_Printf(" >= "); - break; - case EXP_OP_LE: - DEBUG_Printf(" <= "); - break; - case EXP_OP_NE: - DEBUG_Printf(" != "); - break; - case EXP_OP_SHL: - DEBUG_Printf(" << "); - break; - case EXP_OP_SHR: - DEBUG_Printf(" >> "); - break; - case EXP_OP_MUL: - DEBUG_Printf(" * "); - break; - case EXP_OP_DIV: - DEBUG_Printf(" / "); - break; - case EXP_OP_REM: - DEBUG_Printf(" %% "); - break; - case EXP_OP_ARR: - DEBUG_Printf("["); - break; - default: - break; + case EXP_OP_ADD: dbg_printf(" + "); break; + case EXP_OP_SUB: dbg_printf(" - "); break; + case EXP_OP_SEG: dbg_printf(":"); break; + case EXP_OP_LOR: dbg_printf(" || "); break; + case EXP_OP_LAND: dbg_printf(" && "); break; + case EXP_OP_OR: dbg_printf(" | "); break; + case EXP_OP_AND: dbg_printf(" & "); break; + case EXP_OP_XOR: dbg_printf(" ^ "); break; + case EXP_OP_EQ: dbg_printf(" == "); break; + case EXP_OP_GT: dbg_printf(" > "); break; + case EXP_OP_LT: dbg_printf(" < "); break; + case EXP_OP_GE: dbg_printf(" >= "); break; + case EXP_OP_LE: dbg_printf(" <= "); break; + case EXP_OP_NE: dbg_printf(" != "); break; + case EXP_OP_SHL: dbg_printf(" << "); break; + case EXP_OP_SHR: dbg_printf(" >> "); break; + case EXP_OP_MUL: dbg_printf(" * "); break; + case EXP_OP_DIV: dbg_printf(" / "); break; + case EXP_OP_REM: dbg_printf(" %% "); break; + case EXP_OP_ARR: dbg_printf("["); break; + default: break; } - DEBUG_DisplayExpr(exp->un.binop.exp2); - if( exp->un.binop.binop_type == EXP_OP_ARR ) - { - DEBUG_Printf("]"); - } - DEBUG_Printf(" )"); - break; + expr_print(exp->un.binop.exp2); + if (exp->un.binop.binop_type == EXP_OP_ARR) dbg_printf("]"); + dbg_printf(")"); + break; case EXPR_TYPE_UNOP: - switch(exp->un.unop.unop_type) + switch (exp->un.unop.unop_type) { - case EXP_OP_NEG: - DEBUG_Printf("-"); - break; - case EXP_OP_NOT: - DEBUG_Printf("!"); - break; - case EXP_OP_LNOT: - DEBUG_Printf("~"); - break; - case EXP_OP_DEREF: - DEBUG_Printf("*"); - break; - case EXP_OP_ADDR: - DEBUG_Printf("&"); - break; + case EXP_OP_NEG: dbg_printf("-"); break; + case EXP_OP_NOT: dbg_printf("!"); break; + case EXP_OP_LNOT: dbg_printf("~"); break; + case EXP_OP_DEREF: dbg_printf("*"); break; + case EXP_OP_ADDR: dbg_printf("&"); break; } - DEBUG_DisplayExpr(exp->un.unop.exp1); - break; + expr_print(exp->un.unop.exp1); + break; default: - DEBUG_Printf("Unexpected expression.\n"); - RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); - break; + WINE_FIXME("Unexpected expression (%u).\n", exp->type); + RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); + break; } - return TRUE; + return TRUE; } -struct expr * -DEBUG_CloneExpr(const struct expr * exp) +struct expr* expr_clone(const struct expr* exp) { - int i; - struct expr * rtn; + int i; + struct expr* rtn; - rtn = (struct expr *) DBG_alloc(sizeof(struct expr)); + rtn = HeapAlloc(GetProcessHeap(), 0, sizeof(struct expr)); - /* - * First copy the contents of the expression itself. - */ - *rtn = *exp; + /* + * First copy the contents of the expression itself. + */ + *rtn = *exp; - - switch(exp->type) + switch (exp->type) { case EXPR_TYPE_CAST: - rtn->un.cast.expr = DEBUG_CloneExpr(exp->un.cast.expr); - break; + rtn->un.cast.expr = expr_clone(exp->un.cast.expr); + break; case EXPR_TYPE_INTVAR: - rtn->un.intvar.name = DBG_strdup(exp->un.intvar.name); - break; - case EXPR_TYPE_US_CONST: - case EXPR_TYPE_CONST: - break; + rtn->un.intvar.name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(exp->un.intvar.name) + 1), exp->un.intvar.name); + break; + case EXPR_TYPE_U_CONST: + case EXPR_TYPE_S_CONST: + break; case EXPR_TYPE_STRING: - rtn->un.string.str = DBG_strdup(exp->un.string.str); - break; + rtn->un.string.str = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(exp->un.string.str) + 1), exp->un.string.str); + break; case EXPR_TYPE_SYMBOL: - rtn->un.symbol.name = DBG_strdup(exp->un.symbol.name); - break; + rtn->un.symbol.name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(exp->un.symbol.name) + 1), exp->un.symbol.name); + break; case EXPR_TYPE_PSTRUCT: case EXPR_TYPE_STRUCT: - rtn->un.structure.exp1 = DEBUG_CloneExpr(exp->un.structure.exp1); - rtn->un.structure.element_name = DBG_strdup(exp->un.structure.element_name); - break; + rtn->un.structure.exp1 = expr_clone(exp->un.structure.exp1); + rtn->un.structure.element_name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(exp->un.structure.element_name) + 1), exp->un.structure.element_name); + break; case EXPR_TYPE_CALL: - for(i=0; i < exp->un.call.nargs; i++) - { - rtn->un.call.arg[i] = DEBUG_CloneExpr(exp->un.call.arg[i]); + for (i = 0; i < exp->un.call.nargs; i++) + { + rtn->un.call.arg[i] = expr_clone(exp->un.call.arg[i]); } - rtn->un.call.funcname = DBG_strdup(exp->un.call.funcname); - break; + rtn->un.call.funcname = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(exp->un.call.funcname) + 1), exp->un.call.funcname); + break; case EXPR_TYPE_BINOP: - rtn->un.binop.exp1 = DEBUG_CloneExpr(exp->un.binop.exp1); - rtn->un.binop.exp2 = DEBUG_CloneExpr(exp->un.binop.exp2); - break; + rtn->un.binop.exp1 = expr_clone(exp->un.binop.exp1); + rtn->un.binop.exp2 = expr_clone(exp->un.binop.exp2); + break; case EXPR_TYPE_UNOP: - rtn->un.unop.exp1 = DEBUG_CloneExpr(exp->un.unop.exp1); - break; + rtn->un.unop.exp1 = expr_clone(exp->un.unop.exp1); + break; default: - DEBUG_Printf("Unexpected expression.\n"); - RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); - break; + WINE_FIXME("Unexpected expression (%u).\n", exp->type); + RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); + break; } - return rtn; + return rtn; } @@ -914,53 +839,52 @@ DEBUG_CloneExpr(const struct expr * exp) * Recursively go through an expression tree and free all memory associated * with it. */ -int -DEBUG_FreeExpr(struct expr * exp) +int expr_free(struct expr* exp) { - int i; + int i; - switch(exp->type) + switch (exp->type) { case EXPR_TYPE_CAST: - DEBUG_FreeExpr(exp->un.cast.expr); - break; + expr_free(exp->un.cast.expr); + break; case EXPR_TYPE_INTVAR: - DBG_free((char *) exp->un.intvar.name); - break; - case EXPR_TYPE_US_CONST: - case EXPR_TYPE_CONST: - break; + HeapFree(GetProcessHeap(), 0, (char*)exp->un.intvar.name); + break; + case EXPR_TYPE_U_CONST: + case EXPR_TYPE_S_CONST: + break; case EXPR_TYPE_STRING: - DBG_free((char *) exp->un.string.str); - break; + HeapFree(GetProcessHeap(), 0, (char*)exp->un.string.str); + break; case EXPR_TYPE_SYMBOL: - DBG_free((char *) exp->un.symbol.name); - break; + HeapFree(GetProcessHeap(), 0, (char*)exp->un.symbol.name); + break; case EXPR_TYPE_PSTRUCT: case EXPR_TYPE_STRUCT: - DEBUG_FreeExpr(exp->un.structure.exp1); - DBG_free((char *) exp->un.structure.element_name); - break; + expr_free(exp->un.structure.exp1); + HeapFree(GetProcessHeap(), 0, (char*)exp->un.structure.element_name); + break; case EXPR_TYPE_CALL: - for(i=0; i < exp->un.call.nargs; i++) + for (i = 0; i < exp->un.call.nargs; i++) { - DEBUG_FreeExpr(exp->un.call.arg[i]); + expr_free(exp->un.call.arg[i]); } - DBG_free((char *) exp->un.call.funcname); - break; + HeapFree(GetProcessHeap(), 0, (char*)exp->un.call.funcname); + break; case EXPR_TYPE_BINOP: - DEBUG_FreeExpr(exp->un.binop.exp1); - DEBUG_FreeExpr(exp->un.binop.exp2); - break; + expr_free(exp->un.binop.exp1); + expr_free(exp->un.binop.exp2); + break; case EXPR_TYPE_UNOP: - DEBUG_FreeExpr(exp->un.unop.exp1); - break; + expr_free(exp->un.unop.exp1); + break; default: - DEBUG_Printf("Unexpected expression.\n"); - RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); - break; + WINE_FIXME("Unexpected expression (%u).\n", exp->type); + RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); + break; } - DBG_free(exp); - return TRUE; + HeapFree(GetProcessHeap(), 0, exp); + return TRUE; } diff --git a/programs/winedbg/ext_debugger.c b/programs/winedbg/ext_debugger.c deleted file mode 100644 index a65485dbfd9..00000000000 --- a/programs/winedbg/ext_debugger.c +++ /dev/null @@ -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 -#endif -#include -#include -#include -#include - -#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: - * - * - * 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"); - -} diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index 0d87ba00261..3ac68191cc2 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -3,7 +3,7 @@ * This allows to debug Wine (and any "emulated" program) under * Linux using GDB * - * Copyright (c) Eric Pouech 2002-2003 + * Copyright (c) Eric Pouech 2002-2004 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -65,7 +65,7 @@ struct gdb_ctx_Xpoint { - int type; /* -1 means free */ + enum be_xpoint_type type; /* -1 means free */ void* addr; unsigned long val; }; @@ -87,15 +87,15 @@ struct gdb_context int out_len; int out_curr_packet; /* generic GDB thread information */ - DBG_THREAD* exec_thread; /* thread used in step & continue */ - DBG_THREAD* other_thread; /* thread to be used in any other operation */ + struct dbg_thread* exec_thread; /* thread used in step & continue */ + struct dbg_thread* other_thread; /* thread to be used in any other operation */ unsigned trace; /* current Win32 trap env */ unsigned last_sig; BOOL in_trap; CONTEXT context; /* Win32 information */ - DBG_PROCESS* process; + struct dbg_process* process; #define NUM_XPOINT 32 struct gdb_ctx_Xpoint Xpoints[NUM_XPOINT]; /* Unix environment */ @@ -158,341 +158,115 @@ static unsigned char checksum(const char* ptr, int len) * =============================================== * */ -#define OFFSET_OF(__c,__f) ((int)(((char*)&(((__c*)0)->__f))-((char*)0))) - #ifdef __i386__ static size_t cpu_register_map[] = { - OFFSET_OF(CONTEXT, Eax), - OFFSET_OF(CONTEXT, Ecx), - OFFSET_OF(CONTEXT, Edx), - OFFSET_OF(CONTEXT, Ebx), - OFFSET_OF(CONTEXT, Esp), - OFFSET_OF(CONTEXT, Ebp), - OFFSET_OF(CONTEXT, Esi), - OFFSET_OF(CONTEXT, Edi), - OFFSET_OF(CONTEXT, Eip), - OFFSET_OF(CONTEXT, EFlags), - OFFSET_OF(CONTEXT, SegCs), - OFFSET_OF(CONTEXT, SegSs), - OFFSET_OF(CONTEXT, SegDs), - OFFSET_OF(CONTEXT, SegEs), - OFFSET_OF(CONTEXT, SegFs), - OFFSET_OF(CONTEXT, SegGs), + FIELD_OFFSET(CONTEXT, Eax), + FIELD_OFFSET(CONTEXT, Ecx), + FIELD_OFFSET(CONTEXT, Edx), + FIELD_OFFSET(CONTEXT, Ebx), + FIELD_OFFSET(CONTEXT, Esp), + FIELD_OFFSET(CONTEXT, Ebp), + FIELD_OFFSET(CONTEXT, Esi), + FIELD_OFFSET(CONTEXT, Edi), + FIELD_OFFSET(CONTEXT, Eip), + FIELD_OFFSET(CONTEXT, EFlags), + FIELD_OFFSET(CONTEXT, SegCs), + FIELD_OFFSET(CONTEXT, SegSs), + FIELD_OFFSET(CONTEXT, SegDs), + FIELD_OFFSET(CONTEXT, SegEs), + FIELD_OFFSET(CONTEXT, SegFs), + FIELD_OFFSET(CONTEXT, SegGs), }; #else # ifdef __powerpc__ static size_t cpu_register_map[] = { - OFFSET_OF(CONTEXT, Gpr0), - OFFSET_OF(CONTEXT, Gpr1), - OFFSET_OF(CONTEXT, Gpr2), - OFFSET_OF(CONTEXT, Gpr3), - OFFSET_OF(CONTEXT, Gpr4), - OFFSET_OF(CONTEXT, Gpr5), - OFFSET_OF(CONTEXT, Gpr6), - OFFSET_OF(CONTEXT, Gpr7), - OFFSET_OF(CONTEXT, Gpr8), - OFFSET_OF(CONTEXT, Gpr9), - OFFSET_OF(CONTEXT, Gpr10), - OFFSET_OF(CONTEXT, Gpr11), - OFFSET_OF(CONTEXT, Gpr12), - OFFSET_OF(CONTEXT, Gpr13), - OFFSET_OF(CONTEXT, Gpr14), - OFFSET_OF(CONTEXT, Gpr15), - OFFSET_OF(CONTEXT, Gpr16), - OFFSET_OF(CONTEXT, Gpr17), - OFFSET_OF(CONTEXT, Gpr18), - OFFSET_OF(CONTEXT, Gpr19), - OFFSET_OF(CONTEXT, Gpr20), - OFFSET_OF(CONTEXT, Gpr21), - OFFSET_OF(CONTEXT, Gpr22), - OFFSET_OF(CONTEXT, Gpr23), - OFFSET_OF(CONTEXT, Gpr24), - OFFSET_OF(CONTEXT, Gpr25), - OFFSET_OF(CONTEXT, Gpr26), - OFFSET_OF(CONTEXT, Gpr27), - OFFSET_OF(CONTEXT, Gpr28), - OFFSET_OF(CONTEXT, Gpr29), - OFFSET_OF(CONTEXT, Gpr30), - OFFSET_OF(CONTEXT, Gpr31), - OFFSET_OF(CONTEXT, Fpr0), - OFFSET_OF(CONTEXT, Fpr1), - OFFSET_OF(CONTEXT, Fpr2), - OFFSET_OF(CONTEXT, Fpr3), - OFFSET_OF(CONTEXT, Fpr4), - OFFSET_OF(CONTEXT, Fpr5), - OFFSET_OF(CONTEXT, Fpr6), - OFFSET_OF(CONTEXT, Fpr7), - OFFSET_OF(CONTEXT, Fpr8), - OFFSET_OF(CONTEXT, Fpr9), - OFFSET_OF(CONTEXT, Fpr10), - OFFSET_OF(CONTEXT, Fpr11), - OFFSET_OF(CONTEXT, Fpr12), - OFFSET_OF(CONTEXT, Fpr13), - OFFSET_OF(CONTEXT, Fpr14), - OFFSET_OF(CONTEXT, Fpr15), - OFFSET_OF(CONTEXT, Fpr16), - OFFSET_OF(CONTEXT, Fpr17), - OFFSET_OF(CONTEXT, Fpr18), - OFFSET_OF(CONTEXT, Fpr19), - OFFSET_OF(CONTEXT, Fpr20), - OFFSET_OF(CONTEXT, Fpr21), - OFFSET_OF(CONTEXT, Fpr22), - OFFSET_OF(CONTEXT, Fpr23), - OFFSET_OF(CONTEXT, Fpr24), - OFFSET_OF(CONTEXT, Fpr25), - OFFSET_OF(CONTEXT, Fpr26), - OFFSET_OF(CONTEXT, Fpr27), - OFFSET_OF(CONTEXT, Fpr28), - OFFSET_OF(CONTEXT, Fpr29), - OFFSET_OF(CONTEXT, Fpr30), - OFFSET_OF(CONTEXT, Fpr31), + FIELD_OFFSET(CONTEXT, Gpr0), + FIELD_OFFSET(CONTEXT, Gpr1), + FIELD_OFFSET(CONTEXT, Gpr2), + FIELD_OFFSET(CONTEXT, Gpr3), + FIELD_OFFSET(CONTEXT, Gpr4), + FIELD_OFFSET(CONTEXT, Gpr5), + FIELD_OFFSET(CONTEXT, Gpr6), + FIELD_OFFSET(CONTEXT, Gpr7), + FIELD_OFFSET(CONTEXT, Gpr8), + FIELD_OFFSET(CONTEXT, Gpr9), + FIELD_OFFSET(CONTEXT, Gpr10), + FIELD_OFFSET(CONTEXT, Gpr11), + FIELD_OFFSET(CONTEXT, Gpr12), + FIELD_OFFSET(CONTEXT, Gpr13), + FIELD_OFFSET(CONTEXT, Gpr14), + FIELD_OFFSET(CONTEXT, Gpr15), + FIELD_OFFSET(CONTEXT, Gpr16), + FIELD_OFFSET(CONTEXT, Gpr17), + FIELD_OFFSET(CONTEXT, Gpr18), + FIELD_OFFSET(CONTEXT, Gpr19), + FIELD_OFFSET(CONTEXT, Gpr20), + FIELD_OFFSET(CONTEXT, Gpr21), + FIELD_OFFSET(CONTEXT, Gpr22), + FIELD_OFFSET(CONTEXT, Gpr23), + FIELD_OFFSET(CONTEXT, Gpr24), + FIELD_OFFSET(CONTEXT, Gpr25), + FIELD_OFFSET(CONTEXT, Gpr26), + FIELD_OFFSET(CONTEXT, Gpr27), + FIELD_OFFSET(CONTEXT, Gpr28), + FIELD_OFFSET(CONTEXT, Gpr29), + FIELD_OFFSET(CONTEXT, Gpr30), + FIELD_OFFSET(CONTEXT, Gpr31), + FIELD_OFFSET(CONTEXT, Fpr0), + FIELD_OFFSET(CONTEXT, Fpr1), + FIELD_OFFSET(CONTEXT, Fpr2), + FIELD_OFFSET(CONTEXT, Fpr3), + FIELD_OFFSET(CONTEXT, Fpr4), + FIELD_OFFSET(CONTEXT, Fpr5), + FIELD_OFFSET(CONTEXT, Fpr6), + FIELD_OFFSET(CONTEXT, Fpr7), + FIELD_OFFSET(CONTEXT, Fpr8), + FIELD_OFFSET(CONTEXT, Fpr9), + FIELD_OFFSET(CONTEXT, Fpr10), + FIELD_OFFSET(CONTEXT, Fpr11), + FIELD_OFFSET(CONTEXT, Fpr12), + FIELD_OFFSET(CONTEXT, Fpr13), + FIELD_OFFSET(CONTEXT, Fpr14), + FIELD_OFFSET(CONTEXT, Fpr15), + FIELD_OFFSET(CONTEXT, Fpr16), + FIELD_OFFSET(CONTEXT, Fpr17), + FIELD_OFFSET(CONTEXT, Fpr18), + FIELD_OFFSET(CONTEXT, Fpr19), + FIELD_OFFSET(CONTEXT, Fpr20), + FIELD_OFFSET(CONTEXT, Fpr21), + FIELD_OFFSET(CONTEXT, Fpr22), + FIELD_OFFSET(CONTEXT, Fpr23), + FIELD_OFFSET(CONTEXT, Fpr24), + FIELD_OFFSET(CONTEXT, Fpr25), + FIELD_OFFSET(CONTEXT, Fpr26), + FIELD_OFFSET(CONTEXT, Fpr27), + FIELD_OFFSET(CONTEXT, Fpr28), + FIELD_OFFSET(CONTEXT, Fpr29), + FIELD_OFFSET(CONTEXT, Fpr30), + FIELD_OFFSET(CONTEXT, Fpr31), - OFFSET_OF(CONTEXT, Iar), - OFFSET_OF(CONTEXT, Msr), - OFFSET_OF(CONTEXT, Cr), - OFFSET_OF(CONTEXT, Lr), - OFFSET_OF(CONTEXT, Ctr), - OFFSET_OF(CONTEXT, Xer), - /* FIXME: MQ is missing? OFFSET_OF(CONTEXT, Mq), */ + FIELD_OFFSET(CONTEXT, Iar), + FIELD_OFFSET(CONTEXT, Msr), + FIELD_OFFSET(CONTEXT, Cr), + FIELD_OFFSET(CONTEXT, Lr), + FIELD_OFFSET(CONTEXT, Ctr), + FIELD_OFFSET(CONTEXT, Xer), + /* FIXME: MQ is missing? FIELD_OFFSET(CONTEXT, Mq), */ /* see gdb/nlm/ppc.c */ }; # else # error "Define the registers map for your CPU" # endif #endif -#undef OFFSET_OF static const size_t cpu_num_regs = (sizeof(cpu_register_map) / sizeof(cpu_register_map[0])); -static inline unsigned long* cpu_register(const CONTEXT* ctx, unsigned idx) +static inline unsigned long* cpu_register(CONTEXT* ctx, unsigned idx) { assert(idx < cpu_num_regs); return (unsigned long*)((char*)ctx + cpu_register_map[idx]); } -static inline BOOL cpu_enter_stepping(struct gdb_context* gdbctx) -{ -#ifdef __i386__ - gdbctx->context.EFlags |= 0x100; - return TRUE; -#elif __powerpc__ -#ifndef MSR_SE -# define MSR_SE (1<<10) -#endif - gdbctx->context.Msr |= MSR_SE; - return TRUE; -#else -#error "Define step mode enter for your CPU" -#endif - return FALSE; -} - -static inline BOOL cpu_leave_stepping(struct gdb_context* gdbctx) -{ -#ifdef __i386__ - /* The Win32 debug API always resets the Step bit in EFlags after - * a single step instruction, so we don't need to clear when the - * step is done. - */ - return TRUE; -#elif __powerpc__ - gdbctx->context.Msr &= MSR_SE; - return TRUE; -#else -#error "Define step mode leave for your CPU" -#endif - return FALSE; -} - -#ifdef __i386__ -#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 i386_get_unused_DR(struct gdb_context* gdbctx, - unsigned long** r) -{ - if (!IS_DR7_SET(gdbctx->context.Dr7, 0)) - { - *r = &gdbctx->context.Dr0; - return 0; - } - if (!IS_DR7_SET(gdbctx->context.Dr7, 1)) - { - *r = &gdbctx->context.Dr1; - return 1; - } - if (!IS_DR7_SET(gdbctx->context.Dr7, 2)) - { - *r = &gdbctx->context.Dr2; - return 2; - } - if (!IS_DR7_SET(gdbctx->context.Dr7, 3)) - { - *r = &gdbctx->context.Dr3; - return 3; - } - return -1; -} -#endif - -/****************************************************************** - * cpu_insert_Xpoint - * - * returns 1 if ok - * 0 if error - * -1 if operation isn't supported by CPU - */ -static inline int cpu_insert_Xpoint(struct gdb_context* gdbctx, - struct gdb_ctx_Xpoint* xpt, size_t len) -{ -#ifdef __i386__ - unsigned char ch; - unsigned long sz; - unsigned long* pr; - int reg; - unsigned long bits; - - switch (xpt->type) - { - case '0': - if (len != 1) return 0; - if (!ReadProcessMemory(gdbctx->process->handle, xpt->addr, &ch, 1, &sz) || sz != 1) return 0; - xpt->val = ch; - ch = 0xcc; - if (!WriteProcessMemory(gdbctx->process->handle, xpt->addr, &ch, 1, &sz) || sz != 1) return 0; - break; - case '1': - bits = DR7_RW_EXECUTE; - goto hw_bp; - case '2': - bits = DR7_RW_READ; - goto hw_bp; - case '3': - bits = DR7_RW_WRITE; - hw_bp: - if ((reg = i386_get_unused_DR(gdbctx, &pr)) == -1) return 0; - *pr = (unsigned long)xpt->addr; - if (xpt->type != '1') switch (len) - { - case 4: bits |= DR7_LEN_4; break; - case 2: bits |= DR7_LEN_2; break; - case 1: bits |= DR7_LEN_1; break; - default: return 0; - } - xpt->val = reg; - /* clear old values */ - gdbctx->context.Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg)); - /* set the correct ones */ - gdbctx->context.Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg); - gdbctx->context.Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN; - break; - default: - fprintf(stderr, "Unknown bp type %c\n", xpt->type); - return 0; - } - return 1; -#elif defined(__powerpc__) - unsigned long xbp; - unsigned long sz; - - switch (xpt->type) - { - case '0': - if (len != 4) return 0; - if (!ReadProcessMemory(gdbctx->process->handle, xpt->addr, &xbp, 4, &sz) || sz != 4) return 0; - xpt->val = xbp; - xbp = 0x7d821008; /* 7d 82 10 08 ... in big endian */ - if (!WriteProcessMemory(gdbctx->process->handle, xpt->addr, &xbp, 4, &sz) || sz != 4) return 0; - break; - default: - fprintf(stderr, "Unknown/unsupported bp type %c\n", xpt->type); - return 0; - } - return 1; -#else -#error "Define insert Xpoint for your CPU" -#endif - return -1; -} - -/****************************************************************** - * cpu_remove_Xpoint - * - * returns 1 if ok - * 0 if error - * -1 if operation isn't supported by CPU - */ -static inline BOOL cpu_remove_Xpoint(struct gdb_context* gdbctx, - struct gdb_ctx_Xpoint* xpt, size_t len) -{ -#ifdef __i386__ - unsigned long sz; - unsigned char ch; - - switch (xpt->type) - { - case '0': - if (len != 1) return 0; - ch = (unsigned char)xpt->val; - if (!WriteProcessMemory(gdbctx->process->handle, xpt->addr, &ch, 1, &sz) || sz != 1) return 0; - break; - case '1': - case '2': - case '3': - /* simply disable the entry */ - gdbctx->context.Dr7 &= ~DR7_ENABLE_MASK(xpt->val); - break; - default: - fprintf(stderr, "Unknown bp type %c\n", xpt->type); - return 0; - } - return 1; -#elif defined(__powerpc__) - unsigned long sz; - unsigned long xbp; - - switch (xpt->type) - { - case '0': - if (len != 4) return 0; - xbp = xpt->val; - if (!WriteProcessMemory(gdbctx->process->handle, xpt->addr, &xbp, 4, &sz) || sz != 4) return 0; - break; - case '1': - case '2': - case '3': - default: - fprintf(stderr, "Unknown/unsupported bp type %c\n", xpt->type); - return 0; - } - return 1; -#else -#error "Define remove Xpoint for your CPU" -#endif - return -1; -} /* =============================================== * * W I N 3 2 D E B U G I N T E R F A C E * * =============================================== * @@ -572,7 +346,7 @@ static BOOL handle_exception(struct gdb_context* gdbctx, EXCEPTION_DEBUG_INFO* e break; default: if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT) - fprintf(stderr, "Unhandled exception code %08lx\n", rec->ExceptionCode); + fprintf(stderr, "Unhandled exception code 0x%08lx\n", rec->ExceptionCode); gdbctx->last_sig = SIGABRT; ret = TRUE; break; @@ -584,83 +358,74 @@ static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de) { char buffer[256]; - DEBUG_CurrThread = DEBUG_GetThread(gdbctx->process, de->dwThreadId); + dbg_curr_thread = dbg_get_thread(gdbctx->process, de->dwThreadId); switch (de->dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT: - DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), - de->u.CreateProcessInfo.hProcess, - de->u.CreateProcessInfo.lpImageName, - de->u.CreateProcessInfo.fUnicode); + memory_get_string_indirect(de->u.CreateProcessInfo.hProcess, + de->u.CreateProcessInfo.lpImageName, + de->u.CreateProcessInfo.fUnicode, + buffer, sizeof(buffer)); - /* FIXME unicode ? de->u.CreateProcessInfo.fUnicode */ if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT) fprintf(stderr, "%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n", de->dwProcessId, de->dwThreadId, buffer, de->u.CreateProcessInfo.lpImageName, - (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress, + (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress, de->u.CreateProcessInfo.dwDebugInfoFileOffset, de->u.CreateProcessInfo.nDebugInfoSize); - gdbctx->process = DEBUG_AddProcess(de->dwProcessId, - de->u.CreateProcessInfo.hProcess, - buffer); + gdbctx->process = dbg_add_process(de->dwProcessId, + de->u.CreateProcessInfo.hProcess, + buffer); /* de->u.CreateProcessInfo.lpStartAddress; */ + if (!SymInitialize(gdbctx->process->handle, NULL, TRUE)) + fprintf(stderr, "Couldn't initiate DbgHelp\n"); if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT) fprintf(stderr, "%08lx:%08lx: create thread I @%08lx\n", de->dwProcessId, de->dwThreadId, - (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress); + (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress); - assert(DEBUG_CurrThread == NULL); /* shouldn't be there */ - DEBUG_AddThread(gdbctx->process, de->dwThreadId, - de->u.CreateProcessInfo.hThread, - de->u.CreateProcessInfo.lpStartAddress, - de->u.CreateProcessInfo.lpThreadLocalBase); + assert(dbg_curr_thread == NULL); /* shouldn't be there */ + dbg_add_thread(gdbctx->process, de->dwThreadId, + de->u.CreateProcessInfo.hThread, + de->u.CreateProcessInfo.lpThreadLocalBase); break; case LOAD_DLL_DEBUG_EVENT: - assert(DEBUG_CurrThread); - DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), - gdbctx->process->handle, - de->u.LoadDll.lpImageName, - de->u.LoadDll.fUnicode); - - /* FIXME unicode: de->u.LoadDll.fUnicode */ + assert(dbg_curr_thread); + memory_get_string_indirect(gdbctx->process->handle, + de->u.LoadDll.lpImageName, + de->u.LoadDll.fUnicode, + buffer, sizeof(buffer)); if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT) fprintf(stderr, "%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n", de->dwProcessId, de->dwThreadId, buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll, de->u.LoadDll.dwDebugInfoFileOffset, de->u.LoadDll.nDebugInfoSize); -#if 0 - _strupr(buffer); - DEBUG_LoadModule32(buffer, de->u.LoadDll.hFile, de->u.LoadDll.lpBaseOfDll); - DEBUG_CheckDelayedBP(); - if (DBG_IVAR(BreakOnDllLoad)) - { - DEBUG_Printf("Stopping on DLL %s loading at %08lx\n", - buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll); - DEBUG_Parser(); - } -#endif + SymLoadModule(gdbctx->process->handle, de->u.LoadDll.hFile, buffer, NULL, + (unsigned long)de->u.LoadDll.lpBaseOfDll, 0); break; case UNLOAD_DLL_DEBUG_EVENT: if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT) fprintf(stderr, "%08lx:%08lx: unload DLL @%08lx\n", de->dwProcessId, de->dwThreadId, (unsigned long)de->u.UnloadDll.lpBaseOfDll); + SymUnloadModule(gdbctx->process->handle, + (unsigned long)de->u.UnloadDll.lpBaseOfDll); break; case EXCEPTION_DEBUG_EVENT: - assert(DEBUG_CurrThread); + assert(dbg_curr_thread); if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT) - fprintf(stderr, "%08lx:%08lx: exception code=%08lx\n", + fprintf(stderr, "%08lx:%08lx: exception code=0x%08lx\n", de->dwProcessId, de->dwThreadId, de->u.Exception.ExceptionRecord.ExceptionCode); - if (fetch_context(gdbctx, DEBUG_CurrThread->handle, &gdbctx->context)) + if (fetch_context(gdbctx, dbg_curr_thread->handle, &gdbctx->context)) { gdbctx->in_trap = handle_exception(gdbctx, &de->u.Exception); } @@ -669,13 +434,12 @@ static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de) case CREATE_THREAD_DEBUG_EVENT: if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT) fprintf(stderr, "%08lx:%08lx: create thread D @%08lx\n", - de->dwProcessId, de->dwThreadId, (unsigned long)(LPVOID)de->u.CreateThread.lpStartAddress); + de->dwProcessId, de->dwThreadId, (unsigned long)(void*)de->u.CreateThread.lpStartAddress); - DEBUG_AddThread(gdbctx->process, - de->dwThreadId, - de->u.CreateThread.hThread, - de->u.CreateThread.lpStartAddress, - de->u.CreateThread.lpThreadLocalBase); + dbg_add_thread(gdbctx->process, + de->dwThreadId, + de->u.CreateThread.hThread, + de->u.CreateThread.lpThreadLocalBase); break; case EXIT_THREAD_DEBUG_EVENT: @@ -683,10 +447,10 @@ static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de) fprintf(stderr, "%08lx:%08lx: exit thread (%ld)\n", de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode); - assert(DEBUG_CurrThread); - if (DEBUG_CurrThread == gdbctx->exec_thread) gdbctx->exec_thread = NULL; - if (DEBUG_CurrThread == gdbctx->other_thread) gdbctx->other_thread = NULL; - DEBUG_DelThread(DEBUG_CurrThread); + assert(dbg_curr_thread); + if (dbg_curr_thread == gdbctx->exec_thread) gdbctx->exec_thread = NULL; + if (dbg_curr_thread == gdbctx->other_thread) gdbctx->other_thread = NULL; + dbg_del_thread(dbg_curr_thread); break; case EXIT_PROCESS_DEBUG_EVENT: @@ -694,7 +458,7 @@ static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de) fprintf(stderr, "%08lx:%08lx: exit process (%ld)\n", de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode); - DEBUG_DelProcess(gdbctx->process); + dbg_del_process(gdbctx->process); gdbctx->process = NULL; /* now signal gdb that we're done */ gdbctx->last_sig = SIGTERM; @@ -702,11 +466,10 @@ static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de) break; case OUTPUT_DEBUG_STRING_EVENT: - assert(DEBUG_CurrThread); - DEBUG_ProcessGetString(buffer, sizeof(buffer), - gdbctx->process->handle, - de->u.DebugString.lpDebugStringData); - /* FIXME unicode de->u.DebugString.fUnicode ? */ + assert(dbg_curr_thread); + memory_get_string(gdbctx->process->handle, + de->u.DebugString.lpDebugStringData, DLV_TARGET, + de->u.DebugString.fUnicode, buffer, sizeof(buffer)); if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT) fprintf(stderr, "%08lx:%08lx: output debug string (%s)\n", de->dwProcessId, de->dwThreadId, buffer); @@ -728,18 +491,18 @@ static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de) static void resume_debuggee(struct gdb_context* gdbctx, unsigned long cont) { - if (DEBUG_CurrThread) + if (dbg_curr_thread) { - if (!SetThreadContext(DEBUG_CurrThread->handle, &gdbctx->context)) + if (!SetThreadContext(dbg_curr_thread->handle, &gdbctx->context)) if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR) - fprintf(stderr, "Cannot set context on thread %lu\n", DEBUG_CurrThread->tid); - if (!ContinueDebugEvent(gdbctx->process->pid, DEBUG_CurrThread->tid, cont)) + fprintf(stderr, "Cannot set context on thread %lu\n", dbg_curr_thread->tid); + if (!ContinueDebugEvent(gdbctx->process->pid, dbg_curr_thread->tid, cont)) if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR) fprintf(stderr, "Cannot continue on %lu (%lu)\n", - DEBUG_CurrThread->tid, cont); + dbg_curr_thread->tid, cont); } else if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR) - fprintf(stderr, "Cannot find last thread (%lu)\n", DEBUG_CurrThread->tid); + fprintf(stderr, "Cannot find last thread (%lu)\n", dbg_curr_thread->tid); } static void wait_for_debuggee(struct gdb_context* gdbctx) @@ -753,7 +516,7 @@ static void wait_for_debuggee(struct gdb_context* gdbctx) assert(!gdbctx->process || gdbctx->process->pid == 0 || de.dwProcessId == gdbctx->process->pid); - assert(!DEBUG_CurrThread || de.dwThreadId == DEBUG_CurrThread->tid); + assert(!dbg_curr_thread || de.dwThreadId == dbg_curr_thread->tid); if (gdbctx->in_trap) break; ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE); } @@ -761,11 +524,11 @@ static void wait_for_debuggee(struct gdb_context* gdbctx) static void detach_debuggee(struct gdb_context* gdbctx, BOOL kill) { - cpu_leave_stepping(gdbctx); + be_cpu->single_step(&gdbctx->context, FALSE); resume_debuggee(gdbctx, DBG_CONTINUE); if (!kill) DebugActiveProcessStop(gdbctx->process->pid); - DEBUG_DelProcess(gdbctx->process); + dbg_del_process(gdbctx->process); gdbctx->process = NULL; } @@ -805,12 +568,12 @@ static void get_process_info(struct gdb_context* gdbctx, char* buffer, size_t le static void get_thread_info(struct gdb_context* gdbctx, unsigned tid, char* buffer, size_t len) { - DBG_THREAD* thd; + struct dbg_thread* thd; unsigned long status; int prio; /* FIXME: use the size of buffer */ - thd = DEBUG_GetThread(gdbctx->process, tid); + thd = dbg_get_thread(gdbctx->process, tid); if (thd == NULL) { strcpy(buffer, "No information"); @@ -978,7 +741,7 @@ static enum packet_return packet_reply_status(struct gdb_context* gdbctx) sig = gdbctx->last_sig; packet_reply_val(gdbctx, sig, 1); packet_reply_add(gdbctx, "thread:", 7); - packet_reply_val(gdbctx, DEBUG_CurrThread->tid, 4); + packet_reply_val(gdbctx, dbg_curr_thread->tid, 4); packet_reply_catc(gdbctx, ';'); for (i = 0; i < cpu_num_regs; i++) @@ -1024,10 +787,10 @@ static enum packet_return packet_continue(struct gdb_context* gdbctx) { /* FIXME: add support for address in packet */ assert(gdbctx->in_packet_len == 0); - if (DEBUG_CurrThread != gdbctx->exec_thread && gdbctx->exec_thread) + if (dbg_curr_thread != gdbctx->exec_thread && gdbctx->exec_thread) if (gdbctx->trace & GDBPXY_TRC_COMMAND_FIXME) fprintf(stderr, "NIY: cont on %lu, while last thread is %lu\n", - gdbctx->exec_thread->tid, DEBUG_CurrThread->tid); + gdbctx->exec_thread->tid, dbg_curr_thread->tid); resume_debuggee(gdbctx, DBG_CONTINUE); wait_for_debuggee(gdbctx); return packet_reply_status(gdbctx); @@ -1039,10 +802,10 @@ static enum packet_return packet_continue_signal(struct gdb_context* gdbctx) /* FIXME: add support for address in packet */ assert(gdbctx->in_packet_len == 2); - if (DEBUG_CurrThread != gdbctx->exec_thread && gdbctx->exec_thread) + if (dbg_curr_thread != gdbctx->exec_thread && gdbctx->exec_thread) if (gdbctx->trace & GDBPXY_TRC_COMMAND_FIXME) fprintf(stderr, "NIY: cont/sig on %lu, while last thread is %lu\n", - gdbctx->exec_thread->tid, DEBUG_CurrThread->tid); + gdbctx->exec_thread->tid, dbg_curr_thread->tid); hex_from(&sig, gdbctx->in_packet, 1); /* cannot change signals on the fly */ if (gdbctx->trace & GDBPXY_TRC_COMMAND) @@ -1068,7 +831,7 @@ static enum packet_return packet_read_registers(struct gdb_context* gdbctx) assert(gdbctx->in_trap); - if (DEBUG_CurrThread != gdbctx->other_thread && gdbctx->other_thread) + if (dbg_curr_thread != gdbctx->other_thread && gdbctx->other_thread) { if (!fetch_context(gdbctx, gdbctx->other_thread->handle, pctx = &ctx)) return packet_error; @@ -1090,7 +853,7 @@ static enum packet_return packet_write_registers(struct gdb_context* gdbctx) CONTEXT* pctx = &gdbctx->context; assert(gdbctx->in_trap); - if (DEBUG_CurrThread != gdbctx->other_thread && gdbctx->other_thread) + if (dbg_curr_thread != gdbctx->other_thread && gdbctx->other_thread) { if (!fetch_context(gdbctx, gdbctx->other_thread->handle, pctx = &ctx)) return packet_error; @@ -1143,9 +906,9 @@ static enum packet_return packet_thread(struct gdb_context* gdbctx) return packet_error; } if (gdbctx->in_packet[0] == 'c') - gdbctx->exec_thread = DEBUG_GetThread(gdbctx->process, thread); + gdbctx->exec_thread = dbg_get_thread(gdbctx->process, thread); else - gdbctx->other_thread = DEBUG_GetThread(gdbctx->process, thread); + gdbctx->other_thread = dbg_get_thread(gdbctx->process, thread); return packet_ok; default: if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR) @@ -1270,7 +1033,7 @@ static enum packet_return packet_write_register(struct gdb_context* gdbctx) reg, gdbctx->in_packet_len - (ptr - gdbctx->in_packet), gdbctx->in_packet_len - (ptr - gdbctx->in_packet), ptr); - if (DEBUG_CurrThread != gdbctx->other_thread && gdbctx->other_thread) + if (dbg_curr_thread != gdbctx->other_thread && gdbctx->other_thread) { if (!fetch_context(gdbctx, gdbctx->other_thread->handle, pctx = &ctx)) return packet_error; @@ -1346,7 +1109,7 @@ static void packet_query_monitor_process(struct gdb_context* gdbctx, int len, co return; entry.dwSize = sizeof(entry); - ok = Process32First( snap, &entry ); + ok = Process32First(snap, &entry); /* we do the output in several 'O' packets, with the last one being just OK for * marking the end of the output */ @@ -1355,7 +1118,7 @@ static void packet_query_monitor_process(struct gdb_context* gdbctx, int len, co packet_reply_catc(gdbctx, 'O'); snprintf(buffer, sizeof(buffer), " %-8.8s %-8.8s %-8.8s %s\n", - "pid", "threads", "parent", "executable" ); + "pid", "threads", "parent", "executable"); packet_reply_hex_to_str(gdbctx, buffer); packet_reply_close(gdbctx); @@ -1469,43 +1232,6 @@ static void packet_query_monitor_trace(struct gdb_context* gdbctx, packet_reply_close(gdbctx); } -#ifdef __i386__ -static void packet_query_monitor_linear(struct gdb_context* gdbctx, - int len, const char* str) -{ - unsigned seg, ofs; - LDT_ENTRY le; - unsigned linear; - char buffer[32]; - - while (len > 0 && (*str == ' ' || *str == '\t')) - { - str++; len--; - } - /* FIXME: do a better scanning (allow both decimal and hex numbers) */ - if (!len || sscanf(str, "%x:%x", &seg, &ofs) != 2) - { - packet_reply_error(gdbctx, 0); - return; - } - - /* V86 mode ? */ - if (gdbctx->context.EFlags & 0x00020000) linear = (LOWORD(seg) << 4) + ofs; - /* linux system selector ? */ - else if (!(seg & 4) || ((seg >> 3) < 17)) linear = ofs; - /* standard selector */ - else if (GetThreadSelectorEntry(gdbctx->process->threads->handle, seg, &le)) - linear = (le.HighWord.Bits.BaseHi << 24) + (le.HighWord.Bits.BaseMid << 16) + - le.BaseLow + ofs; - /* error */ - else linear = 0; - snprintf(buffer, sizeof(buffer), "0x%x", linear); - packet_reply_open(gdbctx); - packet_reply_hex_to_str(gdbctx, buffer); - packet_reply_close(gdbctx); -} -#endif - struct query_detail { int with_arg; @@ -1520,9 +1246,6 @@ struct query_detail {0, "process", 7, packet_query_monitor_process}, {0, "mem", 3, packet_query_monitor_mem}, {1, "trace", 5, packet_query_monitor_trace}, -#ifdef __i386__ - {1, "linear", 6, packet_query_monitor_linear}, -#endif {0, NULL, 0, NULL}, }; @@ -1554,7 +1277,7 @@ static enum packet_return packet_query(struct gdb_context* gdbctx) case 'f': if (strncmp(gdbctx->in_packet + 1, "ThreadInfo", gdbctx->in_packet_len - 1) == 0) { - DBG_THREAD* thd; + struct dbg_thread* thd; packet_reply_open(gdbctx); packet_reply_add(gdbctx, "m", 1); @@ -1594,7 +1317,7 @@ static enum packet_return packet_query(struct gdb_context* gdbctx) case 'C': if (gdbctx->in_packet_len == 1) { - DBG_THREAD* thd; + struct dbg_thread* thd; /* FIXME: doc says 16 bit val ??? */ /* grab first created thread, aka last in list */ assert(gdbctx->process && gdbctx->process->threads); @@ -1661,14 +1384,14 @@ static enum packet_return packet_step(struct gdb_context* gdbctx) { /* FIXME: add support for address in packet */ assert(gdbctx->in_packet_len == 0); - if (DEBUG_CurrThread != gdbctx->exec_thread && gdbctx->exec_thread) + if (dbg_curr_thread != gdbctx->exec_thread && gdbctx->exec_thread) if (gdbctx->trace & GDBPXY_TRC_COMMAND_FIXME) fprintf(stderr, "NIY: step on %lu, while last thread is %lu\n", - gdbctx->exec_thread->tid, DEBUG_CurrThread->tid); - if (!cpu_enter_stepping(gdbctx)) return packet_error; + gdbctx->exec_thread->tid, dbg_curr_thread->tid); + be_cpu->single_step(&gdbctx->context, TRUE); resume_debuggee(gdbctx, DBG_CONTINUE); wait_for_debuggee(gdbctx); - if (!cpu_leave_stepping(gdbctx)) return packet_error; + be_cpu->single_step(&gdbctx->context, FALSE); return packet_reply_status(gdbctx); } @@ -1679,7 +1402,7 @@ static enum packet_return packet_step_signal(struct gdb_context* gdbctx) /* FIXME: add support for address in packet */ assert(gdbctx->in_packet_len == 2); - if (DEBUG_CurrThread->tid != gdbctx->exec_thread && gdbctx->exec_thread) + if (dbg_curr_thread->tid != gdbctx->exec_thread && gdbctx->exec_thread) if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR) fprintf(stderr, "NIY: step/sig on %u, while last thread is %u\n", gdbctx->exec_thread, DEBUG_CurrThread->tid); @@ -1703,7 +1426,7 @@ static enum packet_return packet_thread_alive(struct gdb_context* gdbctx) tid = strtol(gdbctx->in_packet, &end, 16); if (tid == -1 || tid == 0) return packet_reply_error(gdbctx, EINVAL); - if (DEBUG_GetThread(gdbctx->process, tid) != NULL) + if (dbg_get_thread(gdbctx->process, tid) != NULL) return packet_ok; return packet_reply_error(gdbctx, ESRCH); } @@ -1713,6 +1436,7 @@ static enum packet_return packet_remove_breakpoint(struct gdb_context* gdbctx) void* addr; unsigned len; struct gdb_ctx_Xpoint* xpt; + enum be_xpoint_type t; /* FIXME: check packet_len */ if (gdbctx->in_packet[0] < '0' || gdbctx->in_packet[0] > '4' || @@ -1722,17 +1446,25 @@ static enum packet_return packet_remove_breakpoint(struct gdb_context* gdbctx) if (gdbctx->trace & GDBPXY_TRC_COMMAND) fprintf(stderr, "Remove bp %p[%u] typ=%c\n", addr, len, gdbctx->in_packet[0]); + switch (gdbctx->in_packet[0]) + { + case '0': t = be_xpoint_break; len = 0; break; + case '1': t = be_xpoint_watch_exec; break; + case '2': t = be_xpoint_watch_read; break; + case '3': t = be_xpoint_watch_write; break; + default: return packet_error; + } for (xpt = &gdbctx->Xpoints[NUM_XPOINT - 1]; xpt >= gdbctx->Xpoints; xpt--) { - if (xpt->addr == addr && xpt->type == gdbctx->in_packet[0]) + if (xpt->addr == addr && xpt->type == t) { - switch (cpu_remove_Xpoint(gdbctx, xpt, len)) + if (be_cpu->remove_Xpoint(gdbctx->process->handle, &gdbctx->context, + t, xpt->addr, xpt->val, len)) { - case 1: xpt->type = -1; return packet_ok; - case 0: return packet_error; - case -1: return packet_done; - default: assert(0); + xpt->type = -1; + return packet_ok; } + break; } } return packet_error; @@ -1743,6 +1475,7 @@ static enum packet_return packet_set_breakpoint(struct gdb_context* gdbctx) void* addr; unsigned len; struct gdb_ctx_Xpoint* xpt; + enum be_xpoint_type t; /* FIXME: check packet_len */ if (gdbctx->in_packet[0] < '0' || gdbctx->in_packet[0] > '4' || @@ -1752,10 +1485,18 @@ static enum packet_return packet_set_breakpoint(struct gdb_context* gdbctx) if (gdbctx->trace & GDBPXY_TRC_COMMAND) fprintf(stderr, "Set bp %p[%u] typ=%c\n", addr, len, gdbctx->in_packet[0]); + switch (gdbctx->in_packet[0]) + { + case '0': t = be_xpoint_break; len = 0; break; + case '1': t = be_xpoint_watch_exec; break; + case '2': t = be_xpoint_watch_read; break; + case '3': t = be_xpoint_watch_write; break; + default: return packet_error; + } /* because of packet command handling, this should be made idempotent */ for (xpt = &gdbctx->Xpoints[NUM_XPOINT - 1]; xpt >= gdbctx->Xpoints; xpt--) { - if (xpt->addr == addr && xpt->type == gdbctx->in_packet[0]) + if (xpt->addr == addr && xpt->type == t) return packet_ok; /* nothing to do */ } /* really set the Xpoint */ @@ -1763,15 +1504,15 @@ static enum packet_return packet_set_breakpoint(struct gdb_context* gdbctx) { if (xpt->type == -1) { - xpt->addr = addr; - xpt->type = gdbctx->in_packet[0]; - switch (cpu_insert_Xpoint(gdbctx, xpt, len)) + if (be_cpu->insert_Xpoint(gdbctx->process->handle, &gdbctx->context, + t, addr, &xpt->val, len)) { - case 1: return packet_ok; - case 0: return packet_error; - case -1: return packet_done; - default: assert(0); + xpt->addr = addr; + xpt->type = t; + return packet_ok; } + fprintf(stderr, "cannot set xpoint\n"); + break; } } /* no more entries... eech */ @@ -1948,14 +1689,50 @@ static int fetch_data(struct gdb_context* gdbctx) return gdbctx->in_len - in_len; } +static BOOL gdb_exec(const char* wine_path, unsigned port, unsigned flags) +{ + char buf[MAX_PATH]; + int fd; + const char* gdb_path; + FILE* f; + + if (!(gdb_path = getenv("WINE_GDB"))) gdb_path = "gdb"; + strcpy(buf,"/tmp/winegdb.XXXXXX"); + fd = mkstemps(buf, 0); + if (fd == -1) return FALSE; + if ((f = fdopen(fd, "w+")) == NULL) return FALSE; + fprintf(f, "file %s\n", wine_path); + fprintf(f, "target remote localhost:%d\n", ntohs(port)); + fprintf(f, "monitor trace=%d\n", GDBPXY_TRC_COMMAND_FIXME); + fprintf(f, "set prompt Wine-gdb>\\ \n"); + /* gdb 5.1 seems to require it, won't hurt anyway */ + fprintf(f, "sharedlibrary\n"); + /* This is needed (but not a decent & final fix) + * Without this, gdb would skip our inter-DLL relay code (because + * we don't have any line number information for the relay code) + * With this, we will stop on first instruction of the stub, and + * reusing step, will get us through the relay stub at the actual + * function we're looking at. + */ + fprintf(f, "set step-mode on\n"); + /* tell gdb to delete this file when done handling it... */ + fprintf(f, "shell rm -f \"%s\"\n", buf); + fclose(f); + if (flags & 2) + execlp("xterm", "xterm", "-e", gdb_path, "-x", buf, NULL); + else + execlp(gdb_path, gdb_path, "-x", buf, NULL); + assert(0); /* never reached */ + return TRUE; +} + static BOOL gdb_startup(struct gdb_context* gdbctx, DEBUG_EVENT* de, unsigned flags) { int sock; struct sockaddr_in s_addrs; int s_len = sizeof(s_addrs); struct pollfd pollfd; - char wine_path[MAX_PATH]; - struct elf_info elf_info; + IMAGEHLP_MODULE imh_mod; /* step 1: create socket for gdb connection request */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) @@ -1969,19 +1746,13 @@ static BOOL gdb_startup(struct gdb_context* gdbctx, DEBUG_EVENT* de, unsigned fl getsockname(sock, (struct sockaddr*)&s_addrs, &s_len) == -1) return FALSE; - /* step 2: find out wine executable location (as a Unix filename) */ - elf_info.flags = ELF_INFO_PATH | ELF_INFO_SEGMENTS; - elf_info.elf_path = wine_path; - elf_info.elf_path_len = sizeof(wine_path); - if (DEBUG_ReadWineLoaderDbgInfo(de->u.CreateProcessInfo.hProcess, &elf_info) == DIL_ERROR) - return FALSE; - gdbctx->wine_segs[0] = elf_info.segments[0]; - gdbctx->wine_segs[1] = elf_info.segments[1]; - gdbctx->wine_segs[2] = elf_info.segments[2]; + /* step 2: do the process internal creation */ + handle_debug_event(gdbctx, de); - fprintf(stderr, "Using wine_path: %s\n", wine_path); + /* step3: get the wine loader name */ + if (!dbg_get_debuggee_info(gdbctx->process->handle, &imh_mod)) return FALSE; - /* step 3: fire up gdb (if requested) */ + /* step 4: fire up gdb (if requested) */ if (flags & 1) fprintf(stderr, "target remote localhost:%d\n", ntohs(s_addrs.sin_port)); else @@ -1994,39 +1765,11 @@ static BOOL gdb_startup(struct gdb_context* gdbctx, DEBUG_EVENT* de, unsigned fl default: /* in parent... success */ break; case 0: /* in child... and alive */ - { - char buf[MAX_PATH]; - int fd; - const char* gdb_path; - FILE* f; - - if (!(gdb_path = getenv("WINE_GDB"))) gdb_path = "gdb"; - strcpy(buf,"/tmp/winegdb.XXXXXX"); - fd = mkstemps(buf,0); - if (fd == -1) return FALSE; - if ((f = fdopen(fd, "w+")) == NULL) return FALSE; - fprintf(f, "file %s\n", wine_path); - fprintf(f, "target remote localhost:%d\n", ntohs(s_addrs.sin_port)); - fprintf(f, "monitor trace=%d\n", GDBPXY_TRC_COMMAND_FIXME); - fprintf(f, "set prompt Wine-gdb>\\ \n"); - /* gdb 5.1 seems to require it, won't hurt anyway */ - fprintf(f, "sharedlibrary\n"); - /* tell gdb to delete this file when done handling it... */ - fprintf(f, "shell rm -f \"%s\"\n", buf); - fclose(f); - if (flags & 2) - execlp("xterm", "xterm", "-e", gdb_path, "-x", buf, NULL); - else - execlp(gdb_path, gdb_path, "-x", buf, NULL); - assert(0); /* never reached */ - break; - } - break; + gdb_exec(imh_mod.LoadedImageName, s_addrs.sin_port, flags); + /* if we're here, exec failed, so report failure */ + return FALSE; } - /* step 4: do the process internal creation */ - handle_debug_event(gdbctx, de); - /* step 5: wait for gdb to connect actually */ pollfd.fd = sock; pollfd.events = POLLIN; @@ -2094,8 +1837,8 @@ static BOOL gdb_init_context(struct gdb_context* gdbctx, unsigned flags) { /* this should be the first event we get, * and the only one of this type */ - assert(gdbctx->process == NULL && de.dwProcessId == DEBUG_CurrPid); - /*gdbctx->dwProcessId = pid; */ + assert(gdbctx->process == NULL && de.dwProcessId == dbg_curr_pid); + /* gdbctx->dwProcessId = pid; */ if (!gdb_startup(gdbctx, &de, flags)) return FALSE; assert(!gdbctx->in_trap); } @@ -2109,7 +1852,7 @@ static BOOL gdb_init_context(struct gdb_context* gdbctx, unsigned flags) return TRUE; } -BOOL DEBUG_GdbRemote(unsigned flags) +BOOL gdb_remote(unsigned flags) { struct pollfd pollfd; struct gdb_context gdbctx; diff --git a/programs/winedbg/hash.c b/programs/winedbg/hash.c deleted file mode 100644 index 266a0251bcb..00000000000 --- a/programs/winedbg/hash.c +++ /dev/null @@ -1,1392 +0,0 @@ -/* - * File hash.c - generate hash tables for Wine debugger symbols - * - * Copyright (C) 1993, Eric Youngdale. - * - * 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 -#include -#include -#include -#include -#include "debugger.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winedbg); -WINE_DECLARE_DEBUG_CHANNEL(winedbg_sym); - -#define NR_NAME_HASH 16384 -#ifndef PATH_MAX -#define PATH_MAX MAX_PATH -#endif - -#ifdef __i386__ -static const char * reg_name[] = -{ - "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" -}; - -static unsigned reg_ofs[] = -{ - FIELD_OFFSET(CONTEXT, Eax), FIELD_OFFSET(CONTEXT, Ecx), - FIELD_OFFSET(CONTEXT, Edx), FIELD_OFFSET(CONTEXT, Ebx), - FIELD_OFFSET(CONTEXT, Esp), FIELD_OFFSET(CONTEXT, Ebp), - FIELD_OFFSET(CONTEXT, Esi), FIELD_OFFSET(CONTEXT, Edi) -}; -#else -static char * reg_name[] = { NULL }; /* FIXME */ -static unsigned reg_ofs[] = { 0 }; -#endif - - -struct name_hash -{ - struct name_hash * next; /* Used to look up within name hash */ - char * name; - char * sourcefile; - - int n_locals; - int locals_alloc; - WineLocals * local_vars; - - int n_lines; - int lines_alloc; - WineLineNo * linetab; - - DBG_VALUE value; - unsigned short flags; - unsigned short breakpoint_offset; - unsigned int symbol_size; -}; - - -static BOOL DEBUG_GetStackSymbolValue( const char * name, DBG_VALUE *value ); -static int sortlist_valid = FALSE; - -static int sorttab_nsym; -static struct name_hash ** addr_sorttab = NULL; - -static struct name_hash * name_hash_table[NR_NAME_HASH]; - -static unsigned int name_hash( const char * name ) -{ - unsigned int hash = 0; - unsigned int tmp; - const char * p; - - p = name; - - while (*p) - { - hash = (hash << 4) + *p++; - - if( (tmp = (hash & 0xf0000000)) ) - { - hash ^= tmp >> 24; - } - hash &= ~tmp; - } - return hash % NR_NAME_HASH; -} - -int -DEBUG_cmp_sym(const void * p1, const void * p2) -{ - struct name_hash * name1 = *(struct name_hash **) p1; - struct name_hash * name2 = *(struct name_hash **) p2; - - if( (name1->flags & SYM_INVALID) != 0 ) - return -1; - - if( (name2->flags & SYM_INVALID) != 0 ) - return 1; - - if( name1->value.addr.seg > name2->value.addr.seg ) - return 1; - - if( name1->value.addr.seg < name2->value.addr.seg ) - return -1; - - if( name1->value.addr.off > name2->value.addr.off ) - return 1; - - if( name1->value.addr.off < name2->value.addr.off ) - return -1; - - return 0; -} - -/*********************************************************************** - * DEBUG_ResortSymbols - * - * Rebuild sorted list of symbols. - */ -static -void -DEBUG_ResortSymbols(void) -{ - struct name_hash *nh; - int nsym = 0; - int i; - - for(i=0; inext) - { - if( (nh->flags & SYM_INVALID) == 0 ) - nsym++; - else - DEBUG_Printf("Symbol %s (%04lx:%08lx) is invalid\n", - nh->name, nh->value.addr.seg, nh->value.addr.off ); - } - } - - sorttab_nsym = nsym; - if( nsym == 0 ) - { - return; - } - - addr_sorttab = (struct name_hash **) DBG_realloc(addr_sorttab, - nsym * sizeof(struct name_hash *)); - - nsym = 0; - for(i=0; inext) - { - if( (nh->flags & SYM_INVALID) == 0 ) - addr_sorttab[nsym++] = nh; - } - } - - qsort(addr_sorttab, nsym, - sizeof(struct name_hash *), DEBUG_cmp_sym); - sortlist_valid = TRUE; - -} - -/*********************************************************************** - * DEBUG_AddSymbol - * - * Add a symbol to the table. - */ -struct name_hash * -DEBUG_AddSymbol( const char * name, const DBG_VALUE *value, - const char * source, int flags) -{ - struct name_hash * new; - struct name_hash *nh; - static char prev_source[PATH_MAX] = {'\0', }; - static char * prev_duped_source = NULL; - int hash; - - assert(value->cookie == DV_TARGET || value->cookie == DV_HOST); - - hash = name_hash(name); - for (nh = name_hash_table[hash]; nh; nh = nh->next) - { - if (name[0] == nh->name[0] && strcmp(name, nh->name) == 0) - { - int c = memcmp(&nh->value.addr, &value->addr, sizeof(value->addr)); - - if ((nh->flags & SYM_INVALID) != 0) - { - /* this case happens in ELF files, where we don't get the - * address of a symbol for the stabs part, but rather from - * the ELF sections. in this case, we'll call this function - * twice: - * - a first time while parsing the stabs, with a NULL - * address - * - a second time with the correct address - * SYM_INVALID is set for the first pass, and cleared in the second - * the code below gets most of information for both passes - * - * some GCC versions may provide the correct address in the first pass - * but it does not seem to be sensible to rely on that. - */ - if (nh->value.addr.seg == 0 && nh->value.addr.off == 0 && c != 0) - { - WINE_TRACE_(winedbg_sym)( - "Changing address for symbol %s (%04lx:%08lx => %04lx:%08lx)\n", - name, nh->value.addr.seg, nh->value.addr.off, value->addr.seg, value->addr.off); - nh->value.addr = value->addr; - } - if (nh->value.type == NULL && value->type != NULL) - { - nh->value.type = value->type; - nh->value.cookie = value->cookie; - } - /* it may happen that the same symbol is defined in several compilation - * units, but the linker decides to merge it into a single instance. - * in that case, we don't clear the invalid flag for all the compilation - * units (N_GSYM), and wait to get the symbol from the symtab - */ - if ((flags & SYM_INVALID) == 0) - nh->flags &= ~SYM_INVALID; - return nh; - } - /* don't define a symbol twice */ - if (c == 0 && (flags & SYM_INVALID) == 0) return nh; - } - } - - WINE_TRACE_(winedbg_sym)( - "adding %s symbol (%s) from file '%s' at %04lx:%08lx\n", - (flags & SYM_INVALID) ? "invalid" : " valid", name, source, value->addr.seg, value->addr.off); - - /* - * First see if we already have an entry for this symbol. If so - * return it, so we don't end up with duplicates. - */ - - new = (struct name_hash *) DBG_alloc(sizeof(struct name_hash)); - new->value = *value; - new->name = DBG_strdup(name); - - if( source != NULL ) - { - /* - * This is an enhancement to reduce memory consumption. The idea - * is that we duplicate a given string only once. This is a big - * win if there are lots of symbols defined in a given source file. - */ - if( strcmp(source, prev_source) == 0 ) - { - new->sourcefile = prev_duped_source; - } - else - { - strcpy(prev_source, source); - prev_duped_source = new->sourcefile = DBG_strdup(source); - } - } - else - { - new->sourcefile = NULL; - } - - new->n_lines = 0; - new->lines_alloc = 0; - new->linetab = NULL; - - new->n_locals = 0; - new->locals_alloc = 0; - new->local_vars = NULL; - - new->flags = flags; - new->next = NULL; - - /* Now insert into the hash table */ - new->next = name_hash_table[hash]; - name_hash_table[hash] = new; - - /* - * Check some heuristics based upon the file name to see whether - * we want to step through this guy or not. These are machine generated - * assembly files that are used to translate between the MS way of - * calling things and the GCC way of calling things. In general we - * always want to step through. - */ - if ( source != NULL ) { - int len = strlen(source); - - if (len > 2 && source[len-2] == '.' && source[len-1] == 's') { - char* c = strrchr(source - 2, '/'); - if (c != NULL) { - if (strcmp(c + 1, "asmrelay.s") == 0) - new->flags |= SYM_TRAMPOLINE; - } - } - } - - sortlist_valid = FALSE; - return new; -} - -BOOL DEBUG_Normalize(struct name_hash * nh ) -{ - - /* - * We aren't adding any more locals or linenumbers to this function. - * Free any spare memory that we might have allocated. - */ - if( nh == NULL ) - { - return TRUE; - } - - if( nh->n_locals != nh->locals_alloc ) - { - nh->locals_alloc = nh->n_locals; - nh->local_vars = DBG_realloc(nh->local_vars, - nh->locals_alloc * sizeof(WineLocals)); - } - - if( nh->n_lines != nh->lines_alloc ) - { - nh->lines_alloc = nh->n_lines; - nh->linetab = DBG_realloc(nh->linetab, - nh->lines_alloc * sizeof(WineLineNo)); - } - - return TRUE; -} - -/*********************************************************************** - * DEBUG_GetSymbolValue - * - * Get the address of a named symbol. - * Return values: - * gsv_found: if the symbol is found - * gsv_unknown: if the symbol isn't found - * gsv_aborted: some error occurred (likely, many symbols of same name exist, - * and user didn't pick one of them) - */ -static int DEBUG_GSV_Helper(const char* name, const int lineno, - DBG_VALUE* value, int num, int bp_flag) -{ - struct name_hash* nh; - int i = 0; - DBG_ADDR addr; - - for (nh = name_hash_table[name_hash(name)]; nh; nh = nh->next) - { - if ((nh->flags & SYM_INVALID) != 0) continue; - if (!strcmp(nh->name, name) && DEBUG_GetLineNumberAddr( nh, lineno, &addr, bp_flag )) - { - if (i >= num) return num + 1; - value[i].addr = addr; - value[i].type = nh->value.type; - value[i].cookie = nh->value.cookie; - i++; - } - } - return i; -} - -enum get_sym_val DEBUG_GetSymbolValue( const char * name, - const int lineno, - DBG_VALUE *rtn, int bp_flag ) -{ -#define NUMDBGV 100 - /* FIXME: NUMDBGV should be made variable */ - DBG_VALUE value[NUMDBGV]; - DBG_VALUE vtmp; - int num, i, local = -1; - - num = DEBUG_GSV_Helper(name, lineno, value, NUMDBGV, bp_flag); - if (!num && (name[0] != '_')) - { - char buffer[512]; - - if (strlen(name) < sizeof(buffer) - 2) /* one for '_', one for '\0' */ - { - buffer[0] = '_'; - strcpy(buffer + 1, name); - num = DEBUG_GSV_Helper(buffer, lineno, value, NUMDBGV, bp_flag); - } - else WINE_WARN("Way too long symbol (%s)\n", name); - } - - /* now get the local symbols if any */ - if (DEBUG_GetStackSymbolValue(name, &vtmp) && num < NUMDBGV) - { - value[num] = vtmp; - local = num; - num++; - } - - if (num == 0) { - return gsv_unknown; - } else if (!DEBUG_InteractiveP || num == 1) { - i = 0; - } else { - char buffer[256]; - - if (num == NUMDBGV+1) { - DEBUG_Printf("Too many addresses for symbol '%s', limiting the first %d\n", name, NUMDBGV); - num = NUMDBGV; - } - DEBUG_Printf("Many symbols with name '%s', choose the one you want ( to abort):\n", name); - for (i = 0; i < num; i++) { - DEBUG_Printf("[%d]: ", i + 1); - if (i == local) { - struct name_hash*func; - unsigned int ebp; - unsigned int eip; - - if (DEBUG_GetCurrentFrame(&func, &eip, &ebp)) - DEBUG_Printf("local variable of %s in %s\n", func->name, func->sourcefile); - else - DEBUG_Printf("local variable\n"); - } else { - DEBUG_PrintAddress( &value[i].addr, DEBUG_GetSelectorType(value[i].addr.seg), TRUE); - DEBUG_Printf("\n"); - } - } - do { - i = 0; - if (DEBUG_ReadLine("=> ", buffer, sizeof(buffer))) - { - if (buffer[0] == '\0') return gsv_aborted; - i = atoi(buffer); - if (i < 1 || i > num) - DEBUG_Printf("Invalid choice %d\n", i); - } - } while (i < 1 || i > num); - - /* The array is 0-based, but the choices are 1..n, so we have to subtract one before returning. */ - i--; - } - *rtn = value[i]; - return gsv_found; -} - -/*********************************************************************** - * DEBUG_GetLineNumberAddr - * - * Get the address of a named symbol. - */ -BOOL DEBUG_GetLineNumberAddr( const struct name_hash * nh, const int lineno, - DBG_ADDR *addr, int bp_flag ) -{ - int i; - - if( lineno == -1 ) - { - *addr = nh->value.addr; - if( bp_flag ) - { - addr->off += nh->breakpoint_offset; - } - } - else - { - /* - * Search for the specific line number. If we don't find it, - * then return FALSE. - */ - if( nh->linetab == NULL ) - { - return FALSE; - } - - for(i=0; i < nh->n_lines; i++ ) - { - if( nh->linetab[i].line_number == lineno ) - { - *addr = nh->linetab[i].pc_offset; - return TRUE; - } - } - - /* - * This specific line number not found. - */ - return FALSE; - } - - return TRUE; -} - -/*********************************************************************** - * DEBUG_FindNearestSymbol - * - * Find the symbol nearest to a given address. - * If ebp is specified as non-zero, it means we should dump the argument - * list into the string we return as well. - */ -const char * DEBUG_FindNearestSymbol( const DBG_ADDR *addr, int flag, - struct name_hash ** rtn, - unsigned int ebp, - struct list_id * source) -{ - static char name_buffer[MAX_PATH + 256]; - static char arglist[1024]; - static char argtmp[256]; - struct name_hash * nearest = NULL; - int mid, high, low; - unsigned int * ptr; - int lineno; - const char * lineinfo; - char *sourcefile; - int i; - char linebuff[16]; - unsigned val; - DBG_MODULE* module; - char modbuf[256]; - - if( rtn != NULL ) - { - *rtn = NULL; - } - - if( source != NULL ) - { - source->sourcefile = NULL; - source->line = -1; - } - - if( sortlist_valid == FALSE ) - { - DEBUG_ResortSymbols(); - } - - if( sortlist_valid == FALSE ) - { - return NULL; - } - - /* - * FIXME - use the binary search that we added to - * the function DEBUG_CheckLinenoStatus. Better yet, we should - * probably keep some notion of the current function so we don't - * have to search every time. - */ - /* - * Binary search to find closest symbol. - */ - low = 0; - high = sorttab_nsym; - if( addr_sorttab[0]->value.addr.seg > addr->seg - || ( addr_sorttab[0]->value.addr.seg == addr->seg - && addr_sorttab[0]->value.addr.off > addr->off) ) - { - nearest = NULL; - } - else if( addr_sorttab[high - 1]->value.addr.seg < addr->seg - || ( addr_sorttab[high - 1]->value.addr.seg == addr->seg - && addr_sorttab[high - 1]->value.addr.off < addr->off) ) - { - nearest = addr_sorttab[high - 1]; - } - else - { - while(1==1) - { - mid = (high + low)/2; - if( mid == low ) - { - /* - * See if there are any other entries that might also - * have the same address, and would also have a line - * number table. - */ - if( mid > 0 && addr_sorttab[mid]->linetab == NULL ) - { - if( (addr_sorttab[mid - 1]->value.addr.seg == - addr_sorttab[mid]->value.addr.seg) - && (addr_sorttab[mid - 1]->value.addr.off == - addr_sorttab[mid]->value.addr.off) - && (addr_sorttab[mid - 1]->linetab != NULL) ) - { - mid--; - } - } - - if( (mid < sorttab_nsym - 1) - && (addr_sorttab[mid]->linetab == NULL) ) - { - if( (addr_sorttab[mid + 1]->value.addr.seg == - addr_sorttab[mid]->value.addr.seg) - && (addr_sorttab[mid + 1]->value.addr.off == - addr_sorttab[mid]->value.addr.off) - && (addr_sorttab[mid + 1]->linetab != NULL) ) - { - mid++; - } - } - nearest = addr_sorttab[mid]; - WINE_TRACE_(winedbg_sym)( - "Found %lx:%lx when looking for %lx:%lx %p %s\n", - addr_sorttab[mid ]->value.addr.seg, - addr_sorttab[mid ]->value.addr.off, - addr->seg, addr->off, - addr_sorttab[mid ]->linetab, - addr_sorttab[mid ]->name); - break; - } - if( (addr_sorttab[mid]->value.addr.seg < addr->seg) - || ( addr_sorttab[mid]->value.addr.seg == addr->seg - && addr_sorttab[mid]->value.addr.off <= addr->off) ) - { - low = mid; - } - else - { - high = mid; - } - } - } - - if (!nearest) return NULL; - - if( rtn != NULL ) - { - *rtn = nearest; - } - - /* - * Fill in the relevant bits to the structure so that we can - * locate the source and line for this bit of code. - */ - if( source != NULL ) - { - source->sourcefile = nearest->sourcefile; - if( nearest->linetab == NULL ) - { - source->line = -1; - } - else - { - source->line = nearest->linetab[0].line_number; - } - } - - lineinfo = ""; - lineno = -1; - - /* - * Prepare to display the argument list. If ebp is specified, it is - * the framepointer for the function in question. If not specified, - * we don't want the arglist. - */ - memset(arglist, '\0', sizeof(arglist)); - if( ebp != 0 ) - { - for(i=0; i < nearest->n_locals; i++ ) - { - /* - * If this is a register (offset == 0) or a local - * variable, we don't want to know about it. - */ - if( nearest->local_vars[i].offset <= 0 ) - { - continue; - } - - ptr = (unsigned int *) (ebp + nearest->local_vars[i].offset); - if( arglist[0] == '\0' ) - { - arglist[0] = '('; - } - else - { - strcat(arglist, ", "); - } - DEBUG_READ_MEM_VERBOSE(ptr, &val, sizeof(val)); - snprintf(argtmp, sizeof(argtmp), "%s=0x%x", nearest->local_vars[i].name, val); - - strcat(arglist, argtmp); - } - if( arglist[0] == '(' ) - { - strcat(arglist, ")"); - } - } - - module = DEBUG_FindModuleByAddr((void*)DEBUG_ToLinear(addr), DMT_UNKNOWN); - if (module) { - const char *p, *name = module->module_name; - if ((p = strrchr(name, '/'))) name = p + 1; - if ((p = strrchr(name, '\\'))) name = p + 1; - snprintf( modbuf, sizeof(modbuf), " in %s", name); - } - else - modbuf[0] = '\0'; - - if( (nearest->sourcefile != NULL) && (flag == TRUE) - && (addr->off - nearest->value.addr.off < 0x100000) ) - { - - /* - * Try and find the nearest line number to the current offset. - */ - if( nearest->linetab != NULL ) - { - low = 0; - high = nearest->n_lines; - while ((high - low) > 1) - { - mid = (high + low) / 2; - if (addr->off < nearest->linetab[mid].pc_offset.off) - high = mid; - else - low = mid; - } - lineno = nearest->linetab[low].line_number; - } - - if( lineno != -1 ) - { - snprintf(linebuff, sizeof(linebuff), ":%d", lineno); - lineinfo = linebuff; - if( source != NULL ) - { - source->line = lineno; - } - } - - /* Remove the path from the file name */ - sourcefile = strrchr( nearest->sourcefile, '/' ); - if (!sourcefile) sourcefile = nearest->sourcefile; - else sourcefile++; - - if (addr->off == nearest->value.addr.off) - snprintf( name_buffer, sizeof(name_buffer), "%s%s [%s%s]%s", nearest->name, - arglist, sourcefile, lineinfo, modbuf); - else - snprintf( name_buffer, sizeof(name_buffer), "%s+0x%lx%s [%s%s]%s", nearest->name, - addr->off - nearest->value.addr.off, - arglist, sourcefile, lineinfo, modbuf ); - } - else - { - if (addr->off == nearest->value.addr.off) - snprintf( name_buffer, sizeof(name_buffer), "%s%s%s", nearest->name, arglist, modbuf); - else { - if (addr->seg && (nearest->value.addr.seg!=addr->seg)) - return NULL; - else - snprintf( name_buffer, sizeof(name_buffer), "%s+0x%lx%s%s", nearest->name, - addr->off - nearest->value.addr.off, arglist, modbuf); - } - } - return name_buffer; -} - - -/*********************************************************************** - * DEBUG_ReadSymbolTable - * - * Read a symbol file into the hash table. - */ -void DEBUG_ReadSymbolTable( const char* filename, unsigned long offset ) -{ - FILE * symbolfile; - DBG_VALUE value; - 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; - } - - DEBUG_Printf("Reading symbols from file %s\n", filename); - - value.type = NULL; - value.addr.seg = 0; - value.addr.off = 0; - value.cookie = DV_TARGET; - - while (1) - { - fgets( buffer, sizeof(buffer), symbolfile ); - if (feof(symbolfile)) break; - - /* Strip any text after a # sign (i.e. comments) */ - cpnt = buffer; - while (*cpnt) - if(*cpnt++ == '#') { *cpnt = 0; break; } - - /* Quietly ignore any lines that have just whitespace */ - cpnt = buffer; - while(*cpnt) - { - if(*cpnt != ' ' && *cpnt != '\t') break; - cpnt++; - } - if (!(*cpnt) || *cpnt == '\n') continue; - - if (sscanf(buffer, "%lx %c %s", &value.addr.off, &type, name) == 3) - { - if (value.addr.off + offset < value.addr.off) - WINE_WARN("Address wrap around\n"); - value.addr.off += offset; - DEBUG_AddSymbol( name, &value, NULL, SYM_WINE ); - } - } - fclose(symbolfile); -} - - -void -DEBUG_AddLineNumber( struct name_hash * func, int line_num, - unsigned long offset ) -{ - if( func == NULL ) - { - return; - } - - if( func->n_lines + 1 >= func->lines_alloc ) - { - func->lines_alloc += 64; - func->linetab = DBG_realloc(func->linetab, - func->lines_alloc * sizeof(WineLineNo)); - } - - func->linetab[func->n_lines].line_number = line_num; - func->linetab[func->n_lines].pc_offset.seg = func->value.addr.seg; - func->linetab[func->n_lines].pc_offset.off = func->value.addr.off + offset; - func->n_lines++; -} - - -struct wine_locals * -DEBUG_AddLocal( struct name_hash * func, int regno, - int offset, - int pc_start, - int pc_end, - char * name) -{ - if( func == NULL ) - { - return NULL; - } - - if( func->n_locals + 1 >= func->locals_alloc ) - { - func->locals_alloc += 32; - func->local_vars = DBG_realloc(func->local_vars, - func->locals_alloc * sizeof(WineLocals)); - } - - func->local_vars[func->n_locals].regno = regno; - func->local_vars[func->n_locals].offset = offset; - func->local_vars[func->n_locals].pc_start = pc_start; - func->local_vars[func->n_locals].pc_end = pc_end; - func->local_vars[func->n_locals].name = DBG_strdup(name); - func->local_vars[func->n_locals].type = NULL; - func->n_locals++; - - return &func->local_vars[func->n_locals - 1]; -} - -void -DEBUG_DumpHashInfo(void) -{ - int i; - int depth; - struct name_hash *nh; - - /* - * Utility function to dump stats about the hash table. - */ - for(i=0; inext) - { - depth++; - } - DEBUG_Printf("Bucket %d: %d\n", i, depth); - } -} - -/*********************************************************************** - * DEBUG_CheckLinenoStatus - * - * Find the symbol nearest to a given address. - * If ebp is specified as non-zero, it means we should dump the argument - * list into the string we return as well. - */ -int DEBUG_CheckLinenoStatus( const DBG_ADDR *addr) -{ - struct name_hash * nearest = NULL; - int mid, high, low; - - if( sortlist_valid == FALSE ) - { - DEBUG_ResortSymbols(); - } - - /* - * Binary search to find closest symbol. - */ - low = 0; - high = sorttab_nsym; - if( addr_sorttab[0]->value.addr.seg > addr->seg - || ( addr_sorttab[0]->value.addr.seg == addr->seg - && addr_sorttab[0]->value.addr.off > addr->off) ) - { - nearest = NULL; - } - else if( addr_sorttab[high - 1]->value.addr.seg < addr->seg - || ( addr_sorttab[high - 1]->value.addr.seg == addr->seg - && addr_sorttab[high - 1]->value.addr.off < addr->off) ) - { - nearest = addr_sorttab[high - 1]; - } - else - { - while(1==1) - { - mid = (high + low)/2; - if( mid == low ) - { - /* - * See if there are any other entries that might also - * have the same address, and would also have a line - * number table. - */ - if( mid > 0 && addr_sorttab[mid]->linetab == NULL ) - { - if( (addr_sorttab[mid - 1]->value.addr.seg == - addr_sorttab[mid]->value.addr.seg) - && (addr_sorttab[mid - 1]->value.addr.off == - addr_sorttab[mid]->value.addr.off) - && (addr_sorttab[mid - 1]->linetab != NULL) ) - { - mid--; - } - } - - if( (mid < sorttab_nsym - 1) - && (addr_sorttab[mid]->linetab == NULL) ) - { - if( (addr_sorttab[mid + 1]->value.addr.seg == - addr_sorttab[mid]->value.addr.seg) - && (addr_sorttab[mid + 1]->value.addr.off == - addr_sorttab[mid]->value.addr.off) - && (addr_sorttab[mid + 1]->linetab != NULL) ) - { - mid++; - } - } - nearest = addr_sorttab[mid]; - WINE_TRACE_(winedbg_sym)( - "Found %lx:%lx when looking for %lx:%lx %p %s\n", - addr_sorttab[mid ]->value.addr.seg, - addr_sorttab[mid ]->value.addr.off, - addr->seg, addr->off, - addr_sorttab[mid ]->linetab, - addr_sorttab[mid ]->name); - break; - } - if( (addr_sorttab[mid]->value.addr.seg < addr->seg) - || ( addr_sorttab[mid]->value.addr.seg == addr->seg - && addr_sorttab[mid]->value.addr.off <= addr->off) ) - { - low = mid; - } - else - { - high = mid; - } - } - } - - if (!nearest) return FUNC_HAS_NO_LINES; - - if( nearest->flags & SYM_STEP_THROUGH ) - { - /* - * This will cause us to keep single stepping until - * we get to the other side somewhere. - */ - return NOT_ON_LINENUMBER; - } - - if( (nearest->flags & SYM_TRAMPOLINE) ) - { - /* - * This will cause us to keep single stepping until - * we get to the other side somewhere. - */ - return FUNC_IS_TRAMPOLINE; - } - - if( nearest->linetab == NULL ) - { - return FUNC_HAS_NO_LINES; - } - - - /* - * We never want to stop on the first instruction of a function - * even if it has it's own linenumber. Let the thing keep running - * until it gets past the function prologue. We only do this if there - * is more than one line number for the function, of course. - */ - if( nearest->value.addr.off == addr->off && nearest->n_lines > 1 ) - { - return NOT_ON_LINENUMBER; - } - - if( (nearest->sourcefile != NULL) - && (addr->off - nearest->value.addr.off < 0x100000) ) - { - low = 0; - high = nearest->n_lines; - while ((high - low) > 1) - { - mid = (high + low) / 2; - if (addr->off < nearest->linetab[mid].pc_offset.off) high = mid; - else low = mid; - } - if (addr->off == nearest->linetab[low].pc_offset.off) - return AT_LINENUMBER; - else - return NOT_ON_LINENUMBER; - } - - return FUNC_HAS_NO_LINES; -} - -/*********************************************************************** - * DEBUG_GetFuncInfo - * - * Find the symbol nearest to a given address. - * Returns sourcefile name and line number in a format that the listing - * handler can deal with. - */ -void -DEBUG_GetFuncInfo( struct list_id * ret, const char * filename, - const char * name) -{ - char buffer[256]; - char * pnt; - struct name_hash *nh; - - for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next) - { - if( filename != NULL ) - { - - if( nh->sourcefile == NULL ) - { - continue; - } - - pnt = strrchr(nh->sourcefile, '/'); - if( strcmp(nh->sourcefile, filename) != 0 - && (pnt == NULL || strcmp(pnt + 1, filename) != 0) ) - { - continue; - } - } - if (!strcmp(nh->name, name)) break; - } - - if (!nh && (name[0] != '_')) - { - buffer[0] = '_'; - strcpy(buffer+1, name); - for(nh = name_hash_table[name_hash(buffer)]; nh; nh = nh->next) - { - if( filename != NULL ) - { - if( nh->sourcefile == NULL ) - { - continue; - } - - pnt = strrchr(nh->sourcefile, '/'); - if( strcmp(nh->sourcefile, filename) != 0 - && (pnt == NULL || strcmp(pnt + 1, filename) != 0) ) - { - continue; - } - } - if (!strcmp(nh->name, buffer)) break; - } - } - - if( !nh ) - { - if( filename != NULL ) - { - DEBUG_Printf("No such function %s in %s\n", name, filename); - } - else - { - DEBUG_Printf("No such function %s\n", name); - } - ret->sourcefile = NULL; - ret->line = -1; - return; - } - - ret->sourcefile = nh->sourcefile; - - /* - * Search for the specific line number. If we don't find it, - * then return FALSE. - */ - if( nh->linetab == NULL ) - { - ret->line = -1; - } - else - { - ret->line = nh->linetab[0].line_number; - } -} - -/*********************************************************************** - * DEBUG_GetStackSymbolValue - * - * Get the address of a named symbol from the current stack frame. - */ -static -BOOL DEBUG_GetStackSymbolValue( const char * name, DBG_VALUE *value ) -{ - struct name_hash * curr_func; - unsigned int ebp; - unsigned int eip; - int i; - - if( DEBUG_GetCurrentFrame(&curr_func, &eip, &ebp) == FALSE ) - { - return FALSE; - } - - for(i=0; i < curr_func->n_locals; i++ ) - { - /* - * Test the range of validity of the local variable. This - * comes up with RBRAC/LBRAC stabs in particular. - */ - if( (curr_func->local_vars[i].pc_start != 0) - && ((eip - curr_func->value.addr.off) - < curr_func->local_vars[i].pc_start) ) - { - continue; - } - - if( (curr_func->local_vars[i].pc_end != 0) - && ((eip - curr_func->value.addr.off) - > curr_func->local_vars[i].pc_end) ) - { - continue; - } - - if( strcmp(name, curr_func->local_vars[i].name) == 0 ) - { - /* - * OK, we found it. Now figure out what to do with this. - */ - if( curr_func->local_vars[i].regno != 0 ) - { - /* - * Register variable. Point to DEBUG_context field. - */ - assert(curr_func->local_vars[i].regno - 1 < sizeof(reg_ofs)/sizeof(reg_ofs[0])); - value->addr.off = ((DWORD)&DEBUG_context) + - reg_ofs[curr_func->local_vars[i].regno - 1]; - value->cookie = DV_HOST; - } - else - { - value->addr.off = ebp + curr_func->local_vars[i].offset; - value->cookie = DV_TARGET; - } - value->addr.seg = 0; - value->type = curr_func->local_vars[i].type; - - return TRUE; - } - } - - return FALSE; -} - -int -DEBUG_InfoLocals(void) -{ - struct name_hash * curr_func; - unsigned int ebp; - unsigned int eip; - int i; - unsigned int * ptr; - unsigned int val; - - if( DEBUG_GetCurrentFrame(&curr_func, &eip, &ebp) == FALSE ) - { - return FALSE; - } - - DEBUG_Printf("%s:\n", curr_func->name); - - for(i=0; i < curr_func->n_locals; i++ ) - { - /* - * Test the range of validity of the local variable. This - * comes up with RBRAC/LBRAC stabs in particular. - */ - if( (curr_func->local_vars[i].pc_start != 0) - && ((eip - curr_func->value.addr.off) - < curr_func->local_vars[i].pc_start) ) - { - continue; - } - - if( (curr_func->local_vars[i].pc_end != 0) - && ((eip - curr_func->value.addr.off) - > curr_func->local_vars[i].pc_end) ) - { - continue; - } - - DEBUG_PrintTypeCast(curr_func->local_vars[i].type); - - if( curr_func->local_vars[i].regno != 0 ) - { - ptr = (unsigned int *)(((DWORD)&DEBUG_context) - + reg_ofs[curr_func->local_vars[i].regno - 1]); - DEBUG_Printf(" %s (optimized into register $%s) == 0x%8.8x\n", - curr_func->local_vars[i].name, - reg_name[curr_func->local_vars[i].regno - 1], - *ptr); - } - else - { - DEBUG_READ_MEM_VERBOSE((void*)(ebp + curr_func->local_vars[i].offset), - &val, sizeof(val)); - DEBUG_Printf(" %s == 0x%8.8x\n", - curr_func->local_vars[i].name, val); - } - } - - return TRUE; -} - -int -DEBUG_SetSymbolSize(struct name_hash * sym, unsigned int len) -{ - sym->symbol_size = len; - - return TRUE; -} - -int -DEBUG_SetSymbolBPOff(struct name_hash * sym, unsigned int off) -{ - sym->breakpoint_offset = off; - - return TRUE; -} - -int -DEBUG_GetSymbolAddr(struct name_hash * sym, DBG_ADDR * addr) -{ - - *addr = sym->value.addr; - - return TRUE; -} - -int DEBUG_SetLocalSymbolType(struct wine_locals * sym, struct datatype * type) -{ - sym->type = type; - - return TRUE; -} - -const char *DEBUG_GetSymbolName(const struct name_hash * sym) -{ - return sym->name; -} - -#ifdef HAVE_REGEX_H - -static int cmp_sym_by_name(const void * p1, const void * p2) -{ - struct name_hash ** name1 = (struct name_hash **) p1; - struct name_hash ** name2 = (struct name_hash **) p2; - - return strcmp( (*name1)->name, (*name2)->name ); -} - -#include - -void DEBUG_InfoSymbols(const char* str) -{ - int i; - struct name_hash* nh; - struct name_hash** array = NULL; - unsigned num_used_array = 0; - unsigned num_alloc_array = 0; - const char* name; - enum dbg_mode mode; - regex_t preg; - - regcomp(&preg, str, REG_NOSUB); - - /* grab all symbols */ - for (i = 0; i < NR_NAME_HASH; i++) - { - for (nh = name_hash_table[i]; nh; nh = nh->next) - { - if (regexec(&preg, nh->name, 0, NULL, 0) == 0) - { - if (num_used_array == num_alloc_array) - { - int size = sizeof(*array) * (num_alloc_array += 32); - if (!array) array = HeapAlloc(GetProcessHeap(), 0, size); - else array = HeapReAlloc(GetProcessHeap(), 0, array, size); - if (!array) return; - } - array[num_used_array++] = nh; - } - } - } - regfree(&preg); - - /* now sort them by alphabetical order */ - qsort(array, num_used_array, sizeof(*array), cmp_sym_by_name); - - /* and display them */ - for (i = 0; i < num_used_array; i++) - { - mode = DEBUG_GetSelectorType(array[i]->value.addr.seg); - name = DEBUG_FindNearestSymbol( &array[i]->value.addr, TRUE, - NULL, 0, NULL ); - - if (mode != MODE_32) - DEBUG_Printf("%04lx:%04lx :", - array[i]->value.addr.seg & 0xFFFF, - array[i]->value.addr.off); - else - DEBUG_Printf("%08lx :", array[i]->value.addr.off); - if (array[i]->value.type) - { - DEBUG_Printf(" ("); - DEBUG_PrintTypeCast(array[i]->value.type); - DEBUG_Printf(")"); - } - if (name) DEBUG_Printf(" %s\n", name); - } - HeapFree(GetProcessHeap(), 0, array); -} - -#else /* HAVE_REGEX_H */ - -void DEBUG_InfoSymbols(const char* str) -{ - WINE_FIXME("Requires regex support\n"); -} - -#endif /* HAVE_REGEX_H */ diff --git a/programs/winedbg/info.c b/programs/winedbg/info.c index 68248fb77b5..8e9105f49c7 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -22,485 +22,464 @@ #include "config.h" #include +#include #include #include -#include "windef.h" -#include "winbase.h" +#include "debugger.h" #include "wingdi.h" #include "winuser.h" #include "tlhelp32.h" -#include "debugger.h" -#include "expr.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(winedbg); /*********************************************************************** - * DEBUG_PrintBasic - * - * Implementation of the 'print' command. - */ -void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format ) -{ - const char * default_format; - long long int res; - - assert(value->cookie == DV_TARGET || value->cookie == DV_HOST); - if (value->type == NULL) - { - DEBUG_Printf("Unable to evaluate expression\n"); - return; - } - - default_format = NULL; - res = DEBUG_GetExprValue(value, &default_format); - - switch (format) - { - case 'x': - if (value->addr.seg) - { - DEBUG_nchar += DEBUG_Printf("0x%04lx", (long unsigned int)res); - } - else - { - DEBUG_nchar += DEBUG_Printf("0x%08lx", (long unsigned int)res); - } - break; - - case 'd': - DEBUG_nchar += DEBUG_Printf("%ld\n", (long int)res); - break; - - case 'c': - DEBUG_nchar += DEBUG_Printf("%d = '%c'", - (char)(res & 0xff), (char)(res & 0xff)); - break; - - case 'u': - { - WCHAR wch = (WCHAR)(res & 0xFFFF); - DEBUG_nchar += DEBUG_Printf("%d = '", (unsigned)(res & 0xffff)); - DEBUG_OutputW(&wch, 1); - DEBUG_Printf("'"); - } - break; - - case 'i': - case 's': - case 'w': - case 'b': - DEBUG_Printf("Format specifier '%c' is meaningless in 'print' command\n", format); - case 0: - if (default_format == NULL) break; - - if (strstr(default_format, "%S") != NULL) - { - const char* ptr; - int state = 0; - - /* FIXME: simplistic implementation for default_format being - * foo%Sbar => will print foo, then string then bar - */ - for (ptr = default_format; *ptr; ptr++) - { - if (*ptr == '%') - { - state++; - } - else if (state == 1) - { - if (*ptr == 'S') - { - DBG_ADDR addr; - - addr.seg = 0; - addr.off = (long)res; - DEBUG_nchar += DEBUG_PrintStringA(&addr, -1); - } - else - { - /* shouldn't happen */ - DEBUG_Printf("%%%c", *ptr); - DEBUG_nchar += 2; - } - state = 0; - } - else - { - DEBUG_OutputA(ptr, 1); - DEBUG_nchar++; - } - } - } - else if (strcmp(default_format, "%B") == 0) - { - DEBUG_nchar += DEBUG_Printf("%s", res ? "true" : "false"); - } - else if (strcmp(default_format, "%R") == 0) - { - if (value->cookie == DV_HOST) - DEBUG_InfoRegisters((CONTEXT*)value->addr.off); - else - DEBUG_Printf("NIY: info on register struct in debuggee address space\n"); - DEBUG_nchar = 0; - } - else - { - DEBUG_nchar += DEBUG_Printf(default_format, res); - } - break; - } -} - - -/*********************************************************************** - * DEBUG_PrintAddress - * - * Print an 16- or 32-bit address, with the nearest symbol if any. - */ -struct symbol_info -DEBUG_PrintAddress( const DBG_ADDR *addr, enum dbg_mode mode, int flag ) -{ - struct symbol_info rtn; - - const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0, - &rtn.list ); - - if (addr->seg) DEBUG_Printf("0x%04lx:", addr->seg & 0xFFFF); - if (mode != MODE_32) DEBUG_Printf("0x%04lx", addr->off); - else DEBUG_Printf("0x%08lx", addr->off); - if (name) DEBUG_Printf(" (%s)", name); - return rtn; -} -/*********************************************************************** - * DEBUG_PrintAddressAndArgs - * - * Print an 16- or 32-bit address, with the nearest symbol if any. - * Similar to DEBUG_PrintAddress, but we print the arguments to - * each function (if known). This is useful in a backtrace. - */ -struct symbol_info -DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, enum dbg_mode mode, - unsigned int ebp, int flag ) -{ - struct symbol_info rtn; - - const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp, - &rtn.list ); - - if (addr->seg) DEBUG_Printf("0x%04lx:", addr->seg); - if (mode != MODE_32) DEBUG_Printf("0x%04lx", addr->off); - else DEBUG_Printf("0x%08lx", addr->off); - if (name) DEBUG_Printf(" (%s)", name); - - return rtn; -} - - -/*********************************************************************** - * DEBUG_Help + * print_help * * Implementation of the 'help' command. */ -void DEBUG_Help(void) +void print_help(void) { int i = 0; static const char * const helptext[] = -{ -"The commands accepted by the Wine debugger are a reasonable", -"subset of the commands that gdb accepts.", -"The commands currently are:", -" help quit", -" break [*] watch *", -" delete break bpnum disable bpnum", -" enable bpnum condition []", -" finish cont [N]", -" step [N] next [N]", -" stepi [N] nexti [N]", -" x print ", -" display undisplay ", -" local display delete display ", -" enable display disable display ", -" bt frame ", -" up down", -" list disassemble [][,]", -" show dir dir ", -" set = set * = ", -" mode [16,32,vm86] pass", -" whatis walk [wnd,class,module,maps,", -" info (see 'help info' for options) process,thread,exception]", + { + "The commands accepted by the Wine debugger are a reasonable", + "subset of the commands that gdb accepts.", + "The commands currently are:", + " help quit", + " break [*] watch *", + " delete break bpnum disable bpnum", + " enable bpnum condition []", + " finish cont [N]", + " step [N] next [N]", + " stepi [N] nexti [N]", + " x print ", + " display undisplay ", + " local display delete display ", + " enable display disable display ", + " bt frame ", + " up down", + " list disassemble [][,]", + " show dir dir ", + " set = set * = ", + " mode [16,32,vm86] pass", + " whatis info (see 'help info' for options)", -"The 'x' command accepts repeat counts and formats (including 'i') in the", -"same way that gdb does.\n", + "The 'x' command accepts repeat counts and formats (including 'i') in the", + "same way that gdb does.\n", -" The following are examples of legal expressions:", -" $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)", -" Also, a nm format symbol table can be read from a file using the", -" symbolfile command.", /* Symbols can also be defined individually with", -" the define command.", */ -"", -NULL -}; + "The following are examples of legal expressions:", + " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)", + " Also, a nm format symbol table can be read from a file using the", + " symbolfile command.", /* Symbols can also be defined individually with", + " the define command.", */ + "", + NULL + }; - while(helptext[i]) DEBUG_Printf("%s\n", helptext[i++]); + while (helptext[i]) dbg_printf("%s\n", helptext[i++]); } /*********************************************************************** - * DEBUG_HelpInfo + * info_help * * Implementation of the 'help info' command. */ -void DEBUG_HelpInfo(void) +void info_help(void) { int i = 0; static const char * const infotext[] = + { + "The info commands allow you to get assorted bits of interesting stuff", + "to be displayed. The options are:", + " info break Displays information about breakpoints", + " info class Displays information about window class ", + " info display Shows auto-display expressions in use", + " info except Shows exception handler chain (in a given process)", + " info locals Displays values of all local vars for current frame", + " info maps Shows virtual mappings (in a given process)", + " info process Shows all running processes", + " info reg Displays values in all registers at top of stack", + " info segments Displays information about all known segments", + " info share Displays all loaded modules", + " info share Displays internal module state", + " info stack Dumps information about top of stack", + " info symbol Displays information about a given symbol", + " info thread Shows all running threads", + " info wnd Displays internal window state", + "", + NULL + }; + + while (infotext[i]) dbg_printf("%s\n", infotext[i++]); +} + +static const char* get_symtype_str(SYM_TYPE st) { -"The info commands allow you to get assorted bits of interesting stuff", -"to be displayed. The options are:", -" info break Dumps information about breakpoints", -" info display Shows auto-display expressions in use", -" info locals Displays values of all local vars for current frame", -" info module Displays internal module state", -" info reg Displays values in all registers at top of stack", -" info segments Dumps information about all known segments", -" info share Dumps information about shared libraries", -" info stack Dumps information about top of stack", -" info wnd Displays internal window state", -"", -NULL + switch (st) + { + default: + case SymNone: return "--none--"; + case SymCoff: return "COFF"; + case SymCv: return "CodeView"; + case SymPdb: return "PDB"; + case SymExport: return "Export"; + case SymDeferred: return "Deferred"; + case SymSym: return "Sym"; + case SymDia: return "DIA"; + } +} + +struct info_module +{ + IMAGEHLP_MODULE* mi; + unsigned num_alloc; + unsigned num_used; }; - while(infotext[i]) DEBUG_Printf("%s\n", infotext[i++]); +static void module_print_info(const IMAGEHLP_MODULE* mi) +{ + dbg_printf("0x%08lx-%08lx\t%-16s%s\n", + mi->BaseOfImage, mi->BaseOfImage + mi->ImageSize, + get_symtype_str(mi->SymType), mi->ModuleName); } -/* FIXME: merge InfoClass and InfoClass2 */ -void DEBUG_InfoClass(const char* name) +static int module_compare(const void* p1, const void* p2) { - WNDCLASSEXA wca; - - if (!GetClassInfoEx(0, name, &wca)) { - DEBUG_Printf("Cannot find class '%s'\n", name); - return; - } - - DEBUG_Printf("Class '%s':\n", name); - DEBUG_Printf("style=%08x wndProc=%08lx\n" - "inst=%p icon=%p cursor=%p bkgnd=%p\n" - "clsExtra=%d winExtra=%d\n", - wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance, - wca.hIcon, wca.hCursor, wca.hbrBackground, - wca.cbClsExtra, wca.cbWndExtra); - - /* FIXME: - * + print #windows (or even list of windows...) - * + print extra bytes => this requires a window handle on this very class... - */ + return (char*)(((const IMAGEHLP_MODULE*)p1)->BaseOfImage) - + (char*)(((const IMAGEHLP_MODULE*)p2)->BaseOfImage); } -static void DEBUG_InfoClass2(HWND hWnd, const char* name) +static inline BOOL module_is_container(const IMAGEHLP_MODULE* wmod_cntnr, + const IMAGEHLP_MODULE* wmod_child) { - WNDCLASSEXA wca; + return wmod_cntnr->BaseOfImage <= wmod_child->BaseOfImage && + (DWORD)wmod_cntnr->BaseOfImage + wmod_cntnr->ImageSize >= + (DWORD)wmod_child->BaseOfImage + wmod_child->ImageSize; +} - if (!GetClassInfoEx((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), name, &wca)) { - DEBUG_Printf("Cannot find class '%s'\n", name); - return; - } +static BOOL CALLBACK info_mod_cb(PSTR mod_name, DWORD base, void* ctx) +{ + struct info_module* im = (struct info_module*)ctx; - DEBUG_Printf("Class '%s':\n", name); - DEBUG_Printf("style=%08x wndProc=%08lx\n" - "inst=%p icon=%p cursor=%p bkgnd=%p\n" - "clsExtra=%d winExtra=%d\n", - wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance, - wca.hIcon, wca.hCursor, wca.hbrBackground, - wca.cbClsExtra, wca.cbWndExtra); - - if (wca.cbClsExtra) { - int i; - WORD w; - - DEBUG_Printf("Extra bytes:"); - for (i = 0; i < wca.cbClsExtra / 2; i++) { - w = GetClassWord(hWnd, i * 2); - /* FIXME: depends on i386 endian-ity */ - DEBUG_Printf(" %02x %02x", HIBYTE(w), LOBYTE(w)); - } - DEBUG_Printf("\n"); + if (im->num_used + 1 > im->num_alloc) + { + im->num_alloc += 16; + im->mi = dbg_heap_realloc(im->mi, im->num_alloc * sizeof(*im->mi)); } - DEBUG_Printf("\n"); + im->mi[im->num_used].SizeOfStruct = sizeof(im->mi[im->num_used]); + if (SymGetModuleInfo(dbg_curr_process->handle, base, &im->mi[im->num_used])) + { + module_print_info(&im->mi[im->num_used]); + im->num_used++; + } + return TRUE; } -struct class_walker { - ATOM* table; - int used; - int alloc; +/*********************************************************************** + * info_win32_module + * + * Display information about a given module (DLL or EXE), or about all modules + */ +void info_win32_module(DWORD base) +{ + if (!dbg_curr_process || !dbg_curr_thread) + { + dbg_printf("Cannot get info on module while no process is loaded\n"); + return; + } + + if (base) + { + IMAGEHLP_MODULE mi; + + mi.SizeOfStruct = sizeof(mi); + + if (!SymGetModuleInfo(dbg_curr_process->handle, base, &mi)) + { + dbg_printf("'0x%08lx' is not a valid module address\n", base); + return; + } + module_print_info(&mi); + } + else + { + struct info_module im; + int i, j; + DWORD opt; + + im.mi = NULL; + im.num_alloc = im.num_used = 0; + + /* this is a wine specific options to return also ELF modules in the + * enumeration + */ + SymSetOptions((opt = SymGetOptions()) | 0x40000000); + SymEnumerateModules(dbg_curr_process->handle, info_mod_cb, (void*)&im); + SymSetOptions(opt); + + qsort(im.mi, im.num_used, sizeof(im.mi[0]), module_compare); + + dbg_printf("Module\tAddress\t\t\tDebug info\tName (%d modules)\n", im.num_used); + + for (i = 0; i < im.num_used; i++) + { + if (strstr(im.mi[i].ModuleName, "")) + { + dbg_printf("ELF\t"); + module_print_info(&im.mi[i]); + /* print all modules embedded in this one */ + for (j = 0; j < im.num_used; j++) + { + if (!strstr(im.mi[j].ModuleName, "") && module_is_container(&im.mi[i], &im.mi[j])) + { + dbg_printf(" \\-PE\t"); + module_print_info(&im.mi[j]); + } + } + } + else + { + /* check module is not embedded in another module */ + for (j = 0; j < im.num_used; j++) + { + if (strstr(im.mi[j].ModuleName, "") && module_is_container(&im.mi[j], &im.mi[i])) + break; + } + if (j < im.num_used) continue; + if (strstr(im.mi[i].ModuleName, ".so") || strchr(im.mi[i].ModuleName, '<')) + dbg_printf("ELF\t"); + else + dbg_printf("PE\t"); + module_print_info(&im.mi[i]); + } + } + HeapFree(GetProcessHeap(), 0, im.mi); + } +} + +struct class_walker +{ + ATOM* table; + int used; + int alloc; }; -static void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw) +static void class_walker(HWND hWnd, struct class_walker* cw) { - char clsName[128]; - int i; - ATOM atom; - HWND child; + char clsName[128]; + int i; + ATOM atom; + HWND child; - if (!GetClassName(hWnd, clsName, sizeof(clsName))) - return; - if ((atom = FindAtom(clsName)) == 0) - return; + if (!GetClassName(hWnd, clsName, sizeof(clsName))) + return; + if ((atom = FindAtom(clsName)) == 0) + return; - for (i = 0; i < cw->used; i++) { - if (cw->table[i] == atom) - break; - } - if (i == cw->used) { - if (cw->used >= cw->alloc) { - cw->alloc += 16; - cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM)); - } - cw->table[cw->used++] = atom; - DEBUG_InfoClass2(hWnd, clsName); - } - do { - if ((child = GetWindow(hWnd, GW_CHILD)) != 0) - DEBUG_WalkClassesHelper(child, cw); - } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0); -} - -void DEBUG_WalkClasses(void) -{ - struct class_walker cw; - - cw.table = NULL; - cw.used = cw.alloc = 0; - DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw); - DBG_free(cw.table); -} - -void DEBUG_InfoWindow(HWND hWnd) -{ - char clsName[128]; - char wndName[128]; - RECT clientRect; - RECT windowRect; - int i; - WORD w; - - if (!GetClassName(hWnd, clsName, sizeof(clsName))) - strcpy(clsName, "-- Unknown --"); - if (!GetWindowText(hWnd, wndName, sizeof(wndName))) - strcpy(wndName, "-- Empty --"); - if (!GetClientRect(hWnd, &clientRect) || - !MapWindowPoints( hWnd, 0, (LPPOINT) &clientRect, 2)) - SetRectEmpty(&clientRect); - if (!GetWindowRect(hWnd, &windowRect)) - SetRectEmpty(&windowRect); - - /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */ - DEBUG_Printf("next=%p child=%p parent=%p owner=%p class='%s'\n" - "inst=%p active=%p idmenu=%08lx\n" - "style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n" - "client=%ld,%ld-%ld,%ld window=%ld,%ld-%ld,%ld sysmenu=%p\n", - GetWindow(hWnd, GW_HWNDNEXT), - GetWindow(hWnd, GW_CHILD), - GetParent(hWnd), - GetWindow(hWnd, GW_OWNER), - clsName, - (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), - GetLastActivePopup(hWnd), - GetWindowLong(hWnd, GWL_ID), - GetWindowLong(hWnd, GWL_STYLE), - GetWindowLong(hWnd, GWL_EXSTYLE), - GetWindowLong(hWnd, GWL_WNDPROC), - wndName, - clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, - windowRect.left, windowRect.top, windowRect.right, windowRect.bottom, - GetSystemMenu(hWnd, FALSE)); - - if (GetClassLong(hWnd, GCL_CBWNDEXTRA)) { - DEBUG_Printf("Extra bytes:" ); - for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++) { - w = GetWindowWord(hWnd, i * 2); - /* FIXME: depends on i386 endian-ity */ - DEBUG_Printf(" %02x %02x", HIBYTE(w), LOBYTE(w)); - } - DEBUG_Printf("\n"); + for (i = 0; i < cw->used; i++) + { + if (cw->table[i] == atom) + break; } - DEBUG_Printf("\n"); -} - -void DEBUG_WalkWindows(HWND hWnd, int indent) -{ - char clsName[128]; - char wndName[128]; - HWND child; - - if (!IsWindow(hWnd)) - hWnd = GetDesktopWindow(); - - if (!indent) /* first time around */ - DEBUG_Printf("%-16.16s %-17.17s %-8.8s %s\n", - "hwnd", "Class Name", " Style", " WndProc Text"); - - do { - if (!GetClassName(hWnd, clsName, sizeof(clsName))) - strcpy(clsName, "-- Unknown --"); - if (!GetWindowText(hWnd, wndName, sizeof(wndName))) - strcpy(wndName, "-- Empty --"); - - /* FIXME: missing hmemTaskQ */ - DEBUG_Printf("%*s%04x%*s", indent, "", (UINT)hWnd, 13-indent,""); - DEBUG_Printf("%-17.17s %08lx %08lx %.14s\n", - clsName, GetWindowLong(hWnd, GWL_STYLE), - GetWindowLong(hWnd, GWL_WNDPROC), wndName); - - if ((child = GetWindow(hWnd, GW_CHILD)) != 0) - DEBUG_WalkWindows(child, indent + 1 ); + if (i == cw->used) + { + if (cw->used >= cw->alloc) + { + cw->alloc += 16; + cw->table = dbg_heap_realloc(cw->table, cw->alloc * sizeof(ATOM)); + } + cw->table[cw->used++] = atom; + info_win32_class(hWnd, clsName); + } + do + { + if ((child = GetWindow(hWnd, GW_CHILD)) != 0) + class_walker(child, cw); } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0); } -void DEBUG_WalkProcess(void) +void info_win32_class(HWND hWnd, const char* name) { - HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); + WNDCLASSEXA wca; + HINSTANCE hInst = hWnd ? (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE) : 0; + + if (!name) + { + struct class_walker cw; + + cw.table = NULL; + cw.used = cw.alloc = 0; + class_walker(GetDesktopWindow(), &cw); + HeapFree(GetProcessHeap(), 0, cw.table); + return; + } + + if (!GetClassInfoEx(hInst, name, &wca)) + { + dbg_printf("Cannot find class '%s'\n", name); + return; + } + + dbg_printf("Class '%s':\n", name); + dbg_printf("style=0x%08x wndProc=0x%08lx\n" + "inst=%p icon=%p cursor=%p bkgnd=%p\n" + "clsExtra=%d winExtra=%d\n", + wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance, + wca.hIcon, wca.hCursor, wca.hbrBackground, + wca.cbClsExtra, wca.cbWndExtra); + + if (hWnd && wca.cbClsExtra) + { + int i; + WORD w; + + dbg_printf("Extra bytes:"); + for (i = 0; i < wca.cbClsExtra / 2; i++) + { + w = GetClassWord(hWnd, i * 2); + /* FIXME: depends on i386 endian-ity */ + dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w)); + } + dbg_printf("\n"); + } + dbg_printf("\n"); + /* FIXME: + * + print #windows (or even list of windows...) + * + print extra bytes => this requires a window handle on this very class... + */ +} + +static void info_window(HWND hWnd, int indent) +{ + char clsName[128]; + char wndName[128]; + HWND child; + + do + { + if (!GetClassName(hWnd, clsName, sizeof(clsName))) + strcpy(clsName, "-- Unknown --"); + if (!GetWindowText(hWnd, wndName, sizeof(wndName))) + strcpy(wndName, "-- Empty --"); + + dbg_printf("%*s%08x%*s %-17.17s %08lx %08lx %.14s\n", + indent, "", (UINT)hWnd, 12 - indent, "", + clsName, GetWindowLong(hWnd, GWL_STYLE), + GetWindowLong(hWnd, GWL_WNDPROC), wndName); + + if ((child = GetWindow(hWnd, GW_CHILD)) != 0) + info_window(child, indent + 1); + } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0); +} + +void info_win32_window(HWND hWnd, BOOL detailed) +{ + char clsName[128]; + char wndName[128]; + RECT clientRect; + RECT windowRect; + int i; + WORD w; + + if (!IsWindow(hWnd)) hWnd = GetDesktopWindow(); + + if (!detailed) + { + dbg_printf("%-20.20s %-17.17s %-8.8s %-8.8s %s\n", + "Window handle", "Class Name", "Style", "WndProc", "Text"); + info_window(hWnd, 0); + return; + } + + if (!GetClassName(hWnd, clsName, sizeof(clsName))) + strcpy(clsName, "-- Unknown --"); + if (!GetWindowText(hWnd, wndName, sizeof(wndName))) + strcpy(wndName, "-- Empty --"); + if (!GetClientRect(hWnd, &clientRect) || + !MapWindowPoints(hWnd, 0, (LPPOINT) &clientRect, 2)) + SetRectEmpty(&clientRect); + if (!GetWindowRect(hWnd, &windowRect)) + SetRectEmpty(&windowRect); + + /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */ + dbg_printf("next=%p child=%p parent=%p owner=%p class='%s'\n" + "inst=%p active=%p idmenu=%08lx\n" + "style=0x%08lx exstyle=0x%08lx wndproc=0x%08lx text='%s'\n" + "client=%ld,%ld-%ld,%ld window=%ld,%ld-%ld,%ld sysmenu=%p\n", + GetWindow(hWnd, GW_HWNDNEXT), + GetWindow(hWnd, GW_CHILD), + GetParent(hWnd), + GetWindow(hWnd, GW_OWNER), + clsName, + (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), + GetLastActivePopup(hWnd), + GetWindowLong(hWnd, GWL_ID), + GetWindowLong(hWnd, GWL_STYLE), + GetWindowLong(hWnd, GWL_EXSTYLE), + GetWindowLong(hWnd, GWL_WNDPROC), + wndName, + clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, + windowRect.left, windowRect.top, windowRect.right, windowRect.bottom, + GetSystemMenu(hWnd, FALSE)); + + if (GetClassLong(hWnd, GCL_CBWNDEXTRA)) + { + dbg_printf("Extra bytes:"); + for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++) + { + w = GetWindowWord(hWnd, i * 2); + /* FIXME: depends on i386 endian-ity */ + dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w)); + } + dbg_printf("\n"); + } + dbg_printf("\n"); +} + +void info_win32_processes(void) +{ + HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snap != INVALID_HANDLE_VALUE) { - PROCESSENTRY32 entry; - DWORD current = DEBUG_CurrProcess ? DEBUG_CurrProcess->pid : 0; - BOOL ok; + PROCESSENTRY32 entry; + DWORD current = dbg_curr_process ? dbg_curr_process->pid : 0; + BOOL ok; entry.dwSize = sizeof(entry); - ok = Process32First( snap, &entry ); + ok = Process32First(snap, &entry); - DEBUG_Printf(" %-8.8s %-8.8s %-8.8s %s\n", - "pid", "threads", "parent", "executable" ); + dbg_printf(" %-8.8s %-8.8s %-8.8s %s (all id:s are in hex)\n", + "pid", "threads", "parent", "executable"); while (ok) { if (entry.th32ProcessID != GetCurrentProcessId()) - DEBUG_Printf("%c%08lx %-8ld %08lx '%s'\n", - (entry.th32ProcessID == current) ? '>' : ' ', - entry.th32ProcessID, entry.cntThreads, - entry.th32ParentProcessID, entry.szExeFile); - ok = Process32Next( snap, &entry ); + dbg_printf("%c%08lx %-8ld %08lx '%s'\n", + (entry.th32ProcessID == current) ? '>' : ' ', + entry.th32ProcessID, entry.cntThreads, + entry.th32ParentProcessID, entry.szExeFile); + ok = Process32Next(snap, &entry); } - CloseHandle( snap ); + CloseHandle(snap); } } -void DEBUG_WalkThreads(void) +void info_win32_threads(void) { - HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); + HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (snap != INVALID_HANDLE_VALUE) { THREADENTRY32 entry; - DWORD current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0; BOOL ok; DWORD lastProcessId = 0; entry.dwSize = sizeof(entry); - ok = Thread32First( snap, &entry ); + ok = Thread32First(snap, &entry); - DEBUG_Printf("%-8.8s %-8.8s %s\n", "process", "tid", "prio" ); + dbg_printf("%-8.8s %-8.8s %s (all id:s are in hex)\n", + "process", "tid", "prio"); while (ok) { if (entry.th32OwnerProcessID != GetCurrentProcessId()) @@ -511,84 +490,83 @@ void DEBUG_WalkThreads(void) */ if (entry.th32OwnerProcessID != lastProcessId) { - DBG_PROCESS* p = DEBUG_GetProcess(entry.th32OwnerProcessID); + struct dbg_process* p = dbg_get_process(entry.th32OwnerProcessID); - DEBUG_Printf("%08lx%s %s\n", - entry.th32OwnerProcessID, p ? " (D)" : "", p ? p->imageName : ""); + dbg_printf("%08lx%s %s\n", + entry.th32OwnerProcessID, p ? " (D)" : "", p ? p->imageName : ""); lastProcessId = entry.th32OwnerProcessID; } - DEBUG_Printf("\t%08lx %4ld%s\n", - entry.th32ThreadID, entry.tpBasePri, - (entry.th32ThreadID == current) ? " <==" : ""); + dbg_printf("\t%08lx %4ld%s\n", + entry.th32ThreadID, entry.tpBasePri, + (entry.th32ThreadID == dbg_curr_tid) ? " <==" : ""); } - ok = Thread32Next( snap, &entry ); + ok = Thread32Next(snap, &entry); } - CloseHandle( snap ); + CloseHandle(snap); } } /*********************************************************************** - * DEBUG_WalkExceptions + * info_win32_exceptions * - * Walk the exception frames of a given thread. + * Get info on the exception frames of a given thread. */ -void DEBUG_WalkExceptions(DWORD tid) +void info_win32_exceptions(DWORD tid) { - DBG_THREAD * thread; - void *next_frame; + struct dbg_thread* thread; + void* next_frame; - if (!DEBUG_CurrProcess || !DEBUG_CurrThread) + if (!dbg_curr_process || !dbg_curr_thread) { - DEBUG_Printf("Cannot walk exceptions while no process is loaded\n"); + dbg_printf("Cannot get info on exceptions while no process is loaded\n"); return; } - DEBUG_Printf("Exception frames:\n"); + dbg_printf("Exception frames:\n"); - if (tid == DEBUG_CurrTid) thread = DEBUG_CurrThread; + if (tid == dbg_curr_tid) thread = dbg_curr_thread; else { - thread = DEBUG_GetThread(DEBUG_CurrProcess, tid); + thread = dbg_get_thread(dbg_curr_process, tid); - if (!thread) - { - DEBUG_Printf("Unknown thread id (0x%08lx) in current process\n", tid); - return; - } - if (SuspendThread( thread->handle ) == -1) - { - DEBUG_Printf("Can't suspend thread id (0x%08lx)\n", tid); - return; - } + if (!thread) + { + dbg_printf("Unknown thread id (0x%08lx) in current process\n", tid); + return; + } + if (SuspendThread(thread->handle) == -1) + { + dbg_printf("Can't suspend thread id (0x%08lx)\n", tid); + return; + } } - if (!DEBUG_READ_MEM(thread->teb, &next_frame, sizeof(next_frame))) + if (!dbg_read_memory(thread->teb, &next_frame, sizeof(next_frame))) { - DEBUG_Printf("Can't read TEB:except_frame\n"); + dbg_printf("Can't read TEB:except_frame\n"); return; } - while (next_frame != (void *)-1) + while (next_frame != (void*)-1) { EXCEPTION_REGISTRATION_RECORD frame; - DEBUG_Printf("%p: ", next_frame); - if (!DEBUG_READ_MEM(next_frame, &frame, sizeof(frame))) + dbg_printf("%p: ", next_frame); + if (!dbg_read_memory(next_frame, &frame, sizeof(frame))) { - DEBUG_Printf("Invalid frame address\n"); + dbg_printf("Invalid frame address\n"); break; } - DEBUG_Printf("prev=%p handler=%p\n", frame.Prev, frame.Handler); + dbg_printf("prev=%p handler=%p\n", frame.Prev, frame.Handler); next_frame = frame.Prev; } - if (tid != DEBUG_CurrTid) ResumeThread( thread->handle ); + if (tid != dbg_curr_tid) ResumeThread(thread->handle); } - -void DEBUG_InfoSegments(DWORD start, int length) +void info_win32_segments(DWORD start, int length) { char flags[3]; DWORD i; @@ -598,7 +576,7 @@ void DEBUG_InfoSegments(DWORD start, int length) for (i = start; i < start + length; i++) { - if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3) | 7, &le)) + if (!GetThreadSelectorEntry(dbg_curr_thread->handle, (i << 3) | 7, &le)) continue; if (le.HighWord.Bits.Type & 0x08) @@ -613,18 +591,18 @@ void DEBUG_InfoSegments(DWORD start, int length) flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-'; flags[2] = '-'; } - DEBUG_Printf("%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n", - i, (i<<3)|7, - (le.HighWord.Bits.BaseHi << 24) + - (le.HighWord.Bits.BaseMid << 16) + le.BaseLow, - ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) << - (le.HighWord.Bits.Granularity ? 12 : 0), - le.HighWord.Bits.Default_Big ? 32 : 16, - flags[0], flags[1], flags[2] ); + dbg_printf("%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n", + i, (i << 3) | 7, + (le.HighWord.Bits.BaseHi << 24) + + (le.HighWord.Bits.BaseMid << 16) + le.BaseLow, + ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) << + (le.HighWord.Bits.Granularity ? 12 : 0), + le.HighWord.Bits.Default_Big ? 32 : 16, + flags[0], flags[1], flags[2]); } } -void DEBUG_InfoVirtual(DWORD pid) +void info_win32_virtual(DWORD pid) { MEMORY_BASIC_INFORMATION mbi; char* addr = 0; @@ -633,26 +611,26 @@ void DEBUG_InfoVirtual(DWORD pid) char prot[3+1]; HANDLE hProc; - if (pid == 0) + if (pid == dbg_curr_pid) { - if (DEBUG_CurrProcess == NULL) + if (dbg_curr_process == NULL) { - DEBUG_Printf("Cannot look at mapping of current process, while no process is loaded\n"); + dbg_printf("Cannot look at mapping of current process, while no process is loaded\n"); return; } - hProc = DEBUG_CurrProcess->handle; + hProc = dbg_curr_process->handle; } else { hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (hProc == NULL) { - DEBUG_Printf("Cannot open process <%lu>\n", pid); + dbg_printf("Cannot open process <%lu>\n", pid); return; } } - DEBUG_Printf("Address Size State Type RWX\n"); + dbg_printf("Address Size State Type RWX\n"); while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)) >= sizeof(mbi)) { @@ -673,8 +651,8 @@ void DEBUG_InfoVirtual(DWORD pid) case 0: type = " "; break; default: type = "??? "; break; } - memset(prot, ' ' , sizeof(prot)-1); - prot[sizeof(prot)-1] = '\0'; + memset(prot, ' ' , sizeof(prot) - 1); + prot[sizeof(prot) - 1] = '\0'; if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE)) prot[0] = 'R'; if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) @@ -689,13 +667,13 @@ void DEBUG_InfoVirtual(DWORD pid) type = ""; prot[0] = '\0'; } - DEBUG_Printf("%08lx %08lx %s %s %s\n", - (DWORD)addr, mbi.RegionSize, state, type, prot); + dbg_printf("%08lx %08lx %s %s %s\n", + (DWORD)addr, (DWORD)addr + mbi.RegionSize - 1, state, type, prot); if (addr + mbi.RegionSize < addr) /* wrap around ? */ break; addr += mbi.RegionSize; } - if (hProc != DEBUG_CurrProcess->handle) CloseHandle(hProc); + if (pid != dbg_curr_pid) CloseHandle(hProc); } struct dll_option_layout @@ -706,9 +684,9 @@ struct dll_option_layout int nb_channels; }; -void DEBUG_DbgChannel(BOOL turn_on, const char* chnl, const char* name) +void info_wine_dbg_channel(BOOL turn_on, const char* chnl, const char* name) { - DBG_VALUE val; + struct dbg_lvalue lvalue; struct dll_option_layout dol; int i; char* str; @@ -718,34 +696,40 @@ void DEBUG_DbgChannel(BOOL turn_on, const char* chnl, const char* name) BOOL bAll; void* addr; - if (DEBUG_GetSymbolValue("first_dll", -1, &val, FALSE) != gsv_found) + if (!dbg_curr_process || !dbg_curr_thread) { - DEBUG_Printf("Can't get first_dll symbol\n"); + dbg_printf("Cannot set/get debug channels while no process is loaded\n"); return; } - addr = (void*)DEBUG_ToLinear(&val.addr); + + if (symbol_get_lvalue("first_dll", -1, &lvalue, FALSE) != sglv_found) + { + dbg_printf("Can't get first_dll symbol\n"); + return; + } + addr = memory_to_linear_addr(&lvalue.addr); if (!chnl) mask = 15; else if (!strcmp(chnl, "fixme")) mask = 1; else if (!strcmp(chnl, "err")) mask = 2; else if (!strcmp(chnl, "warn")) mask = 4; else if (!strcmp(chnl, "trace")) mask = 8; - else { DEBUG_Printf("Unknown channel %s\n", chnl); return; } + else { dbg_printf("Unknown channel %s\n", chnl); return; } bAll = !strcmp("all", name); - while (addr && DEBUG_READ_MEM(addr, &dol, sizeof(dol))) + while (addr && dbg_read_memory(addr, &dol, sizeof(dol))) { for (i = 0; i < dol.nb_channels; i++) { - if (DEBUG_READ_MEM((void*)(dol.channels + i), &str, sizeof(str)) && - DEBUG_READ_MEM(str, buffer, sizeof(buffer)) && + if (dbg_read_memory(dol.channels + i, &str, sizeof(str)) && + dbg_read_memory(str, buffer, sizeof(buffer)) && (!strcmp(buffer + 1, name) || bAll)) { if (turn_on) buffer[0] |= mask; else buffer[0] &= ~mask; - if (DEBUG_WRITE_MEM(str, buffer, 1)) done++; + if (dbg_write_memory(str, buffer, 1)) done++; } } addr = dol.next; } - if (!done) DEBUG_Printf("Unable to find debug channel %s\n", name); + if (!done) dbg_printf("Unable to find debug channel %s\n", name); else WINE_TRACE("Changed %d channel instances\n", done); } diff --git a/programs/winedbg/intvar.h b/programs/winedbg/intvar.h index 9ae5a63f97b..f5830b6c337 100644 --- a/programs/winedbg/intvar.h +++ b/programs/winedbg/intvar.h @@ -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) diff --git a/programs/winedbg/memory.c b/programs/winedbg/memory.c index 88b51b6cb81..9976d3d90c3 100644 --- a/programs/winedbg/memory.c +++ b/programs/winedbg/memory.c @@ -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 #include +#include #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; idbg_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)); } diff --git a/programs/winedbg/module.c b/programs/winedbg/module.c deleted file mode 100644 index 0f5b5af0b4e..00000000000 --- a/programs/winedbg/module.c +++ /dev/null @@ -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 -#include -#include -#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); -} diff --git a/programs/winedbg/msc.c b/programs/winedbg/msc.c deleted file mode 100644 index d80e6256a07..00000000000 --- a/programs/winedbg/msc.c +++ /dev/null @@ -1,2855 +0,0 @@ -/* - * File msc.c - read VC++ debug information from COFF and eventually - * from PDB files. - * - * 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 - * - * Note - this handles reading debug information for 32 bit applications - * that run under Windows-NT for example. I doubt that this would work well - * for 16 bit applications, but I don't think it really matters since the - * file format is different, and we should never get in here in such cases. - * - * TODO: - * Get 16 bit CV stuff working. - * Add symbol size to internal symbol table. - */ - -#include "config.h" -#include "wine/port.h" - -#include - -#include -#ifdef HAVE_UNISTD_H -# include -#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); -WINE_DECLARE_DEBUG_CHANNEL(winedbg_msc); - -#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 file access helper routines - */ - -static WINE_EXCEPTION_FILTER(page_fault) -{ - if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) - return EXCEPTION_EXECUTE_HANDLER; - return EXCEPTION_CONTINUE_SEARCH; -} - -/*======================================================================== - * Process COFF debug information. - */ - -struct CoffFile -{ - unsigned int startaddr; - unsigned int endaddr; - const char *filename; - int linetab_offset; - int linecnt; - struct name_hash **entries; - int neps; - int neps_alloc; -}; - -struct CoffFileSet -{ - struct CoffFile *files; - int nfiles; - int nfiles_alloc; -}; - -static const char* DEBUG_GetCoffName( PIMAGE_SYMBOL coff_sym, const char* coff_strtab ) -{ - static char namebuff[9]; - const char* nampnt; - - if( coff_sym->N.Name.Short ) - { - memcpy(namebuff, coff_sym->N.ShortName, 8); - namebuff[8] = '\0'; - nampnt = &namebuff[0]; - } - else - { - nampnt = coff_strtab + coff_sym->N.Name.Long; - } - - if( nampnt[0] == '_' ) - nampnt++; - return nampnt; -} - -static int DEBUG_AddCoffFile( struct CoffFileSet* coff_files, const char* filename ) -{ - struct CoffFile* file; - - if( coff_files->nfiles + 1 >= coff_files->nfiles_alloc ) - { - coff_files->nfiles_alloc += 10; - coff_files->files = (struct CoffFile *) DBG_realloc(coff_files->files, - coff_files->nfiles_alloc * sizeof(struct CoffFile)); - } - file = coff_files->files + coff_files->nfiles; - file->startaddr = 0xffffffff; - file->endaddr = 0; - file->filename = filename; - file->linetab_offset = -1; - file->linecnt = 0; - file->entries = NULL; - file->neps = file->neps_alloc = 0; - - return coff_files->nfiles++; -} - -static void DEBUG_AddCoffSymbol( struct CoffFile* coff_file, struct name_hash* sym ) -{ - if( coff_file->neps + 1 >= coff_file->neps_alloc ) - { - coff_file->neps_alloc += 10; - coff_file->entries = (struct name_hash **) - DBG_realloc(coff_file->entries, - coff_file->neps_alloc * sizeof(struct name_hash *)); - } - coff_file->entries[coff_file->neps++] = sym; -} - -static enum DbgInfoLoad DEBUG_ProcessCoff( DBG_MODULE *module, const BYTE* root ) -{ - PIMAGE_AUX_SYMBOL aux; - PIMAGE_COFF_SYMBOLS_HEADER coff; - PIMAGE_LINENUMBER coff_linetab; - PIMAGE_LINENUMBER linepnt; - char * coff_strtab; - PIMAGE_SYMBOL coff_sym; - PIMAGE_SYMBOL coff_symbols; - struct CoffFileSet coff_files; - int curr_file_idx = -1; - unsigned int i; - int j; - int k; - int l; - int linetab_indx; - const char * nampnt; - int naux; - DBG_VALUE new_value; - enum DbgInfoLoad dil = DIL_ERROR; - - WINE_TRACE("Processing COFF symbols...\n"); - - assert(sizeof(IMAGE_SYMBOL) == IMAGE_SIZEOF_SYMBOL); - assert(sizeof(IMAGE_LINENUMBER) == IMAGE_SIZEOF_LINENUMBER); - - coff_files.files = NULL; - coff_files.nfiles = coff_files.nfiles_alloc = 0; - - coff = (PIMAGE_COFF_SYMBOLS_HEADER) root; - - coff_symbols = (PIMAGE_SYMBOL) ((unsigned int) coff + coff->LvaToFirstSymbol); - coff_linetab = (PIMAGE_LINENUMBER) ((unsigned int) coff + coff->LvaToFirstLinenumber); - coff_strtab = (char *) (coff_symbols + coff->NumberOfSymbols); - - linetab_indx = 0; - - new_value.cookie = DV_TARGET; - new_value.type = NULL; - - for(i=0; i < coff->NumberOfSymbols; i++ ) - { - coff_sym = coff_symbols + i; - naux = coff_sym->NumberOfAuxSymbols; - - if( coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE ) - { - curr_file_idx = DEBUG_AddCoffFile( &coff_files, (char *) (coff_sym + 1) ); - WINE_TRACE("New file %s\n", coff_files.files[curr_file_idx].filename); - i += naux; - continue; - } - - if (curr_file_idx < 0) { - assert(coff_files.nfiles == 0 && coff_files.nfiles_alloc == 0); - curr_file_idx = DEBUG_AddCoffFile( &coff_files, "" ); - WINE_TRACE("New file %s\n", coff_files.files[curr_file_idx].filename); - } - - /* - * This guy marks the size and location of the text section - * for the current file. We need to keep track of this so - * we can figure out what file the different global functions - * go with. - */ - if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC) - && (naux != 0) - && (coff_sym->Type == 0) - && (coff_sym->SectionNumber == 1) ) - { - aux = (PIMAGE_AUX_SYMBOL) (coff_sym + 1); - - if( coff_files.files[curr_file_idx].linetab_offset != -1 ) - { - /* - * Save this so we can still get the old name. - */ - const char* fn = coff_files.files[curr_file_idx].filename; - - WINE_TRACE_(winedbg_msc)( - "Duplicating sect from %s: %lx %x %x %d %d\n", - coff_files.files[curr_file_idx].filename, - aux->Section.Length, - aux->Section.NumberOfRelocations, - aux->Section.NumberOfLinenumbers, - aux->Section.Number, - aux->Section.Selection); - WINE_TRACE_(winedbg_msc)( - "More sect %d %s %08lx %d %d %d\n", - coff_sym->SectionNumber, - DEBUG_GetCoffName( coff_sym, coff_strtab ), - coff_sym->Value, - coff_sym->Type, - coff_sym->StorageClass, - coff_sym->NumberOfAuxSymbols); - - /* - * Duplicate the file entry. We have no way to describe - * multiple text sections in our current way of handling things. - */ - DEBUG_AddCoffFile( &coff_files, fn ); - } - else - { - WINE_TRACE_(winedbg_msc)( - "New text sect from %s: %lx %x %x %d %d\n", - coff_files.files[curr_file_idx].filename, - aux->Section.Length, - aux->Section.NumberOfRelocations, - aux->Section.NumberOfLinenumbers, - aux->Section.Number, - aux->Section.Selection); - } - - if( coff_files.files[curr_file_idx].startaddr > coff_sym->Value ) - { - coff_files.files[curr_file_idx].startaddr = coff_sym->Value; - } - - if( coff_files.files[curr_file_idx].endaddr < coff_sym->Value + aux->Section.Length ) - { - coff_files.files[curr_file_idx].endaddr = coff_sym->Value + aux->Section.Length; - } - - coff_files.files[curr_file_idx].linetab_offset = linetab_indx; - coff_files.files[curr_file_idx].linecnt = aux->Section.NumberOfLinenumbers; - linetab_indx += aux->Section.NumberOfLinenumbers; - i += naux; - continue; - } - - if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC) - && (naux == 0) - && (coff_sym->SectionNumber == 1) ) - { - DWORD base = module->msc_dbg_info->sectp[coff_sym->SectionNumber - 1].VirtualAddress; - /* - * This is a normal static function when naux == 0. - * Just register it. The current file is the correct - * one in this instance. - */ - nampnt = DEBUG_GetCoffName( coff_sym, coff_strtab ); - - new_value.addr.seg = 0; - new_value.addr.off = (int) ((char *)module->load_addr + base + coff_sym->Value); - - WINE_TRACE_(winedbg_msc)("\tAdding static symbol %s\n", nampnt); - - /* FIXME: was adding symbol to this_file ??? */ - DEBUG_AddCoffSymbol( &coff_files.files[curr_file_idx], - DEBUG_AddSymbol( nampnt, &new_value, - coff_files.files[curr_file_idx].filename, - SYM_WIN32 | SYM_FUNC ) ); - i += naux; - continue; - } - - if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) - && ISFCN(coff_sym->Type) - && (coff_sym->SectionNumber > 0) ) - { - const char* this_file = NULL; - DWORD base = module->msc_dbg_info->sectp[coff_sym->SectionNumber - 1].VirtualAddress; - nampnt = DEBUG_GetCoffName( coff_sym, coff_strtab ); - - new_value.addr.seg = 0; - new_value.addr.off = (int) ((char *)module->load_addr + base + coff_sym->Value); - - WINE_TRACE_(winedbg_msc)("%d: %lx %s\n", i, new_value.addr.off, nampnt); - WINE_TRACE_(winedbg_msc)( - "\tAdding global symbol %s (sect=%s)\n", - nampnt, module->msc_dbg_info->sectp[coff_sym->SectionNumber - 1].Name); - - /* - * Now we need to figure out which file this guy belongs to. - */ - for(j=0; j < coff_files.nfiles; j++) - { - if( coff_files.files[j].startaddr <= base + coff_sym->Value - && coff_files.files[j].endaddr > base + coff_sym->Value ) - { - this_file = coff_files.files[j].filename; - break; - } - } - if (j < coff_files.nfiles) { - DEBUG_AddCoffSymbol( &coff_files.files[j], - DEBUG_AddSymbol( nampnt, &new_value, this_file, SYM_WIN32 | SYM_FUNC ) ); - } else { - DEBUG_AddSymbol( nampnt, &new_value, NULL, SYM_WIN32 | SYM_FUNC ); - } - i += naux; - continue; - } - - if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) - && (coff_sym->SectionNumber > 0) ) - { - DWORD base = module->msc_dbg_info->sectp[coff_sym->SectionNumber - 1].VirtualAddress; - /* - * Similar to above, but for the case of data symbols. - * These aren't treated as entrypoints. - */ - nampnt = DEBUG_GetCoffName( coff_sym, coff_strtab ); - - new_value.addr.seg = 0; - new_value.addr.off = (int) ((char *)module->load_addr + base + coff_sym->Value); - - WINE_TRACE_(winedbg_msc)("%d: %lx %s\n", i, new_value.addr.off, nampnt); - WINE_TRACE_(winedbg_msc)("\tAdding global data symbol %s\n", nampnt); - - /* - * Now we need to figure out which file this guy belongs to. - */ - DEBUG_AddSymbol( nampnt, &new_value, NULL, SYM_WIN32 | SYM_DATA ); - i += naux; - continue; - } - - if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC) - && (naux == 0) ) - { - /* - * Ignore these. They don't have anything to do with - * reality. - */ - i += naux; - continue; - } - - WINE_TRACE_(winedbg_msc)( - "Skipping unknown entry '%s' %d %d %d\n", - DEBUG_GetCoffName( coff_sym, coff_strtab ), - coff_sym->StorageClass, coff_sym->SectionNumber, naux); - - /* - * For now, skip past the aux entries. - */ - i += naux; - - } - - /* - * OK, we now should have a list of files, and we should have a list - * of entrypoints. We need to sort the entrypoints so that we are - * able to tie the line numbers with the given functions within the - * file. - */ - if( coff_files.files != NULL ) - { - for(j=0; j < coff_files.nfiles; j++) - { - if( coff_files.files[j].entries != NULL ) - { - qsort(coff_files.files[j].entries, coff_files.files[j].neps, - sizeof(struct name_hash *), DEBUG_cmp_sym); - } - } - - /* - * Now pick apart the line number tables, and attach the entries - * to the given functions. - */ - for(j=0; j < coff_files.nfiles; j++) - { - l = 0; - if( coff_files.files[j].neps != 0 ) - for(k=0; k < coff_files.files[j].linecnt; k++) - { - linepnt = coff_linetab + coff_files.files[j].linetab_offset + k; - /* - * If we have spilled onto the next entrypoint, then - * bump the counter.. - */ - while(TRUE) - { - if (l+1 >= coff_files.files[j].neps) break; - DEBUG_GetSymbolAddr(coff_files.files[j].entries[l+1], &new_value.addr); - if( (((unsigned int)module->load_addr + - linepnt->Type.VirtualAddress) >= new_value.addr.off) ) - { - l++; - } else break; - } - - /* - * Add the line number. This is always relative to the - * start of the function, so we need to subtract that offset - * first. - */ - DEBUG_GetSymbolAddr(coff_files.files[j].entries[l], &new_value.addr); - DEBUG_AddLineNumber(coff_files.files[j].entries[l], - linepnt->Linenumber, - (unsigned int) module->load_addr - + linepnt->Type.VirtualAddress - - new_value.addr.off); - } - } - } - - dil = DIL_LOADED; - - if( coff_files.files != NULL ) - { - for(j=0; j < coff_files.nfiles; j++) - { - if( coff_files.files[j].entries != NULL ) - { - DBG_free(coff_files.files[j].entries); - } - } - DBG_free(coff_files.files); - } - - return dil; - -} - - - -/*======================================================================== - * Process CodeView type information. - */ - -union codeview_type -{ - struct - { - unsigned short int len; - short int id; - } generic; - - struct - { - unsigned short int len; - short int id; - short int attribute; - short int datatype; - unsigned char variant[1]; - } pointer; - - struct - { - unsigned short int len; - short int id; - unsigned int datatype; - unsigned int attribute; - unsigned char variant[1]; - } pointer32; - - struct - { - unsigned short int len; - short int id; - unsigned char nbits; - unsigned char bitoff; - unsigned short type; - } bitfield; - - struct - { - unsigned short int len; - short int id; - unsigned int type; - unsigned char nbits; - unsigned char bitoff; - } bitfield32; - - struct - { - unsigned short int len; - short int id; - short int elemtype; - short int idxtype; - unsigned short int arrlen; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } array; - - struct - { - unsigned short int len; - short int id; - unsigned int elemtype; - unsigned int idxtype; - unsigned short int arrlen; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } array32; - - struct - { - unsigned short int len; - short int id; - short int n_element; - short int fieldlist; - short int property; - short int derived; - short int vshape; - unsigned short int structlen; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } structure; - - struct - { - unsigned short int len; - short int id; - short int n_element; - short int property; - unsigned int fieldlist; - unsigned int derived; - unsigned int vshape; - unsigned short int structlen; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } structure32; - - struct - { - unsigned short int len; - short int id; - short int count; - short int fieldlist; - short int property; - unsigned short int un_len; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } t_union; - - struct - { - unsigned short int len; - short int id; - short int count; - short int property; - unsigned int fieldlist; - unsigned short int un_len; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } t_union32; - - struct - { - unsigned short int len; - short int id; - short int count; - short int type; - short int field; - short int property; - unsigned char name[1]; - } enumeration; - - struct - { - unsigned short int len; - short int id; - short int count; - short int property; - unsigned int type; - unsigned int field; - unsigned char name[1]; - } enumeration32; - - struct - { - unsigned short int len; - short int id; - unsigned char list[1]; - } fieldlist; -}; - -union codeview_fieldtype -{ - struct - { - short int id; - } generic; - - struct - { - short int id; - short int type; - short int attribute; - unsigned short int offset; /* numeric leaf */ - } bclass; - - struct - { - short int id; - short int attribute; - unsigned int type; - unsigned short int offset; /* numeric leaf */ - } bclass32; - - struct - { - short int id; - short int btype; - short int vbtype; - short int attribute; - unsigned short int vbpoff; /* numeric leaf */ -#if 0 - unsigned short int vboff; /* numeric leaf */ -#endif - } vbclass; - - struct - { - short int id; - short int attribute; - unsigned int btype; - unsigned int vbtype; - unsigned short int vbpoff; /* numeric leaf */ -#if 0 - unsigned short int vboff; /* numeric leaf */ -#endif - } vbclass32; - - struct - { - short int id; - short int attribute; - unsigned short int value; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } enumerate; - - struct - { - short int id; - short int type; - unsigned char name[1]; - } friendfcn; - - struct - { - short int id; - short int _pad0; - unsigned int type; - unsigned char name[1]; - } friendfcn32; - - struct - { - short int id; - short int type; - short int attribute; - unsigned short int offset; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } member; - - struct - { - short int id; - short int attribute; - unsigned int type; - unsigned short int offset; /* numeric leaf */ -#if 0 - unsigned char name[1]; -#endif - } member32; - - struct - { - short int id; - short int type; - short int attribute; - unsigned char name[1]; - } stmember; - - struct - { - short int id; - short int attribute; - unsigned int type; - unsigned char name[1]; - } stmember32; - - struct - { - short int id; - short int count; - short int mlist; - unsigned char name[1]; - } method; - - struct - { - short int id; - short int count; - unsigned int mlist; - unsigned char name[1]; - } method32; - - struct - { - short int id; - short int index; - unsigned char name[1]; - } nesttype; - - struct - { - short int id; - short int _pad0; - unsigned int index; - unsigned char name[1]; - } nesttype32; - - struct - { - short int id; - short int type; - } vfunctab; - - struct - { - short int id; - short int _pad0; - unsigned int type; - } vfunctab32; - - struct - { - short int id; - short int type; - } friendcls; - - struct - { - short int id; - short int _pad0; - unsigned int type; - } friendcls32; - - - struct - { - short int id; - short int attribute; - short int type; - unsigned char name[1]; - } onemethod; - struct - { - short int id; - short int attribute; - short int type; - unsigned int vtab_offset; - unsigned char name[1]; - } onemethod_virt; - - struct - { - short int id; - short int attribute; - unsigned int type; - unsigned char name[1]; - } onemethod32; - struct - { - short int id; - short int attribute; - unsigned int type; - unsigned int vtab_offset; - unsigned char name[1]; - } onemethod32_virt; - - struct - { - short int id; - short int type; - unsigned int offset; - } vfuncoff; - - struct - { - short int id; - short int _pad0; - unsigned int type; - unsigned int offset; - } vfuncoff32; - - struct - { - short int id; - short int attribute; - short int index; - unsigned char name[1]; - } nesttypeex; - - struct - { - short int id; - short int attribute; - unsigned int index; - unsigned char name[1]; - } nesttypeex32; - - struct - { - short int id; - short int attribute; - unsigned int type; - unsigned char name[1]; - } membermodify; -}; - - -/* - * This covers the basic datatypes that VC++ seems to be using these days. - * 32 bit mode only. There are additional numbers for the pointers in 16 - * bit mode. There are many other types listed in the documents, but these - * are apparently not used by the compiler, or represent pointer types - * that are not used. - */ -#define T_NOTYPE 0x0000 /* Notype */ -#define T_ABS 0x0001 /* Abs */ -#define T_VOID 0x0003 /* Void */ -#define T_CHAR 0x0010 /* signed char */ -#define T_SHORT 0x0011 /* short */ -#define T_LONG 0x0012 /* long */ -#define T_QUAD 0x0013 /* long long */ -#define T_UCHAR 0x0020 /* unsigned char */ -#define T_USHORT 0x0021 /* unsigned short */ -#define T_ULONG 0x0022 /* unsigned long */ -#define T_UQUAD 0x0023 /* unsigned long long */ -#define T_REAL32 0x0040 /* float */ -#define T_REAL64 0x0041 /* double */ -#define T_RCHAR 0x0070 /* real char */ -#define T_WCHAR 0x0071 /* wide char */ -#define T_INT4 0x0074 /* int */ -#define T_UINT4 0x0075 /* unsigned int */ - -#define T_32PVOID 0x0403 /* 32 bit near pointer to void */ -#define T_32PCHAR 0x0410 /* 16:32 near pointer to signed char */ -#define T_32PSHORT 0x0411 /* 16:32 near pointer to short */ -#define T_32PLONG 0x0412 /* 16:32 near pointer to int */ -#define T_32PQUAD 0x0413 /* 16:32 near pointer to long long */ -#define T_32PUCHAR 0x0420 /* 16:32 near pointer to unsigned char */ -#define T_32PUSHORT 0x0421 /* 16:32 near pointer to unsigned short */ -#define T_32PULONG 0x0422 /* 16:32 near pointer to unsigned int */ -#define T_32PUQUAD 0x0423 /* 16:32 near pointer to long long */ -#define T_32PREAL32 0x0440 /* 16:32 near pointer to float */ -#define T_32PREAL64 0x0441 /* 16:32 near pointer to float */ -#define T_32PRCHAR 0x0470 /* 16:32 near pointer to real char */ -#define T_32PWCHAR 0x0471 /* 16:32 near pointer to real char */ -#define T_32PINT4 0x0474 /* 16:32 near pointer to int */ -#define T_32PUINT4 0x0475 /* 16:32 near pointer to unsigned int */ - - -#define LF_MODIFIER 0x0001 -#define LF_POINTER 0x0002 -#define LF_ARRAY 0x0003 -#define LF_CLASS 0x0004 -#define LF_STRUCTURE 0x0005 -#define LF_UNION 0x0006 -#define LF_ENUM 0x0007 -#define LF_PROCEDURE 0x0008 -#define LF_MFUNCTION 0x0009 -#define LF_VTSHAPE 0x000a -#define LF_COBOL0 0x000b -#define LF_COBOL1 0x000c -#define LF_BARRAY 0x000d -#define LF_LABEL 0x000e -#define LF_NULL 0x000f -#define LF_NOTTRAN 0x0010 -#define LF_DIMARRAY 0x0011 -#define LF_VFTPATH 0x0012 -#define LF_PRECOMP 0x0013 -#define LF_ENDPRECOMP 0x0014 -#define LF_OEM 0x0015 -#define LF_TYPESERVER 0x0016 - -#define LF_MODIFIER_32 0x1001 /* variants with new 32-bit type indices */ -#define LF_POINTER_32 0x1002 -#define LF_ARRAY_32 0x1003 -#define LF_CLASS_32 0x1004 -#define LF_STRUCTURE_32 0x1005 -#define LF_UNION_32 0x1006 -#define LF_ENUM_32 0x1007 -#define LF_PROCEDURE_32 0x1008 -#define LF_MFUNCTION_32 0x1009 -#define LF_COBOL0_32 0x100a -#define LF_BARRAY_32 0x100b -#define LF_DIMARRAY_32 0x100c -#define LF_VFTPATH_32 0x100d -#define LF_PRECOMP_32 0x100e -#define LF_OEM_32 0x100f - -#define LF_SKIP 0x0200 -#define LF_ARGLIST 0x0201 -#define LF_DEFARG 0x0202 -#define LF_LIST 0x0203 -#define LF_FIELDLIST 0x0204 -#define LF_DERIVED 0x0205 -#define LF_BITFIELD 0x0206 -#define LF_METHODLIST 0x0207 -#define LF_DIMCONU 0x0208 -#define LF_DIMCONLU 0x0209 -#define LF_DIMVARU 0x020a -#define LF_DIMVARLU 0x020b -#define LF_REFSYM 0x020c - -#define LF_SKIP_32 0x1200 /* variants with new 32-bit type indices */ -#define LF_ARGLIST_32 0x1201 -#define LF_DEFARG_32 0x1202 -#define LF_FIELDLIST_32 0x1203 -#define LF_DERIVED_32 0x1204 -#define LF_BITFIELD_32 0x1205 -#define LF_METHODLIST_32 0x1206 -#define LF_DIMCONU_32 0x1207 -#define LF_DIMCONLU_32 0x1208 -#define LF_DIMVARU_32 0x1209 -#define LF_DIMVARLU_32 0x120a - -#define LF_BCLASS 0x0400 -#define LF_VBCLASS 0x0401 -#define LF_IVBCLASS 0x0402 -#define LF_ENUMERATE 0x0403 -#define LF_FRIENDFCN 0x0404 -#define LF_INDEX 0x0405 -#define LF_MEMBER 0x0406 -#define LF_STMEMBER 0x0407 -#define LF_METHOD 0x0408 -#define LF_NESTTYPE 0x0409 -#define LF_VFUNCTAB 0x040a -#define LF_FRIENDCLS 0x040b -#define LF_ONEMETHOD 0x040c -#define LF_VFUNCOFF 0x040d -#define LF_NESTTYPEEX 0x040e -#define LF_MEMBERMODIFY 0x040f - -#define LF_BCLASS_32 0x1400 /* variants with new 32-bit type indices */ -#define LF_VBCLASS_32 0x1401 -#define LF_IVBCLASS_32 0x1402 -#define LF_FRIENDFCN_32 0x1403 -#define LF_INDEX_32 0x1404 -#define LF_MEMBER_32 0x1405 -#define LF_STMEMBER_32 0x1406 -#define LF_METHOD_32 0x1407 -#define LF_NESTTYPE_32 0x1408 -#define LF_VFUNCTAB_32 0x1409 -#define LF_FRIENDCLS_32 0x140a -#define LF_ONEMETHOD_32 0x140b -#define LF_VFUNCOFF_32 0x140c -#define LF_NESTTYPEEX_32 0x140d - -#define LF_NUMERIC 0x8000 /* numeric leaf types */ -#define LF_CHAR 0x8000 -#define LF_SHORT 0x8001 -#define LF_USHORT 0x8002 -#define LF_LONG 0x8003 -#define LF_ULONG 0x8004 -#define LF_REAL32 0x8005 -#define LF_REAL64 0x8006 -#define LF_REAL80 0x8007 -#define LF_REAL128 0x8008 -#define LF_QUADWORD 0x8009 -#define LF_UQUADWORD 0x800a -#define LF_REAL48 0x800b -#define LF_COMPLEX32 0x800c -#define LF_COMPLEX64 0x800d -#define LF_COMPLEX80 0x800e -#define LF_COMPLEX128 0x800f -#define LF_VARSTRING 0x8010 - - - -#define MAX_BUILTIN_TYPES 0x480 -static struct datatype * cv_basic_types[MAX_BUILTIN_TYPES]; -static unsigned int num_cv_defined_types = 0; -static struct datatype **cv_defined_types = NULL; - -void -DEBUG_InitCVDataTypes(void) -{ - /* - * These are the common builtin types that are used by VC++. - */ - cv_basic_types[T_NOTYPE] = NULL; - cv_basic_types[T_ABS] = NULL; - cv_basic_types[T_VOID] = DEBUG_GetBasicType(DT_BASIC_VOID); - cv_basic_types[T_CHAR] = DEBUG_GetBasicType(DT_BASIC_CHAR); - cv_basic_types[T_SHORT] = DEBUG_GetBasicType(DT_BASIC_SHORTINT); - cv_basic_types[T_LONG] = DEBUG_GetBasicType(DT_BASIC_LONGINT); - cv_basic_types[T_QUAD] = DEBUG_GetBasicType(DT_BASIC_LONGLONGINT); - cv_basic_types[T_UCHAR] = DEBUG_GetBasicType(DT_BASIC_UCHAR); - cv_basic_types[T_USHORT] = DEBUG_GetBasicType(DT_BASIC_USHORTINT); - cv_basic_types[T_ULONG] = DEBUG_GetBasicType(DT_BASIC_ULONGINT); - cv_basic_types[T_UQUAD] = DEBUG_GetBasicType(DT_BASIC_ULONGLONGINT); - cv_basic_types[T_REAL32] = DEBUG_GetBasicType(DT_BASIC_FLOAT); - cv_basic_types[T_REAL64] = DEBUG_GetBasicType(DT_BASIC_DOUBLE); - cv_basic_types[T_RCHAR] = DEBUG_GetBasicType(DT_BASIC_CHAR); - cv_basic_types[T_WCHAR] = DEBUG_GetBasicType(DT_BASIC_SHORTINT); - cv_basic_types[T_INT4] = DEBUG_GetBasicType(DT_BASIC_INT); - cv_basic_types[T_UINT4] = DEBUG_GetBasicType(DT_BASIC_UINT); - - cv_basic_types[T_32PVOID] = DEBUG_FindOrMakePointerType(cv_basic_types[T_VOID]); - cv_basic_types[T_32PCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_CHAR]); - cv_basic_types[T_32PSHORT] = DEBUG_FindOrMakePointerType(cv_basic_types[T_SHORT]); - cv_basic_types[T_32PLONG] = DEBUG_FindOrMakePointerType(cv_basic_types[T_LONG]); - cv_basic_types[T_32PQUAD] = DEBUG_FindOrMakePointerType(cv_basic_types[T_QUAD]); - cv_basic_types[T_32PUCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UCHAR]); - cv_basic_types[T_32PUSHORT] = DEBUG_FindOrMakePointerType(cv_basic_types[T_USHORT]); - cv_basic_types[T_32PULONG] = DEBUG_FindOrMakePointerType(cv_basic_types[T_ULONG]); - cv_basic_types[T_32PUQUAD] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UQUAD]); - cv_basic_types[T_32PREAL32] = DEBUG_FindOrMakePointerType(cv_basic_types[T_REAL32]); - cv_basic_types[T_32PREAL64] = DEBUG_FindOrMakePointerType(cv_basic_types[T_REAL64]); - cv_basic_types[T_32PRCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_RCHAR]); - cv_basic_types[T_32PWCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_WCHAR]); - cv_basic_types[T_32PINT4] = DEBUG_FindOrMakePointerType(cv_basic_types[T_INT4]); - cv_basic_types[T_32PUINT4] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UINT4]); -} - - -static int -numeric_leaf( int *value, unsigned short int *leaf ) -{ - unsigned short int type = *leaf++; - int length = 2; - - if ( type < LF_NUMERIC ) - { - *value = type; - } - else - { - switch ( type ) - { - case LF_CHAR: - length += 1; - *value = *(char *)leaf; - break; - - case LF_SHORT: - length += 2; - *value = *(short *)leaf; - break; - - case LF_USHORT: - length += 2; - *value = *(unsigned short *)leaf; - break; - - case LF_LONG: - length += 4; - *value = *(int *)leaf; - break; - - case LF_ULONG: - length += 4; - *value = *(unsigned int *)leaf; - break; - - case LF_QUADWORD: - case LF_UQUADWORD: - length += 8; - *value = 0; /* FIXME */ - break; - - case LF_REAL32: - length += 4; - *value = 0; /* FIXME */ - break; - - case LF_REAL48: - length += 6; - *value = 0; /* FIXME */ - break; - - case LF_REAL64: - length += 8; - *value = 0; /* FIXME */ - break; - - case LF_REAL80: - length += 10; - *value = 0; /* FIXME */ - break; - - case LF_REAL128: - length += 16; - *value = 0; /* FIXME */ - break; - - case LF_COMPLEX32: - length += 4; - *value = 0; /* FIXME */ - break; - - case LF_COMPLEX64: - length += 8; - *value = 0; /* FIXME */ - break; - - case LF_COMPLEX80: - length += 10; - *value = 0; /* FIXME */ - break; - - case LF_COMPLEX128: - length += 16; - *value = 0; /* FIXME */ - break; - - case LF_VARSTRING: - length += 2 + *leaf; - *value = 0; /* FIXME */ - break; - - default: - DEBUG_Printf("Unknown numeric leaf type %04x\n", type); - *value = 0; - break; - } - } - - return length; -} - -static char * -terminate_string( unsigned char *name ) -{ - static char symname[256]; - - int namelen = name[0]; - assert( namelen >= 0 && namelen < 256 ); - - memcpy( symname, name+1, namelen ); - symname[namelen] = '\0'; - - if ( !*symname || strcmp( symname, "__unnamed" ) == 0 ) - return NULL; - else - return symname; -} - -static -struct datatype * DEBUG_GetCVType(unsigned int typeno) -{ - struct datatype * dt = NULL; - - /* - * Convert Codeview type numbers into something we can grok internally. - * Numbers < 0x1000 are all fixed builtin types. Numbers from 0x1000 and - * up are all user defined (structs, etc). - */ - if ( typeno < 0x1000 ) - { - if ( typeno < MAX_BUILTIN_TYPES ) - dt = cv_basic_types[typeno]; - } - else - { - if ( typeno - 0x1000 < num_cv_defined_types ) - dt = cv_defined_types[typeno - 0x1000]; - } - - return dt; -} - -static int -DEBUG_AddCVType( unsigned int typeno, struct datatype *dt ) -{ - while ( typeno - 0x1000 >= num_cv_defined_types ) - { - num_cv_defined_types += 0x100; - cv_defined_types = (struct datatype **) - DBG_realloc( cv_defined_types, - num_cv_defined_types * sizeof(struct datatype *) ); - - memset( cv_defined_types + num_cv_defined_types - 0x100, - 0, - 0x100 * sizeof(struct datatype *) ); - - if ( cv_defined_types == NULL ) - return FALSE; - } - - cv_defined_types[ typeno - 0x1000 ] = dt; - return TRUE; -} - -static void -DEBUG_ClearTypeTable( void ) -{ - if ( cv_defined_types ) - DBG_free( cv_defined_types ); - - cv_defined_types = NULL; - num_cv_defined_types = 0; -} - -static int -DEBUG_AddCVType_Pointer( unsigned int typeno, unsigned int datatype ) -{ - struct datatype *dt = - DEBUG_FindOrMakePointerType( DEBUG_GetCVType( datatype ) ); - - return DEBUG_AddCVType( typeno, dt ); -} - -static int -DEBUG_AddCVType_Array( unsigned int typeno, char *name, - unsigned int elemtype, unsigned int arr_len ) -{ - struct datatype *dt = DEBUG_NewDataType( DT_ARRAY, name ); - struct datatype *elem = DEBUG_GetCVType( elemtype ); - unsigned int elem_size = elem? DEBUG_GetObjectSize( elem ) : 0; - unsigned int arr_max = elem_size? arr_len / elem_size : 0; - - DEBUG_SetArrayParams( dt, 0, arr_max, elem ); - return DEBUG_AddCVType( typeno, dt ); -} - -static int -DEBUG_AddCVType_Bitfield( unsigned int typeno, - unsigned int bitoff, unsigned int nbits, - unsigned int basetype ) -{ - struct datatype *dt = DEBUG_NewDataType( DT_BITFIELD, NULL ); - struct datatype *base = DEBUG_GetCVType( basetype ); - - DEBUG_SetBitfieldParams( dt, bitoff, nbits, base ); - return DEBUG_AddCVType( typeno, dt ); -} - -static int -DEBUG_AddCVType_EnumFieldList( unsigned int typeno, unsigned char *list, int len ) -{ - struct datatype *dt = DEBUG_NewDataType( DT_ENUM, NULL ); - unsigned char *ptr = list; - - while ( ptr - list < len ) - { - union codeview_fieldtype *type = (union codeview_fieldtype *)ptr; - - if ( *ptr >= 0xf0 ) /* LF_PAD... */ - { - ptr += *ptr & 0x0f; - continue; - } - - switch ( type->generic.id ) - { - case LF_ENUMERATE: - { - int value, vlen = numeric_leaf( &value, &type->enumerate.value ); - unsigned char *name = (unsigned char *)&type->enumerate.value + vlen; - - DEBUG_AddStructElement( dt, terminate_string( name ), - NULL, value, 0 ); - - ptr += 2 + 2 + vlen + (1 + name[0]); - break; - } - - default: - DEBUG_Printf("Unhandled type %04x in ENUM field list\n", - type->generic.id); - return FALSE; - } - } - - return DEBUG_AddCVType( typeno, dt ); -} - -static int -DEBUG_AddCVType_StructFieldList( unsigned int typeno, unsigned char *list, int len ) -{ - struct datatype *dt = DEBUG_NewDataType( DT_STRUCT, NULL ); - unsigned char *ptr = list; - - while ( ptr - list < len ) - { - union codeview_fieldtype *type = (union codeview_fieldtype *)ptr; - - if ( *ptr >= 0xf0 ) /* LF_PAD... */ - { - ptr += *ptr & 0x0f; - continue; - } - - switch ( type->generic.id ) - { - case LF_BCLASS: - { - int offset, olen = numeric_leaf( &offset, &type->bclass.offset ); - - /* FIXME: ignored for now */ - - ptr += 2 + 2 + 2 + olen; - break; - } - - case LF_BCLASS_32: - { - int offset, olen = numeric_leaf( &offset, &type->bclass32.offset ); - - /* FIXME: ignored for now */ - - ptr += 2 + 2 + 4 + olen; - break; - } - - case LF_VBCLASS: - case LF_IVBCLASS: - { - int vbpoff, vbplen = numeric_leaf( &vbpoff, &type->vbclass.vbpoff ); - unsigned short int *p_vboff = (unsigned short int *)((char *)&type->vbclass.vbpoff + vbpoff); - int vpoff, vplen = numeric_leaf( &vpoff, p_vboff ); - - /* FIXME: ignored for now */ - - ptr += 2 + 2 + 2 + 2 + vbplen + vplen; - break; - } - - case LF_VBCLASS_32: - case LF_IVBCLASS_32: - { - int vbpoff, vbplen = numeric_leaf( &vbpoff, &type->vbclass32.vbpoff ); - unsigned short int *p_vboff = (unsigned short int *)((char *)&type->vbclass32.vbpoff + vbpoff); - int vpoff, vplen = numeric_leaf( &vpoff, p_vboff ); - - /* FIXME: ignored for now */ - - ptr += 2 + 2 + 4 + 4 + vbplen + vplen; - break; - } - - case LF_MEMBER: - { - int offset, olen = numeric_leaf( &offset, &type->member.offset ); - unsigned char *name = (unsigned char *)&type->member.offset + olen; - - struct datatype *subtype = DEBUG_GetCVType( type->member.type ); - int elem_size = subtype? DEBUG_GetObjectSize( subtype ) : 0; - - DEBUG_AddStructElement( dt, terminate_string( name ), - subtype, offset << 3, elem_size << 3 ); - - ptr += 2 + 2 + 2 + olen + (1 + name[0]); - break; - } - - case LF_MEMBER_32: - { - int offset, olen = numeric_leaf( &offset, &type->member32.offset ); - unsigned char *name = (unsigned char *)&type->member32.offset + olen; - - struct datatype *subtype = DEBUG_GetCVType( type->member32.type ); - int elem_size = subtype? DEBUG_GetObjectSize( subtype ) : 0; - - DEBUG_AddStructElement( dt, terminate_string( name ), - subtype, offset << 3, elem_size << 3 ); - - ptr += 2 + 2 + 4 + olen + (1 + name[0]); - break; - } - - case LF_STMEMBER: - /* FIXME: ignored for now */ - ptr += 2 + 2 + 2 + (1 + type->stmember.name[0]); - break; - - case LF_STMEMBER_32: - /* FIXME: ignored for now */ - ptr += 2 + 4 + 2 + (1 + type->stmember32.name[0]); - break; - - case LF_METHOD: - /* FIXME: ignored for now */ - ptr += 2 + 2 + 2 + (1 + type->method.name[0]); - break; - - case LF_METHOD_32: - /* FIXME: ignored for now */ - ptr += 2 + 2 + 4 + (1 + type->method32.name[0]); - break; - - case LF_NESTTYPE: - /* FIXME: ignored for now */ - ptr += 2 + 2 + (1 + type->nesttype.name[0]); - break; - - case LF_NESTTYPE_32: - /* FIXME: ignored for now */ - ptr += 2 + 2 + 4 + (1 + type->nesttype32.name[0]); - break; - - case LF_VFUNCTAB: - /* FIXME: ignored for now */ - ptr += 2 + 2; - break; - - case LF_VFUNCTAB_32: - /* FIXME: ignored for now */ - ptr += 2 + 2 + 4; - break; - - case LF_ONEMETHOD: - /* FIXME: ignored for now */ - switch ( (type->onemethod.attribute >> 2) & 7 ) - { - case 4: case 6: /* (pure) introducing virtual method */ - ptr += 2 + 2 + 2 + 4 + (1 + type->onemethod_virt.name[0]); - break; - - default: - ptr += 2 + 2 + 2 + (1 + type->onemethod.name[0]); - break; - } - break; - - case LF_ONEMETHOD_32: - /* FIXME: ignored for now */ - switch ( (type->onemethod32.attribute >> 2) & 7 ) - { - case 4: case 6: /* (pure) introducing virtual method */ - ptr += 2 + 2 + 4 + 4 + (1 + type->onemethod32_virt.name[0]); - break; - - default: - ptr += 2 + 2 + 4 + (1 + type->onemethod32.name[0]); - break; - } - break; - - default: - DEBUG_Printf("Unhandled type %04x in STRUCT field list\n", - type->generic.id); - return FALSE; - } - } - - return DEBUG_AddCVType( typeno, dt ); -} - -static int -DEBUG_AddCVType_Enum( unsigned int typeno, char *name, unsigned int fieldlist ) -{ - struct datatype *dt = DEBUG_NewDataType( DT_ENUM, name ); - struct datatype *list = DEBUG_GetCVType( fieldlist ); - - if ( list ) - if(DEBUG_CopyFieldlist( dt, list ) == FALSE) - return FALSE; - - return DEBUG_AddCVType( typeno, dt ); -} - -static int -DEBUG_AddCVType_Struct( unsigned int typeno, char *name, int structlen, unsigned int fieldlist ) -{ - struct datatype *dt = DEBUG_NewDataType( DT_STRUCT, name ); - struct datatype *list = DEBUG_GetCVType( fieldlist ); - - if ( list ) - { - DEBUG_SetStructSize( dt, structlen ); - if(DEBUG_CopyFieldlist( dt, list ) == FALSE) - return FALSE; - } - - return DEBUG_AddCVType( typeno, dt ); -} - -static int -DEBUG_ParseTypeTable( char *table, int len ) -{ - unsigned int curr_type = 0x1000; - char *ptr = table; - - while ( ptr - table < len ) - { - union codeview_type *type = (union codeview_type *) ptr; - int retv = TRUE; - - switch ( type->generic.id ) - { - case LF_POINTER: - retv = DEBUG_AddCVType_Pointer( curr_type, type->pointer.datatype ); - break; - case LF_POINTER_32: - retv = DEBUG_AddCVType_Pointer( curr_type, type->pointer32.datatype ); - break; - - case LF_ARRAY: - { - int arrlen, alen = numeric_leaf( &arrlen, &type->array.arrlen ); - unsigned char *name = (unsigned char *)&type->array.arrlen + alen; - - retv = DEBUG_AddCVType_Array( curr_type, terminate_string( name ), - type->array.elemtype, arrlen ); - break; - } - case LF_ARRAY_32: - { - int arrlen, alen = numeric_leaf( &arrlen, &type->array32.arrlen ); - unsigned char *name = (unsigned char *)&type->array32.arrlen + alen; - - retv = DEBUG_AddCVType_Array( curr_type, terminate_string( name ), - type->array32.elemtype, type->array32.arrlen ); - break; - } - - case LF_BITFIELD: - retv = DEBUG_AddCVType_Bitfield( curr_type, type->bitfield.bitoff, - type->bitfield.nbits, - type->bitfield.type ); - break; - case LF_BITFIELD_32: - retv = DEBUG_AddCVType_Bitfield( curr_type, type->bitfield32.bitoff, - type->bitfield32.nbits, - type->bitfield32.type ); - break; - - case LF_FIELDLIST: - case LF_FIELDLIST_32: - { - /* - * A 'field list' is a CodeView-specific data type which doesn't - * directly correspond to any high-level data type. It is used - * to hold the collection of members of a struct, class, union - * or enum type. The actual definition of that type will follow - * later, and refer to the field list definition record. - * - * As we don't have a field list type ourselves, we look ahead - * in the field list to try to find out whether this field list - * will be used for an enum or struct type, and create a dummy - * type of the corresponding sort. Later on, the definition of - * the 'real' type will copy the member / enumeration data. - */ - - char *list = type->fieldlist.list; - int len = (ptr + type->generic.len + 2) - list; - - if ( ((union codeview_fieldtype *)list)->generic.id == LF_ENUMERATE ) - retv = DEBUG_AddCVType_EnumFieldList( curr_type, list, len ); - else - retv = DEBUG_AddCVType_StructFieldList( curr_type, list, len ); - break; - } - - case LF_STRUCTURE: - case LF_CLASS: - { - int structlen, slen = numeric_leaf( &structlen, &type->structure.structlen ); - unsigned char *name = (unsigned char *)&type->structure.structlen + slen; - - retv = DEBUG_AddCVType_Struct( curr_type, terminate_string( name ), - structlen, type->structure.fieldlist ); - break; - } - case LF_STRUCTURE_32: - case LF_CLASS_32: - { - int structlen, slen = numeric_leaf( &structlen, &type->structure32.structlen ); - unsigned char *name = (unsigned char *)&type->structure32.structlen + slen; - - retv = DEBUG_AddCVType_Struct( curr_type, terminate_string( name ), - structlen, type->structure32.fieldlist ); - break; - } - - case LF_UNION: - { - int un_len, ulen = numeric_leaf( &un_len, &type->t_union.un_len ); - unsigned char *name = (unsigned char *)&type->t_union.un_len + ulen; - - retv = DEBUG_AddCVType_Struct( curr_type, terminate_string( name ), - un_len, type->t_union.fieldlist ); - break; - } - case LF_UNION_32: - { - int un_len, ulen = numeric_leaf( &un_len, &type->t_union32.un_len ); - unsigned char *name = (unsigned char *)&type->t_union32.un_len + ulen; - - retv = DEBUG_AddCVType_Struct( curr_type, terminate_string( name ), - un_len, type->t_union32.fieldlist ); - break; - } - - case LF_ENUM: - retv = DEBUG_AddCVType_Enum( curr_type, terminate_string( type->enumeration.name ), - type->enumeration.field ); - break; - case LF_ENUM_32: - retv = DEBUG_AddCVType_Enum( curr_type, terminate_string( type->enumeration32.name ), - type->enumeration32.field ); - break; - - default: - break; - } - - if ( !retv ) - return FALSE; - - curr_type++; - ptr += type->generic.len + 2; - } - - return TRUE; -} - - -/*======================================================================== - * Process CodeView line number information. - */ - -union any_size -{ - const char* c; - const short* s; - const int* i; - const unsigned int* ui; -}; - -struct startend -{ - unsigned int start; - unsigned int end; -}; - -struct codeview_linetab_hdr -{ - unsigned int nline; - unsigned int segno; - unsigned int start; - unsigned int end; - const char * sourcefile; - const unsigned short * linetab; - const unsigned int * offtab; -}; - -static struct codeview_linetab_hdr * -DEBUG_SnarfLinetab(const char * linetab, - int size) -{ - int file_segcount; - char filename[PATH_MAX]; - const unsigned int * filetab; - char * fn; - int i; - int k; - struct codeview_linetab_hdr * lt_hdr; - unsigned int * lt_ptr; - int nfile; - int nseg; - union any_size pnt; - union any_size pnt2; - struct startend * start; - int this_seg; - - /* - * Now get the important bits. - */ - pnt.c = linetab; - nfile = *pnt.s++; - nseg = *pnt.s++; - - filetab = (const unsigned int *) pnt.c; - - /* - * Now count up the number of segments in the file. - */ - nseg = 0; - for(i=0; imsc_dbg_info->nomap; - OMAP_DATA *omapp = module->msc_dbg_info->omapp; - int i; - - if ( !nomap || !omapp ) - return offset; - - /* FIXME: use binary search */ - for ( i = 0; i < nomap-1; i++ ) - if ( omapp[i].from <= offset && omapp[i+1].from > offset ) - return !omapp[i].to? 0 : omapp[i].to + (offset - omapp[i].from); - - return 0; -} - -static struct name_hash * -DEBUG_AddCVSymbol( DBG_MODULE *module, char *name, int namelen, - int type, unsigned int seg, unsigned int offset, - int size, int cookie, int flags, - struct codeview_linetab_hdr *linetab ) -{ - int nsect = module->msc_dbg_info->nsect; - PIMAGE_SECTION_HEADER sectp = module->msc_dbg_info->sectp; - - struct name_hash *symbol; - char symname[PATH_MAX]; - DBG_VALUE value; - - /* - * Some sanity checks - */ - - if ( !name || !namelen ) - return NULL; - - if ( !seg || seg > nsect ) - return NULL; - - /* - * Convert type, address, and symbol name - */ - value.type = type? DEBUG_GetCVType( type ) : NULL; - value.cookie = cookie; - - value.addr.seg = 0; - value.addr.off = (unsigned int) module->load_addr + - DEBUG_MapCVOffset( module, sectp[seg-1].VirtualAddress + offset ); - - memcpy( symname, name, namelen ); - symname[namelen] = '\0'; - - - /* - * Check whether we have line number information - */ - if ( linetab ) - { - for ( ; linetab->linetab; linetab++ ) - if ( linetab->segno == seg - && linetab->start <= offset - && linetab->end > offset ) - break; - - if ( !linetab->linetab ) - linetab = NULL; - } - - - /* - * Create Wine symbol record - */ - symbol = DEBUG_AddSymbol( symname, &value, - linetab? linetab->sourcefile : NULL, flags ); - - if ( size ) - DEBUG_SetSymbolSize( symbol, size ); - - - /* - * Add line numbers if found - */ - if ( linetab ) - { - unsigned int i; - for ( i = 0; i < linetab->nline; i++ ) - if ( linetab->offtab[i] >= offset - && linetab->offtab[i] < offset + size ) - { - DEBUG_AddLineNumber( symbol, linetab->linetab[i], - linetab->offtab[i] - offset ); - } - } - - return symbol; -} - -static struct wine_locals * -DEBUG_AddCVLocal( struct name_hash *func, char *name, int namelen, - int type, int offset ) -{ - struct wine_locals *local; - char symname[PATH_MAX]; - - memcpy( symname, name, namelen ); - symname[namelen] = '\0'; - - local = DEBUG_AddLocal( func, 0, offset, 0, 0, symname ); - DEBUG_SetLocalSymbolType( local, DEBUG_GetCVType( type ) ); - - return local; -} - -static int -DEBUG_SnarfCodeView( DBG_MODULE *module, const BYTE* root, int offset, int size, - struct codeview_linetab_hdr *linetab ) -{ - struct name_hash *curr_func = NULL; - int i, length; - - - /* - * Loop over the different types of records and whenever we - * find something we are interested in, record it and move on. - */ - for ( i = offset; i < size; i += length ) - { - union codeview_symbol *sym = (union codeview_symbol *)(root + i); - length = sym->generic.len + 2; - - switch ( sym->generic.id ) - { - /* - * Global and local data symbols. We don't associate these - * with any given source file. - */ - case S_GDATA: - case S_LDATA: - case S_PUB: - DEBUG_AddCVSymbol( module, sym->data.name, sym->data.namelen, - sym->data.symtype, sym->data.seg, - sym->data.offset, 0, - DV_TARGET, SYM_WIN32 | SYM_DATA, NULL ); - break; - case S_GDATA_32: - case S_LDATA_32: - case S_PUB_32: - DEBUG_AddCVSymbol( module, sym->data32.name, sym->data32.namelen, - sym->data32.symtype, sym->data32.seg, - sym->data32.offset, 0, - DV_TARGET, SYM_WIN32 | SYM_DATA, NULL ); - break; - - /* - * Sort of like a global function, but it just points - * to a thunk, which is a stupid name for what amounts to - * a PLT slot in the normal jargon that everyone else uses. - */ - case S_THUNK: - DEBUG_AddCVSymbol( module, sym->thunk.name, sym->thunk.namelen, - 0, sym->thunk.segment, - sym->thunk.offset, sym->thunk.thunk_len, - DV_TARGET, SYM_WIN32 | SYM_FUNC, NULL ); - break; - - /* - * Global and static functions. - */ - case S_GPROC: - case S_LPROC: - DEBUG_Normalize( curr_func ); - - curr_func = DEBUG_AddCVSymbol( module, sym->proc.name, sym->proc.namelen, - sym->proc.proctype, sym->proc.segment, - sym->proc.offset, sym->proc.proc_len, - DV_TARGET, SYM_WIN32 | SYM_FUNC, linetab ); - - DEBUG_SetSymbolBPOff( curr_func, sym->proc.debug_start ); - break; - case S_GPROC_32: - case S_LPROC_32: - DEBUG_Normalize( curr_func ); - - curr_func = DEBUG_AddCVSymbol( module, sym->proc32.name, sym->proc32.namelen, - sym->proc32.proctype, sym->proc32.segment, - sym->proc32.offset, sym->proc32.proc_len, - DV_TARGET, SYM_WIN32 | SYM_FUNC, linetab ); - - DEBUG_SetSymbolBPOff( curr_func, sym->proc32.debug_start ); - break; - - - /* - * Function parameters and stack variables. - */ - case S_BPREL: - DEBUG_AddCVLocal( curr_func, sym->stack.name, sym->stack.namelen, - sym->stack.symtype, sym->stack.offset ); - break; - case S_BPREL_32: - DEBUG_AddCVLocal( curr_func, sym->stack32.name, sym->stack32.namelen, - sym->stack32.symtype, sym->stack32.offset ); - break; - - - /* - * These are special, in that they are always followed by an - * additional length-prefixed string which is *not* included - * into the symbol length count. We need to skip it. - */ - case S_PROCREF: - case S_DATAREF: - case S_LPROCREF: - { - LPBYTE name = (LPBYTE)sym + length; - length += (*name + 1 + 3) & ~3; - break; - } - } - } - - DEBUG_Normalize( curr_func ); - - if ( linetab ) DBG_free(linetab); - return TRUE; -} - - - -/*======================================================================== - * Process PDB file. - */ - -#pragma pack(1) -typedef struct _PDB_FILE -{ - DWORD size; - DWORD unknown; - -} PDB_FILE, *PPDB_FILE; - -typedef struct _PDB_HEADER -{ - CHAR ident[40]; - DWORD signature; - DWORD blocksize; - WORD freelist; - WORD total_alloc; - PDB_FILE toc; - WORD toc_block[ 1 ]; - -} PDB_HEADER, *PPDB_HEADER; - -typedef struct _PDB_TOC -{ - DWORD nFiles; - PDB_FILE file[ 1 ]; - -} PDB_TOC, *PPDB_TOC; - -typedef struct _PDB_ROOT -{ - DWORD version; - DWORD TimeDateStamp; - DWORD unknown; - DWORD cbNames; - CHAR names[ 1 ]; - -} PDB_ROOT, *PPDB_ROOT; - -typedef struct _PDB_TYPES_OLD -{ - DWORD version; - WORD first_index; - WORD last_index; - DWORD type_size; - WORD file; - WORD pad; - -} PDB_TYPES_OLD, *PPDB_TYPES_OLD; - -typedef struct _PDB_TYPES -{ - DWORD version; - DWORD type_offset; - DWORD first_index; - DWORD last_index; - DWORD type_size; - WORD file; - WORD pad; - DWORD hash_size; - DWORD hash_base; - DWORD hash_offset; - DWORD hash_len; - DWORD search_offset; - DWORD search_len; - DWORD unknown_offset; - DWORD unknown_len; - -} PDB_TYPES, *PPDB_TYPES; - -typedef struct _PDB_SYMBOL_RANGE -{ - WORD segment; - WORD pad1; - DWORD offset; - DWORD size; - DWORD characteristics; - WORD index; - WORD pad2; - -} PDB_SYMBOL_RANGE, *PPDB_SYMBOL_RANGE; - -typedef struct _PDB_SYMBOL_RANGE_EX -{ - WORD segment; - WORD pad1; - DWORD offset; - DWORD size; - DWORD characteristics; - WORD index; - WORD pad2; - DWORD timestamp; - DWORD unknown; - -} PDB_SYMBOL_RANGE_EX, *PPDB_SYMBOL_RANGE_EX; - -typedef struct _PDB_SYMBOL_FILE -{ - DWORD unknown1; - PDB_SYMBOL_RANGE range; - WORD flag; - WORD file; - DWORD symbol_size; - DWORD lineno_size; - DWORD unknown2; - DWORD nSrcFiles; - DWORD attribute; - CHAR filename[ 1 ]; - -} PDB_SYMBOL_FILE, *PPDB_SYMBOL_FILE; - -typedef struct _PDB_SYMBOL_FILE_EX -{ - DWORD unknown1; - PDB_SYMBOL_RANGE_EX range; - WORD flag; - WORD file; - DWORD symbol_size; - DWORD lineno_size; - DWORD unknown2; - DWORD nSrcFiles; - DWORD attribute; - DWORD reserved[ 2 ]; - CHAR filename[ 1 ]; - -} PDB_SYMBOL_FILE_EX, *PPDB_SYMBOL_FILE_EX; - -typedef struct _PDB_SYMBOL_SOURCE -{ - WORD nModules; - WORD nSrcFiles; - WORD table[ 1 ]; - -} PDB_SYMBOL_SOURCE, *PPDB_SYMBOL_SOURCE; - -typedef struct _PDB_SYMBOL_IMPORT -{ - DWORD unknown1; - DWORD unknown2; - DWORD TimeDateStamp; - DWORD nRequests; - CHAR filename[ 1 ]; - -} PDB_SYMBOL_IMPORT, *PPDB_SYMBOL_IMPORT; - -typedef struct _PDB_SYMBOLS_OLD -{ - WORD hash1_file; - WORD hash2_file; - WORD gsym_file; - WORD pad; - DWORD module_size; - DWORD offset_size; - DWORD hash_size; - DWORD srcmodule_size; - -} PDB_SYMBOLS_OLD, *PPDB_SYMBOLS_OLD; - -typedef struct _PDB_SYMBOLS -{ - DWORD signature; - DWORD version; - DWORD unknown; - DWORD hash1_file; - DWORD hash2_file; - DWORD gsym_file; - DWORD module_size; - DWORD offset_size; - DWORD hash_size; - DWORD srcmodule_size; - DWORD pdbimport_size; - DWORD resvd[ 5 ]; - -} PDB_SYMBOLS, *PPDB_SYMBOLS; -#pragma pack() - - -static void *pdb_read( LPBYTE image, WORD *block_list, int size ) -{ - PPDB_HEADER pdb = (PPDB_HEADER)image; - int i, nBlocks; - LPBYTE buffer; - - if ( !size ) return NULL; - - nBlocks = (size + pdb->blocksize-1) / pdb->blocksize; - buffer = DBG_alloc( nBlocks * pdb->blocksize ); - - for ( i = 0; i < nBlocks; i++ ) - memcpy( buffer + i*pdb->blocksize, - image + block_list[i]*pdb->blocksize, pdb->blocksize ); - - return buffer; -} - -static void *pdb_read_file( LPBYTE image, PPDB_TOC toc, DWORD fileNr ) -{ - PPDB_HEADER pdb = (PPDB_HEADER)image; - WORD *block_list; - DWORD i; - - if ( !toc || fileNr >= toc->nFiles ) - return NULL; - - block_list = (WORD *) &toc->file[ toc->nFiles ]; - for ( i = 0; i < fileNr; i++ ) - block_list += (toc->file[i].size + pdb->blocksize-1) / pdb->blocksize; - - return pdb_read( image, block_list, toc->file[fileNr].size ); -} - -static void pdb_free( void *buffer ) -{ - DBG_free( buffer ); -} - -static void pdb_convert_types_header( PDB_TYPES *types, char *image ) -{ - memset( types, 0, sizeof(PDB_TYPES) ); - if ( !image ) return; - - if ( *(DWORD *)image < 19960000 ) /* FIXME: correct version? */ - { - /* Old version of the types record header */ - PDB_TYPES_OLD *old = (PDB_TYPES_OLD *)image; - types->version = old->version; - types->type_offset = sizeof(PDB_TYPES_OLD); - types->type_size = old->type_size; - types->first_index = old->first_index; - types->last_index = old->last_index; - types->file = old->file; - } - else - { - /* New version of the types record header */ - *types = *(PDB_TYPES *)image; - } -} - -static void pdb_convert_symbols_header( PDB_SYMBOLS *symbols, - int *header_size, char *image ) -{ - memset( symbols, 0, sizeof(PDB_SYMBOLS) ); - if ( !image ) return; - - if ( *(DWORD *)image != 0xffffffff ) - { - /* Old version of the symbols record header */ - PDB_SYMBOLS_OLD *old = (PDB_SYMBOLS_OLD *)image; - symbols->version = 0; - symbols->module_size = old->module_size; - symbols->offset_size = old->offset_size; - symbols->hash_size = old->hash_size; - symbols->srcmodule_size = old->srcmodule_size; - symbols->pdbimport_size = 0; - symbols->hash1_file = old->hash1_file; - symbols->hash2_file = old->hash2_file; - symbols->gsym_file = old->gsym_file; - - *header_size = sizeof(PDB_SYMBOLS_OLD); - } - else - { - /* New version of the symbols record header */ - *symbols = *(PDB_SYMBOLS *)image; - - *header_size = sizeof(PDB_SYMBOLS); - } -} - -static enum DbgInfoLoad DEBUG_ProcessPDBFile( DBG_MODULE *module, - const char *filename, DWORD timestamp ) -{ - enum DbgInfoLoad dil = DIL_ERROR; - HANDLE hFile, hMap; - char *image = NULL; - PDB_HEADER *pdb = NULL; - PDB_TOC *toc = NULL; - PDB_ROOT *root = NULL; - char *types_image = NULL; - char *symbols_image = NULL; - PDB_TYPES types; - PDB_SYMBOLS symbols; - int header_size = 0; - char *modimage, *file; - - WINE_TRACE("Processing PDB file %s\n", filename); - - /* - * Open and map() .PDB file - */ - image = DEBUG_MapDebugInfoFile( filename, 0, 0, &hFile, &hMap ); - if ( !image ) - { - WINE_ERR("-Unable to peruse .PDB file %s\n", filename); - goto leave; - } - - /* - * Read in TOC and well-known files - */ - - pdb = (PPDB_HEADER)image; - toc = pdb_read( image, pdb->toc_block, pdb->toc.size ); - root = pdb_read_file( image, toc, 1 ); - types_image = pdb_read_file( image, toc, 2 ); - symbols_image = pdb_read_file( image, toc, 3 ); - - pdb_convert_types_header( &types, types_image ); - pdb_convert_symbols_header( &symbols, &header_size, symbols_image ); - - if ( !root ) - { - WINE_ERR("-Unable to get root from .PDB file %s\n", filename); - goto leave; - } - - /* - * Check for unknown versions - */ - - switch ( root->version ) - { - case 19950623: /* VC 4.0 */ - case 19950814: - case 19960307: /* VC 5.0 */ - case 19970604: /* VC 6.0 */ - break; - default: - WINE_ERR("-Unknown root block version %ld\n", root->version); - } - - switch ( types.version ) - { - case 19950410: /* VC 4.0 */ - case 19951122: - case 19961031: /* VC 5.0 / 6.0 */ - break; - default: - WINE_ERR("-Unknown type info version %ld\n", types.version); - } - - switch ( symbols.version ) - { - case 0: /* VC 4.0 */ - case 19960307: /* VC 5.0 */ - case 19970606: /* VC 6.0 */ - break; - default: - WINE_ERR("-Unknown symbol info version %ld\n", symbols.version); - } - - - /* - * Check .PDB time stamp - */ - - if ( root->TimeDateStamp != timestamp ) - { - WINE_ERR("-Wrong time stamp of .PDB file %s (0x%08lx, 0x%08lx)\n", - filename, root->TimeDateStamp, timestamp ); - } - - /* - * Read type table - */ - - DEBUG_ParseTypeTable( types_image + types.type_offset, types.type_size ); - - /* - * Read type-server .PDB imports - */ - - if ( symbols.pdbimport_size ) - { - /* FIXME */ - WINE_ERR("-Type server .PDB imports ignored!\n"); - } - - /* - * Read global symbol table - */ - - modimage = pdb_read_file( image, toc, symbols.gsym_file ); - if ( modimage ) - { - DEBUG_SnarfCodeView( module, modimage, 0, - toc->file[symbols.gsym_file].size, NULL ); - pdb_free( modimage ); - } - - /* - * Read per-module symbol / linenumber tables - */ - - file = symbols_image + header_size; - while ( file - symbols_image < header_size + symbols.module_size ) - { - int file_nr, file_index, symbol_size, lineno_size; - char *file_name; - - if ( symbols.version < 19970000 ) - { - PDB_SYMBOL_FILE *sym_file = (PDB_SYMBOL_FILE *) file; - file_nr = sym_file->file; - file_name = sym_file->filename; - file_index = sym_file->range.index; - symbol_size = sym_file->symbol_size; - lineno_size = sym_file->lineno_size; - } - else - { - PDB_SYMBOL_FILE_EX *sym_file = (PDB_SYMBOL_FILE_EX *) file; - file_nr = sym_file->file; - file_name = sym_file->filename; - file_index = sym_file->range.index; - symbol_size = sym_file->symbol_size; - lineno_size = sym_file->lineno_size; - } - - modimage = pdb_read_file( image, toc, file_nr ); - if ( modimage ) - { - struct codeview_linetab_hdr *linetab = NULL; - - if ( lineno_size ) - linetab = DEBUG_SnarfLinetab( modimage + symbol_size, lineno_size ); - - if ( symbol_size ) - DEBUG_SnarfCodeView( module, modimage, sizeof(DWORD), - symbol_size, linetab ); - - pdb_free( modimage ); - } - - file_name += strlen(file_name) + 1; - file = (char *)( (DWORD)(file_name + strlen(file_name) + 1 + 3) & ~3 ); - } - - dil = DIL_LOADED; - - leave: - - /* - * Cleanup - */ - - DEBUG_ClearTypeTable(); - - if ( symbols_image ) pdb_free( symbols_image ); - if ( types_image ) pdb_free( types_image ); - if ( root ) pdb_free( root ); - if ( toc ) pdb_free( toc ); - - DEBUG_UnmapDebugInfoFile(hFile, hMap, image); - - return dil; -} - - - - -/*======================================================================== - * Process CodeView debug information. - */ - -#define CODEVIEW_NB09_SIG ( 'N' | ('B' << 8) | ('0' << 16) | ('9' << 24) ) -#define CODEVIEW_NB10_SIG ( 'N' | ('B' << 8) | ('1' << 16) | ('0' << 24) ) -#define CODEVIEW_NB11_SIG ( 'N' | ('B' << 8) | ('1' << 16) | ('1' << 24) ) - -typedef struct _CODEVIEW_HEADER -{ - DWORD dwSignature; - DWORD lfoDirectory; - -} CODEVIEW_HEADER, *PCODEVIEW_HEADER; - -typedef struct _CODEVIEW_PDB_DATA -{ - DWORD timestamp; - DWORD unknown; - CHAR name[ 1 ]; - -} CODEVIEW_PDB_DATA, *PCODEVIEW_PDB_DATA; - -typedef struct _CV_DIRECTORY_HEADER -{ - WORD cbDirHeader; - WORD cbDirEntry; - DWORD cDir; - DWORD lfoNextDir; - DWORD flags; - -} CV_DIRECTORY_HEADER, *PCV_DIRECTORY_HEADER; - -typedef struct _CV_DIRECTORY_ENTRY -{ - WORD subsection; - WORD iMod; - DWORD lfo; - DWORD cb; - -} CV_DIRECTORY_ENTRY, *PCV_DIRECTORY_ENTRY; - - -#define sstAlignSym 0x125 -#define sstSrcModule 0x127 - - -static enum DbgInfoLoad DEBUG_ProcessCodeView( DBG_MODULE *module, const BYTE* root ) -{ - PCODEVIEW_HEADER cv = (PCODEVIEW_HEADER)root; - enum DbgInfoLoad dil = DIL_ERROR; - - switch ( cv->dwSignature ) - { - case CODEVIEW_NB09_SIG: - case CODEVIEW_NB11_SIG: - { - PCV_DIRECTORY_HEADER hdr = (PCV_DIRECTORY_HEADER)(root + cv->lfoDirectory); - PCV_DIRECTORY_ENTRY ent, prev, next; - unsigned int i; - - ent = (PCV_DIRECTORY_ENTRY)((LPBYTE)hdr + hdr->cbDirHeader); - for ( i = 0; i < hdr->cDir; i++, ent = next ) - { - next = (i == hdr->cDir-1)? NULL : - (PCV_DIRECTORY_ENTRY)((LPBYTE)ent + hdr->cbDirEntry); - prev = (i == 0)? NULL : - (PCV_DIRECTORY_ENTRY)((LPBYTE)ent - hdr->cbDirEntry); - - if ( ent->subsection == sstAlignSym ) - { - /* - * Check the next and previous entry. If either is a - * sstSrcModule, it contains the line number info for - * this file. - * - * FIXME: This is not a general solution! - */ - struct codeview_linetab_hdr *linetab = NULL; - - if ( next && next->iMod == ent->iMod - && next->subsection == sstSrcModule ) - linetab = DEBUG_SnarfLinetab( root + next->lfo, next->cb ); - - if ( prev && prev->iMod == ent->iMod - && prev->subsection == sstSrcModule ) - linetab = DEBUG_SnarfLinetab( root + prev->lfo, prev->cb ); - - - DEBUG_SnarfCodeView( module, root + ent->lfo, sizeof(DWORD), - ent->cb, linetab ); - } - } - - dil = DIL_LOADED; - break; - } - - case CODEVIEW_NB10_SIG: - { - PCODEVIEW_PDB_DATA pdb = (PCODEVIEW_PDB_DATA)(cv + 1); - - dil = DEBUG_ProcessPDBFile( module, pdb->name, pdb->timestamp ); - break; - } - - default: - WINE_ERR("Unknown CODEVIEW signature %08lX in module %s\n", - cv->dwSignature, module->module_name ); - break; - } - - return dil; -} - - -/*======================================================================== - * Process debug directory. - */ -enum DbgInfoLoad DEBUG_ProcessDebugDirectory( DBG_MODULE *module, const BYTE* file_map, - PIMAGE_DEBUG_DIRECTORY dbg, int nDbg ) -{ - enum DbgInfoLoad dil; - int i; - __TRY { - dil = DIL_ERROR; - /* First, watch out for OMAP data */ - for ( i = 0; i < nDbg; i++ ) - { - if ( dbg[i].Type == IMAGE_DEBUG_TYPE_OMAP_FROM_SRC ) - { - module->msc_dbg_info->nomap = dbg[i].SizeOfData / sizeof(OMAP_DATA); - module->msc_dbg_info->omapp = (OMAP_DATA *)(file_map + dbg[i].PointerToRawData); - break; - } - } - - /* Now, try to parse CodeView debug info */ - for ( i = 0; dil != DIL_LOADED && i < nDbg; i++ ) - { - if ( dbg[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW ) - { - dil = DEBUG_ProcessCodeView( module, file_map + dbg[i].PointerToRawData ); - } - } - - /* If not found, try to parse COFF debug info */ - for ( i = 0; dil != DIL_LOADED && i < nDbg; i++ ) - { - if ( dbg[i].Type == IMAGE_DEBUG_TYPE_COFF ) - dil = DEBUG_ProcessCoff( module, file_map + dbg[i].PointerToRawData ); - } -#if 0 - /* FIXME: this should be supported... this is the debug information for - * functions compiled without a frame pointer (FPO = frame pointer omission) - * the associated data helps finding out the relevant information - */ - for ( i = 0; i < nDbg; i++ ) - if ( dbg[i].Type == IMAGE_DEBUG_TYPE_FPO ) - DEBUG_Printf("This guy has FPO information\n"); - -#define FRAME_FPO 0 -#define FRAME_TRAP 1 -#define FRAME_TSS 2 - -typedef struct _FPO_DATA { - DWORD ulOffStart; /* offset 1st byte of function code */ - DWORD cbProcSize; /* # bytes in function */ - DWORD cdwLocals; /* # bytes in locals/4 */ - WORD cdwParams; /* # bytes in params/4 */ - - WORD cbProlog : 8; /* # bytes in prolog */ - WORD cbRegs : 3; /* # regs saved */ - WORD fHasSEH : 1; /* TRUE if SEH in func */ - WORD fUseBP : 1; /* TRUE if EBP has been allocated */ - WORD reserved : 1; /* reserved for future use */ - WORD cbFrame : 2; /* frame type */ -} FPO_DATA; -#endif - } - __EXCEPT(page_fault) - { - return DIL_ERROR; - } - __ENDTRY - return dil; -} - - diff --git a/programs/winedbg/pe.c b/programs/winedbg/pe.c deleted file mode 100644 index ef021f6e895..00000000000 --- a/programs/winedbg/pe.c +++ /dev/null @@ -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 -#include -#include -#ifdef HAVE_UNISTD_H -# include -#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); -} diff --git a/programs/winedbg/registers.c b/programs/winedbg/registers.c deleted file mode 100644 index 0bbeb78caba..00000000000 --- a/programs/winedbg/registers.c +++ /dev/null @@ -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 -#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); -} diff --git a/programs/winedbg/source.c b/programs/winedbg/source.c index e6b43453c22..ad287390569 100644 --- a/programs/winedbg/source.c +++ b/programs/winedbg/source.c @@ -22,93 +22,76 @@ #include #include -#include -#ifdef HAVE_SYS_MMAN_H -#include -#endif -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#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;ihandle, lin, NULL, &il)) + source_list(&il, NULL, nlines); } diff --git a/programs/winedbg/stabs.c b/programs/winedbg/stabs.c deleted file mode 100644 index dd0a8d7e5f7..00000000000 --- a/programs/winedbg/stabs.c +++ /dev/null @@ -1,1201 +0,0 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ - -/* - * File stabs.c - read stabs information from the wine executable itself. - * - * Copyright (C) 1996, Eric Youngdale. - * 1999-2003 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 - * - * - * Maintenance Information - * ----------------------- - * - * For documentation on the stabs format see for example - * The "stabs" debug format - * by Julia Menapace, Jim Kingdon, David Mackenzie - * of Cygnus Support - * available (hopefully) from http:\\sources.redhat.com\gdb\onlinedocs - */ - -#include "config.h" - -#include -#include -#include -#ifdef HAVE_SYS_MMAN_H -#include -#endif -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#ifndef PATH_MAX -#define PATH_MAX MAX_PATH -#endif - -#include "debugger.h" - -#if defined(__svr4__) || defined(__sun) -#define __ELF__ -#endif - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winedbg_stabs); - -#ifndef N_UNDF -#define N_UNDF 0x00 -#endif - -#ifndef STN_UNDEF -# define STN_UNDEF 0 -#endif - -#define N_GSYM 0x20 -#define N_FUN 0x24 -#define N_STSYM 0x26 -#define N_LCSYM 0x28 -#define N_MAIN 0x2a -#define N_ROSYM 0x2c -#define N_OPT 0x3c -#define N_RSYM 0x40 -#define N_SLINE 0x44 -#define N_SO 0x64 -#define N_LSYM 0x80 -#define N_BINCL 0x82 -#define N_SOL 0x84 -#define N_PSYM 0xa0 -#define N_EINCL 0xa2 -#define N_LBRAC 0xc0 -#define N_EXCL 0xc2 -#define N_RBRAC 0xe0 - -struct stab_nlist { - union { - char *n_name; - struct stab_nlist *n_next; - long n_strx; - } n_un; - unsigned char n_type; - char n_other; - short n_desc; - unsigned long n_value; -}; - -static void stab_strcpy(char * dest, int sz, const char * source) -{ - /* - * A strcpy routine that stops when we hit the ':' character. - * Faster than copying the whole thing, and then nuking the - * ':'. - */ - while(*source != '\0' && *source != ':' && sz-- > 0) - *dest++ = *source++; - *dest = '\0'; - assert(sz > 0); -} - -typedef struct { - char* name; - unsigned long value; - int idx; - struct datatype** vector; - int nrofentries; -} include_def; - -#define MAX_INCLUDES 5120 - -static include_def* include_defs = NULL; -static int num_include_def = 0; -static int num_alloc_include_def = 0; -static int cu_include_stack[MAX_INCLUDES]; -static int cu_include_stk_idx = 0; -static struct datatype** cu_vector = NULL; -static int cu_nrofentries = 0; - -static -int -DEBUG_CreateInclude(const char* file, unsigned long val) -{ - if (num_include_def == num_alloc_include_def) - { - num_alloc_include_def += 256; - include_defs = DBG_realloc(include_defs, sizeof(include_defs[0])*num_alloc_include_def); - memset(include_defs+num_include_def, 0, sizeof(include_defs[0])*256); - } - include_defs[num_include_def].name = DBG_strdup(file); - include_defs[num_include_def].value = val; - include_defs[num_include_def].vector = NULL; - include_defs[num_include_def].nrofentries = 0; - - return num_include_def++; -} - -static -int -DEBUG_FindInclude(const char* file, unsigned long val) -{ - int i; - - for (i = 0; i < num_include_def; i++) - { - if (val == include_defs[i].value && - strcmp(file, include_defs[i].name) == 0) - return i; - } - return -1; -} - -static -int -DEBUG_AddInclude(int idx) -{ - ++cu_include_stk_idx; - - /* is this happen, just bump MAX_INCLUDES */ - /* we could also handle this as another dynarray */ - assert(cu_include_stk_idx < MAX_INCLUDES); - - cu_include_stack[cu_include_stk_idx] = idx; - return cu_include_stk_idx; -} - -static -void -DEBUG_ResetIncludes(void) -{ - /* - * The datatypes that we would need to use are reset when - * we start a new file. (at least the ones in filenr == 0 - */ - cu_include_stk_idx = 0;/* keep 0 as index for the .c file itself */ - memset(cu_vector, 0, sizeof(cu_vector[0]) * cu_nrofentries); -} - -static -void -DEBUG_FreeIncludes(void) -{ - int i; - - DEBUG_ResetIncludes(); - - for (i = 0; i < num_include_def; i++) - { - DBG_free(include_defs[i].name); - DBG_free(include_defs[i].vector); - } - DBG_free(include_defs); - include_defs = NULL; - num_include_def = 0; - num_alloc_include_def = 0; - DBG_free(cu_vector); - cu_vector = NULL; - cu_nrofentries = 0; -} - -static -struct datatype** -DEBUG_FileSubNr2StabEnum(int filenr, int subnr) -{ - struct datatype** ret; - - WINE_TRACE("creating type id for (%d,%d)\n", filenr, subnr); - - /* FIXME: I could perhaps create a dummy include_def for each compilation - * unit which would allow not to handle those two cases separately - */ - if (filenr == 0) - { - if (cu_nrofentries <= subnr) - { - cu_vector = DBG_realloc(cu_vector, sizeof(cu_vector[0])*(subnr+1)); - memset(cu_vector+cu_nrofentries, 0, sizeof(cu_vector[0])*(subnr+1-cu_nrofentries)); - cu_nrofentries = subnr + 1; - } - ret = &cu_vector[subnr]; - } - else - { - include_def* idef; - - assert(filenr <= cu_include_stk_idx); - - idef = &include_defs[cu_include_stack[filenr]]; - - if (idef->nrofentries <= subnr) - { - idef->vector = DBG_realloc(idef->vector, sizeof(idef->vector[0])*(subnr+1)); - memset(idef->vector + idef->nrofentries, 0, sizeof(idef->vector[0])*(subnr+1-idef->nrofentries)); - idef->nrofentries = subnr + 1; - } - ret = &idef->vector[subnr]; - } - WINE_TRACE("(%d,%d) is %p\n",filenr,subnr,ret); - return ret; -} - -static -struct datatype** -DEBUG_ReadTypeEnum(LPCSTR *x) -{ - int filenr,subnr; - - if (**x=='(') { - (*x)++; /* '(' */ - filenr=strtol(*x,(char**)x,10); /* */ - (*x)++; /* ',' */ - subnr=strtol(*x,(char**)x,10); /* */ - (*x)++; /* ')' */ - } else { - filenr = 0; - subnr = strtol(*x,(char**)x,10); /* */ - } - return DEBUG_FileSubNr2StabEnum(filenr,subnr); -} - -/*#define PTS_DEBUG*/ -struct ParseTypedefData -{ - const char* ptr; - char buf[1024]; - int idx; -#ifdef PTS_DEBUG - struct PTS_Error - { - char* ptr; - unsigned line; - } errors[16]; - int err_idx; -#endif -}; - -#ifdef PTS_DEBUG -static void PTS_Push(struct ParseTypedefData* ptd, unsigned line) -{ - assert(ptd->err_idx < sizeof(ptd->errors) / sizeof(ptd->errors[0])); - ptd->errors[ptd->err_idx].line = line; - ptd->errors[ptd->err_idx].ptr = ptd->ptr; - ptd->err_idx++; -} -#define PTS_ABORTIF(ptd, t) do { if (t) { PTS_Push((ptd), __LINE__); return -1;} } while (0) -#else -#define PTS_ABORTIF(ptd, t) do { if (t) return -1; } while (0) -#endif - -static int DEBUG_PTS_ReadTypedef(struct ParseTypedefData* ptd, const char* typename, - struct datatype** dt); - -static int DEBUG_PTS_ReadID(struct ParseTypedefData* ptd) -{ - const char* first = ptd->ptr; - unsigned int len; - - PTS_ABORTIF(ptd, (ptd->ptr = strchr(ptd->ptr, ':')) == NULL); - len = ptd->ptr - first; - PTS_ABORTIF(ptd, len >= sizeof(ptd->buf) - ptd->idx); - memcpy(ptd->buf + ptd->idx, first, len); - ptd->buf[ptd->idx + len] = '\0'; - ptd->idx += len + 1; - ptd->ptr++; /* ':' */ - return 0; -} - -static int DEBUG_PTS_ReadNum(struct ParseTypedefData* ptd, int* v) -{ - char* last; - - *v = strtol(ptd->ptr, &last, 10); - PTS_ABORTIF(ptd, last == ptd->ptr); - ptd->ptr = last; - return 0; -} - -static int DEBUG_PTS_ReadTypeReference(struct ParseTypedefData* ptd, - int* filenr, int* subnr) -{ - if (*ptd->ptr == '(') { - /* '(' ',' ')' */ - ptd->ptr++; - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, filenr) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ','); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, subnr) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ')'); - } else { - *filenr = 0; - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, subnr) == -1); - } - return 0; -} - -static int DEBUG_PTS_ReadRange(struct ParseTypedefData* ptd, struct datatype** dt, - int* lo, int* hi) -{ - /* type ';' ';' ';' */ - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, dt) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */ - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, lo) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */ - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, hi) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */ - return 0; -} - -static inline int DEBUG_PTS_ReadMethodInfo(struct ParseTypedefData* ptd) -{ - struct datatype* dt; - char* tmp; - char mthd; - - do - { - /* get type of return value */ - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &dt) == -1); - if (*ptd->ptr == ';') ptd->ptr++; - - /* get types of parameters */ - if (*ptd->ptr == ':') - { - PTS_ABORTIF(ptd, !(tmp = strchr(ptd->ptr + 1, ';'))); - ptd->ptr = tmp + 1; - } - PTS_ABORTIF(ptd, !(*ptd->ptr >= '0' && *ptd->ptr <= '9')); - ptd->ptr++; - PTS_ABORTIF(ptd, !(ptd->ptr[0] >= 'A' && *ptd->ptr <= 'D')); - mthd = *++ptd->ptr; - PTS_ABORTIF(ptd, mthd != '.' && mthd != '?' && mthd != '*'); - ptd->ptr++; - if (mthd == '*') - { - int ofs; - struct datatype* dt; - - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &ofs) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &dt) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); - } - } while (*ptd->ptr != ';'); - ptd->ptr++; - - return 0; -} - -static inline int DEBUG_PTS_ReadAggregate(struct ParseTypedefData* ptd, - struct datatype* sdt) -{ - int sz, ofs; - struct datatype* adt; - struct datatype* dt = NULL; - int idx; - int doadd; - - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &sz) == -1); - - doadd = DEBUG_SetStructSize(sdt, sz); - if (*ptd->ptr == '!') /* C++ inheritence */ - { - int num_classes; - char tmp[256]; - - ptd->ptr++; - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &num_classes) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ','); - while (--num_classes >= 0) - { - ptd->ptr += 2; /* skip visibility and inheritence */ - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &ofs) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ','); - - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &adt) == -1); - - snprintf(tmp, sizeof(tmp), "__inherited_class_%s", DEBUG_GetName(adt)); - /* FIXME: DEBUG_GetObjectSize will not always work, especially when adt - * has just been seen as a forward definition and not the real stuff yet. - * As we don't use much the size of members in structs, this may not - * be much of a problem - */ - if (doadd) DEBUG_AddStructElement(sdt, tmp, adt, ofs, DEBUG_GetObjectSize(adt) * 8); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); - } - - } - /* if the structure has already been filled, just redo the parsing - * but don't store results into the struct - * FIXME: there's a quite ugly memory leak in there... - */ - - /* Now parse the individual elements of the structure/union. */ - while (*ptd->ptr != ';') - { - /* agg_name : type ',' ',' */ - idx = ptd->idx; - - if (ptd->ptr[0] == '$' && ptd->ptr[1] == 'v') - { - int x; - - if (ptd->ptr[2] == 'f') - { - /* C++ virtual method table */ - ptd->ptr += 3; - DEBUG_ReadTypeEnum(&ptd->ptr); - PTS_ABORTIF(ptd, *ptd->ptr++ != ':'); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &dt) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ','); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &x) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); - ptd->idx = idx; - continue; - } - else if (ptd->ptr[2] == 'b') - { - ptd->ptr += 3; - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &dt) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ':'); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &dt) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ','); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &x) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); - ptd->idx = idx; - continue; - } - } - - PTS_ABORTIF(ptd, DEBUG_PTS_ReadID(ptd) == -1); - /* Ref. TSDF R2.130 Section 7.4. When the field name is a method name - * it is followed by two colons rather than one. - */ - if (*ptd->ptr == ':') - { - ptd->ptr++; - DEBUG_PTS_ReadMethodInfo(ptd); - ptd->idx = idx; - continue; - } - else - { - /* skip C++ member protection /0 /1 or /2 */ - if (*ptd->ptr == '/') ptd->ptr += 2; - } - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &adt) == -1); - - switch (*ptd->ptr++) - { - case ',': - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &ofs) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ','); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &sz) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); - - if (doadd) DEBUG_AddStructElement(sdt, ptd->buf + idx, adt, ofs, sz); - break; - case ':': - { - char* tmp; - /* method parameters... terminated by ';' */ - PTS_ABORTIF(ptd, !(tmp = strchr(ptd->ptr, ';'))); - ptd->ptr = tmp + 1; - } - break; - default: - PTS_ABORTIF(ptd, TRUE); - } - ptd->idx = idx; - } - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); - if (*ptd->ptr == '~') - { - ptd->ptr++; - PTS_ABORTIF(ptd, *ptd->ptr++ != '%'); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &dt) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); - } - return 0; -} - -static inline int DEBUG_PTS_ReadEnum(struct ParseTypedefData* ptd, - struct datatype* edt) -{ - int ofs; - int idx; - - while (*ptd->ptr != ';') { - idx = ptd->idx; - PTS_ABORTIF(ptd, DEBUG_PTS_ReadID(ptd) == -1); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &ofs) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ','); - DEBUG_AddStructElement(edt, ptd->buf + idx, NULL, ofs, 0); - ptd->idx = idx; - } - ptd->ptr++; - return 0; -} - -static inline int DEBUG_PTS_ReadArray(struct ParseTypedefData* ptd, - struct datatype* adt) -{ - int lo, hi; - struct datatype* rdt; - - /* ar;;; */ - - PTS_ABORTIF(ptd, *ptd->ptr++ != 'r'); - /* FIXME: range type is lost, always assume int */ - PTS_ABORTIF(ptd, DEBUG_PTS_ReadRange(ptd, &rdt, &lo, &hi) == -1); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &rdt) == -1); - - DEBUG_SetArrayParams(adt, lo, hi, rdt); - return 0; -} - -static int DEBUG_PTS_ReadTypedef(struct ParseTypedefData* ptd, const char* typename, - struct datatype** ret_dt) -{ - int idx, lo, hi, sz = -1; - struct datatype* new_dt = NULL; /* newly created data type */ - struct datatype* ref_dt; /* referenced data type (pointer...) */ - struct datatype* dt1; /* intermediate data type (scope is limited) */ - struct datatype* dt2; /* intermediate data type: t1=t2=new_dt */ - int filenr1, subnr1; - - /* things are a bit complicated because of the way the typedefs are stored inside - * the file (we cannot keep the struct datatype** around, because address can - * change when realloc is done, so we must call over and over - * DEBUG_FileSubNr2StabEnum to keep the correct values around - * (however, keeping struct datatype* is valid)) - */ - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypeReference(ptd, &filenr1, &subnr1) == -1); - - while (*ptd->ptr == '=') { - ptd->ptr++; - PTS_ABORTIF(ptd, new_dt != NULL); - - /* first handle attribute if any */ - switch (*ptd->ptr) { - case '@': - if (*++ptd->ptr == 's') { - ptd->ptr++; - if (DEBUG_PTS_ReadNum(ptd, &sz) == -1) { - WINE_ERR("Not an attribute... NIY\n"); - ptd->ptr -= 2; - return -1; - } - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); - } - break; - } - /* then the real definitions */ - switch (*ptd->ptr++) { - case '*': - case '&': - new_dt = DEBUG_NewDataType(DT_POINTER, NULL); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &ref_dt) == -1); - DEBUG_SetPointerType(new_dt, ref_dt); - break; - case 'k': /* 'const' modifier */ - case 'B': /* 'volatile' modifier */ - /* just kinda ignore the modifier, I guess -gmt */ - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, typename, &new_dt) == -1); - break; - case '(': - ptd->ptr--; - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, typename, &new_dt) == -1); - break; - case 'a': - new_dt = DEBUG_NewDataType(DT_ARRAY, NULL); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadArray(ptd, new_dt) == -1); - break; - case 'r': - new_dt = DEBUG_NewDataType(DT_BASIC, typename); - assert(!*DEBUG_FileSubNr2StabEnum(filenr1, subnr1)); - *DEBUG_FileSubNr2StabEnum(filenr1, subnr1) = new_dt; - PTS_ABORTIF(ptd, DEBUG_PTS_ReadRange(ptd, &ref_dt, &lo, &hi) == -1); - /* should perhaps do more here... */ - break; - case 'f': - new_dt = DEBUG_NewDataType(DT_FUNC, NULL); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &ref_dt) == -1); - DEBUG_SetPointerType(new_dt, ref_dt); - break; - case 'e': - new_dt = DEBUG_NewDataType(DT_ENUM, NULL); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadEnum(ptd, new_dt) == -1); - break; - case 's': - case 'u': - /* dt1 can have been already defined in a forward definition */ - dt1 = *DEBUG_FileSubNr2StabEnum(filenr1, subnr1); - dt2 = DEBUG_TypeCast(DT_STRUCT, typename); - if (!dt1) { - new_dt = DEBUG_NewDataType(DT_STRUCT, typename); - /* we need to set it here, because a struct can hold a pointer - * to itself - */ - *DEBUG_FileSubNr2StabEnum(filenr1, subnr1) = new_dt; - } else { - if (DEBUG_GetType(dt1) != DT_STRUCT) { - WINE_ERR("Forward declaration is not an aggregate\n"); - return -1; - } - - /* should check typename is the same too */ - new_dt = dt1; - } - PTS_ABORTIF(ptd, DEBUG_PTS_ReadAggregate(ptd, new_dt) == -1); - break; - case 'x': - switch (*ptd->ptr++) { - case 'e': lo = DT_ENUM; break; - case 's': case 'u': lo = DT_STRUCT; break; - default: return -1; - } - - idx = ptd->idx; - PTS_ABORTIF(ptd, DEBUG_PTS_ReadID(ptd) == -1); - new_dt = DEBUG_NewDataType(lo, ptd->buf + idx); - ptd->idx = idx; - break; - case '-': - { - enum debug_type_basic basic = DT_BASIC_LAST; - - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &lo) == -1); - - switch (lo) - { - case 1: basic = DT_BASIC_INT; break; - case 2: basic = DT_BASIC_CHAR; break; - case 3: basic = DT_BASIC_SHORTINT; break; - case 4: basic = DT_BASIC_LONGINT; break; - case 5: basic = DT_BASIC_UCHAR; break; - case 6: basic = DT_BASIC_SCHAR; break; - case 7: basic = DT_BASIC_USHORTINT; break; - case 8: basic = DT_BASIC_UINT; break; -/* case 9: basic = DT_BASIC_UINT"; */ - case 10: basic = DT_BASIC_ULONGINT; break; - case 11: basic = DT_BASIC_VOID; break; - case 12: basic = DT_BASIC_FLOAT; break; - case 13: basic = DT_BASIC_DOUBLE; break; - case 14: basic = DT_BASIC_LONGDOUBLE; break; -/* case 15: basic = DT_BASIC_INT; break; */ - case 16: - switch (sz) { - case 32: basic = DT_BASIC_BOOL1; break; - case 16: basic = DT_BASIC_BOOL2; break; - case 8: basic = DT_BASIC_BOOL4; break; - } - break; -/* case 17: basic = DT_BASIC_SHORT real; break; */ -/* case 18: basic = DT_BASIC_REAL; break; */ - case 25: basic = DT_BASIC_CMPLX_FLOAT; break; - case 26: basic = DT_BASIC_CMPLX_DOUBLE; break; -/* case 30: basic = DT_BASIC_wchar"; break; */ - case 31: basic = DT_BASIC_LONGLONGINT; break; - case 32: basic = DT_BASIC_ULONGLONGINT; break; - default: - PTS_ABORTIF(ptd, 1); - } - PTS_ABORTIF(ptd, !(new_dt = DEBUG_GetBasicType(basic))); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); - } - break; - case '#': - new_dt = DEBUG_NewDataType(DT_FUNC, NULL); - if (*ptd->ptr == '#') - { - ptd->ptr++; - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &ref_dt) == -1); - DEBUG_SetPointerType(new_dt, ref_dt); - } - else - { - struct datatype* cls_dt; - struct datatype* pmt_dt; - - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &cls_dt) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ','); - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &ref_dt) == -1); - DEBUG_SetPointerType(new_dt, ref_dt); - while (*ptd->ptr == ',') - { - ptd->ptr++; - PTS_ABORTIF(ptd, DEBUG_PTS_ReadTypedef(ptd, NULL, &pmt_dt) == -1); - } - } - break; - case 'R': - { - enum debug_type_basic basic = DT_BASIC_LAST; - int type, len, unk; - - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &type) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */ - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &len) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */ - PTS_ABORTIF(ptd, DEBUG_PTS_ReadNum(ptd, &unk) == -1); - PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */ - - switch (type) - { - case 1: basic = DT_BASIC_FLOAT; break; - case 2: basic = DT_BASIC_DOUBLE; break; - case 3: basic = DT_BASIC_CMPLX_FLOAT; break; - case 4: basic = DT_BASIC_CMPLX_DOUBLE; break; - case 5: basic = DT_BASIC_CMPLX_LONGDOUBLE; break; - case 6: basic = DT_BASIC_LONGDOUBLE; break; - default: PTS_ABORTIF(ptd, 1); - } - PTS_ABORTIF(ptd, !(new_dt = DEBUG_GetBasicType(basic))); - } - break; - default: - WINE_ERR("Unknown type '%c'\n", ptd->ptr[-1]); - return -1; - } - } - - if (!new_dt) - { - /* is it a forward declaration that has been filled ? */ - new_dt = *DEBUG_FileSubNr2StabEnum(filenr1, subnr1); - /* if not, this should then be a basic type: define it, or even void */ - if (!new_dt) - new_dt = DEBUG_NewDataType(DT_BASIC, typename); - } - - *DEBUG_FileSubNr2StabEnum(filenr1, subnr1) = *ret_dt = new_dt; - - if (typename && WINE_TRACE_ON(winedbg_stabs)) { - DEBUG_Printf("Adding (%d,%d) %s => ", filenr1, subnr1, typename); - DEBUG_PrintTypeCast(new_dt); - DEBUG_Printf("\n"); - } - - return 0; -} - -static int DEBUG_ParseTypedefStab(const char* ptr, const char* typename) -{ - struct ParseTypedefData ptd; - struct datatype* dt; - int ret = -1; - - /* check for already existing definition */ - - ptd.idx = 0; -#ifdef PTS_DEBUG - ptd.err_idx = 0; -#endif - for (ptd.ptr = ptr - 1; ;) - { - ptd.ptr = strchr(ptd.ptr + 1, ':'); - if (ptd.ptr == NULL || *++ptd.ptr != ':') break; - } - - if (ptd.ptr) - { - if (*ptd.ptr != '(') ptd.ptr++; - /* most of type definitions take one char, except Tt */ - if (*ptd.ptr != '(') ptd.ptr++; - ret = DEBUG_PTS_ReadTypedef(&ptd, typename, &dt); - } - - if (ret == -1 || *ptd.ptr) { -#ifdef PTS_DEBUG - int i; - WINE_TRACE("Failure on %s\n", ptr); - if (ret == -1) - { - for (i = 0; i < ptd.err_idx; i++) - { - WINE_TRACE("[%d]: line %d => %s\n", - i, ptd.errors[i].line, ptd.errors[i].ptr); - } - } - else - WINE_TRACE("[0]: => %s\n", ptd.ptr); - -#else - WINE_ERR("Failure on %s at %s\n", ptr, ptd.ptr); -#endif - return FALSE; - } - - return TRUE; -} - -static struct datatype* -DEBUG_ParseStabType(const char* stab) -{ - const char* c = stab - 1; - - /* - * Look through the stab definition, and figure out what datatype - * this represents. If we have something we know about, assign the - * type. - * According to "The \"stabs\" debug format" (Rev 2.130) the name may be - * a C++ name and contain double colons e.g. foo::bar::baz:t5=*6. - */ - do - { - if ((c = strchr(c + 1, ':')) == NULL) return NULL; - } while (*++c == ':'); - - /* - * The next characters say more about the type (i.e. data, function, etc) - * of symbol. Skip them. (C++ for example may have Tt). - * Actually this is a very weak description; I think Tt is the only - * multiple combination we should see. - */ - while (*c && *c != '(' && !isdigit(*c)) - c++; - /* - * The next is either an integer or a (integer,integer). - * The DEBUG_ReadTypeEnum takes care that stab_types is large enough. - */ - return *DEBUG_ReadTypeEnum(&c); -} - -enum DbgInfoLoad DEBUG_ParseStabs(const char* addr, void* load_offset, - unsigned int staboff, int stablen, - unsigned int strtaboff, int strtablen) -{ - struct name_hash* curr_func = NULL; - struct wine_locals* curr_loc = NULL; - struct name_hash* curr_sym = NULL; - char currpath[PATH_MAX]; - int i; - int in_external_file = FALSE; - int last_nso = -1; - unsigned int len; - DBG_VALUE new_value; - int nstab; - const char* ptr; - char* stabbuff; - unsigned int stabbufflen; - const struct stab_nlist* stab_ptr; - const char* strs; - int strtabinc; - const char* subpath = NULL; - char symname[4096]; - - nstab = stablen / sizeof(struct stab_nlist); - stab_ptr = (struct stab_nlist *) (addr + staboff); - strs = (char *) (addr + strtaboff); - - memset(currpath, 0, sizeof(currpath)); - - /* - * Allocate a buffer into which we can build stab strings for cases - * where the stab is continued over multiple lines. - */ - stabbufflen = 65536; - stabbuff = (char *) DBG_alloc(stabbufflen); - - strtabinc = 0; - stabbuff[0] = '\0'; - for (i = 0; i < nstab; i++, stab_ptr++) - { - ptr = strs + (unsigned int) stab_ptr->n_un.n_name; - if( ptr[strlen(ptr) - 1] == '\\' ) - { - /* - * Indicates continuation. Append this to the buffer, and go onto the - * next record. Repeat the process until we find a stab without the - * '/' character, as this indicates we have the whole thing. - */ - len = strlen(ptr); - if( strlen(stabbuff) + len > stabbufflen ) - { - stabbufflen += 65536; - stabbuff = (char *) DBG_realloc(stabbuff, stabbufflen); - } - strncat(stabbuff, ptr, len - 1); - continue; - } - else if( stabbuff[0] != '\0' ) - { - strcat( stabbuff, ptr); - ptr = stabbuff; - } - - if( strchr(ptr, '=') != NULL ) - { - /* - * The stabs aren't in writable memory, so copy it over so we are - * sure we can scribble on it. - */ - if( ptr != stabbuff ) - { - strcpy(stabbuff, ptr); - ptr = stabbuff; - } - stab_strcpy(symname, sizeof(symname), ptr); - if (!DEBUG_ParseTypedefStab(ptr, symname)) { - /* skip this definition */ - stabbuff[0] = '\0'; - continue; - } - } - - switch(stab_ptr->n_type) - { - case N_GSYM: - /* - * These are useless with ELF. They have no value, and you have to - * read the normal symbol table to get the address. Thus we - * ignore them, and when we process the normal symbol table - * we should do the right thing. - * - * With a.out or mingw, they actually do make some amount of sense. - */ - new_value.type = DEBUG_ParseStabType(ptr); - new_value.addr.seg = 0; - new_value.cookie = DV_TARGET; - - stab_strcpy(symname, sizeof(symname), ptr); -#ifdef __ELF__ - /* EPP used to be: new_value.addr.off = 0; */ - new_value.addr.off = (unsigned long)load_offset + stab_ptr->n_value; - curr_sym = DEBUG_AddSymbol( symname, &new_value, currpath, - SYM_WINE | SYM_DATA | SYM_INVALID ); -#else - new_value.addr.off = (unsigned long)load_offset + stab_ptr->n_value; - curr_sym = DEBUG_AddSymbol( symname, &new_value, currpath, - SYM_WINE | SYM_DATA ); -#endif - break; - case N_RBRAC: - case N_LBRAC: - /* - * We need to keep track of these so we get symbol scoping - * right for local variables. For now, we just ignore them. - * The hooks are already there for dealing with this however, - * so all we need to do is to keep count of the nesting level, - * and find the RBRAC for each matching LBRAC. - */ - break; - case N_LCSYM: - case N_STSYM: - /* - * These are static symbols and BSS symbols. - */ - new_value.addr.seg = 0; - new_value.type = DEBUG_ParseStabType(ptr); - new_value.addr.off = (unsigned long)load_offset + stab_ptr->n_value; - new_value.cookie = DV_TARGET; - - stab_strcpy(symname, sizeof(symname), ptr); - curr_sym = DEBUG_AddSymbol( symname, &new_value, currpath, - SYM_WINE | SYM_DATA ); - break; - case N_PSYM: - /* - * These are function parameters. - */ - if( curr_func != NULL && !in_external_file ) - { - stab_strcpy(symname, sizeof(symname), ptr); - curr_loc = DEBUG_AddLocal( curr_func, 0, - stab_ptr->n_value, 0, 0, symname ); - DEBUG_SetLocalSymbolType( curr_loc, DEBUG_ParseStabType(ptr) ); - } - break; - case N_RSYM: - if( curr_func != NULL && !in_external_file ) - { - stab_strcpy(symname, sizeof(symname), ptr); - curr_loc = DEBUG_AddLocal( curr_func, stab_ptr->n_value + 1, - 0, 0, 0, symname ); - DEBUG_SetLocalSymbolType( curr_loc, DEBUG_ParseStabType(ptr) ); - } - break; - case N_LSYM: - if( curr_func != NULL && !in_external_file ) - { - stab_strcpy(symname, sizeof(symname), ptr); - curr_loc = DEBUG_AddLocal( curr_func, 0, - stab_ptr->n_value, 0, 0, symname ); - DEBUG_SetLocalSymbolType( curr_loc, DEBUG_ParseStabType(ptr) ); - } - break; - case N_SLINE: - /* - * This is a line number. These are always relative to the start - * of the function (N_FUN), and this makes the lookup easier. - */ - if( curr_func != NULL && !in_external_file ) - { -#ifdef __ELF__ - DEBUG_AddLineNumber(curr_func, stab_ptr->n_desc, - stab_ptr->n_value); -#else -#if 0 - /* - * This isn't right. The order of the stabs is different under - * a.out, and as a result we would end up attaching the line - * number to the wrong function. - */ - DEBUG_AddLineNumber(curr_func, stab_ptr->n_desc, - stab_ptr->n_value - curr_func->addr.off); -#endif -#endif - } - break; - case N_FUN: - /* - * First, clean up the previous function we were working on. - */ - DEBUG_Normalize(curr_func); - - /* - * For now, just declare the various functions. Later - * on, we will add the line number information and the - * local symbols. - */ - if( !in_external_file) - { - stab_strcpy(symname, sizeof(symname), ptr); - if (*symname) - { - new_value.addr.seg = 0; - new_value.type = DEBUG_ParseStabType(ptr); - new_value.addr.off = (unsigned long)load_offset + stab_ptr->n_value; - new_value.cookie = DV_TARGET; - /* - * Copy the string to a temp buffer so we - * can kill everything after the ':'. We do - * it this way because otherwise we end up dirtying - * all of the pages related to the stabs, and that - * sucks up swap space like crazy. - */ -#ifdef __ELF__ - curr_func = DEBUG_AddSymbol( symname, &new_value, currpath, - SYM_WINE | SYM_FUNC | SYM_INVALID ); -#else - curr_func = DEBUG_AddSymbol( symname, &new_value, currpath, - SYM_WINE | SYM_FUNC ); -#endif - } - else - { - /* some GCC seem to use a N_FUN "" to mark the end of a function */ - curr_func = NULL; - } - } - else - { - /* - * Don't add line number information for this function - * any more. - */ - curr_func = NULL; - } - break; - case N_SO: - /* - * This indicates a new source file. Append the records - * together, to build the correct path name. - */ -#ifndef __ELF__ - /* - * With a.out, there is no NULL string N_SO entry at the end of - * the file. Thus when we find non-consecutive entries, - * we consider that a new file is started. - */ - if( last_nso < i-1 ) - { - currpath[0] = '\0'; - DEBUG_Normalize(curr_func); - curr_func = NULL; - } -#endif - - if( *ptr == '\0' ) /* end of N_SO file */ - { - /* - * Nuke old path. - */ - currpath[0] = '\0'; - DEBUG_Normalize(curr_func); - curr_func = NULL; - } - else - { - if (*ptr != '/') - strcat(currpath, ptr); - else - strcpy(currpath, ptr); - subpath = ptr; - DEBUG_ResetIncludes(); - } - last_nso = i; - break; - case N_SOL: - /* - * This indicates we are including stuff from an include file. - * If this is the main source, enable the debug stuff, otherwise - * ignore it. - */ - in_external_file = !(subpath == NULL || strcmp(ptr, subpath) == 0); - in_external_file = FALSE; /* FIXME EPP hack FIXME */; - break; - case N_UNDF: - strs += strtabinc; - strtabinc = stab_ptr->n_value; - DEBUG_Normalize(curr_func); - curr_func = NULL; - break; - case N_OPT: - /* - * Ignore this. We don't care what it points to. - */ - break; - case N_BINCL: - DEBUG_AddInclude(DEBUG_CreateInclude(ptr, stab_ptr->n_value)); - break; - case N_EINCL: - break; - case N_EXCL: - DEBUG_AddInclude(DEBUG_FindInclude(ptr, stab_ptr->n_value)); - break; - case N_MAIN: - /* - * Always ignore these. GCC doesn't even generate them. - */ - break; - default: - WINE_ERR("Unknown stab type 0x%02x\n", stab_ptr->n_type); - break; - } - - stabbuff[0] = '\0'; - - WINE_TRACE("0x%02x %x %s\n", stab_ptr->n_type, - (unsigned int) stab_ptr->n_value, - strs + (unsigned int) stab_ptr->n_un.n_name); - } - - DEBUG_FreeIncludes(); - - return DIL_LOADED; -} - diff --git a/programs/winedbg/stack.c b/programs/winedbg/stack.c index 653742da315..ab59ef64947 100644 --- a/programs/winedbg/stack.c +++ b/programs/winedbg/stack.c @@ -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__ */ } diff --git a/programs/winedbg/symbol.c b/programs/winedbg/symbol.c new file mode 100644 index 00000000000..913c74671e2 --- /dev/null +++ b/programs/winedbg/symbol.c @@ -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 +#include +#include + +#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 ( 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); +} diff --git a/programs/winedbg/types.c b/programs/winedbg/types.c index 9fa7a370450..0b3e6300d8b 100644 --- a/programs/winedbg/types.c +++ b/programs/winedbg/types.c @@ -24,1086 +24,697 @@ #include "config.h" #include -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif - #include "debugger.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(winedbg); -#define NR_TYPE_HASH 521 - -int DEBUG_nchar; -static const int DEBUG_maxchar = 1024; - -struct en_values -{ - struct en_values* next; - char * name; - int value; -}; - -struct member -{ - struct member * next; - char * name; - struct datatype * type; - int offset; - int size; -}; - -struct datatype -{ - enum debug_type type; - struct datatype * next; - const char * name; - union - { - struct - { - char basic_type; - const char * output_format; - char basic_size; - unsigned b_signed:1; - } basic; - struct - { - unsigned short bitoff; - unsigned short nbits; - struct datatype * basetype; - } bitfield; - - struct - { - struct datatype * pointsto; - } pointer; - struct - { - struct datatype * rettype; - } funct; - struct - { - int start; - int end; - struct datatype * basictype; - } array; - struct - { - int size; - struct member * members; - } structure; - struct - { - struct en_values * members; - } enumeration; - } un; -}; - -/* - * All of the types that have been defined so far. - */ -static struct datatype * type_hash_table[NR_TYPE_HASH + 1]; -static struct datatype * pointer_types = NULL; -static struct datatype * basic_types[DT_BASIC_LAST]; - -static unsigned int type_hash( const char * name ) -{ - unsigned int hash = 0; - unsigned int tmp; - const char * p; - - p = name; - - while (*p) - { - hash = (hash << 4) + *p++; - - if( (tmp = (hash & 0xf0000000)) ) - { - hash ^= tmp >> 24; - } - hash &= ~tmp; - } - return hash % NR_TYPE_HASH; -} - - -static struct datatype * -DEBUG_InitBasic(int type, const char * name, int size, int b_signed, - const char * output_format) -{ - int hash; - - struct datatype * dt; - dt = (struct datatype *) DBG_alloc(sizeof(struct datatype)); - - if( dt != NULL ) - { - if( name != NULL ) - { - hash = type_hash(name); - } - else - { - hash = NR_TYPE_HASH; - } - - dt->type = DT_BASIC; - dt->name = name; - dt->next = type_hash_table[hash]; - type_hash_table[hash] = dt; - dt->un.basic.basic_type = type; - dt->un.basic.basic_size = size; - dt->un.basic.b_signed = b_signed; - dt->un.basic.output_format = output_format; - basic_types[type] = dt; - } - - return dt; -} - -static -struct datatype * -DEBUG_LookupDataType(enum debug_type xtype, int hash, const char * typename) -{ - struct datatype * dt = NULL; - - if( typename != NULL ) - { - for( dt = type_hash_table[hash]; dt; dt = dt->next ) - { - if( xtype != dt->type || dt->name == NULL - || dt->name[0] != typename[0]) - { - continue; - } - - if( strcmp(dt->name, typename) == 0 ) - { - return dt; - } - } - } - - return dt; -} - -struct datatype * -DEBUG_GetBasicType(enum debug_type_basic basic) -{ - if (basic == 0 || basic >= DT_BASIC_LAST) - { - return NULL; - } - return basic_types[basic]; -} - -struct datatype * -DEBUG_NewDataType(enum debug_type xtype, const char * typename) -{ - struct datatype * dt = NULL; - int hash; - - /* - * The last bucket is special, and is used to hold typeless names. - */ - if( typename == NULL ) - { - hash = NR_TYPE_HASH; - } - else - { - hash = type_hash(typename); - } - - dt = DEBUG_LookupDataType(xtype, hash, typename); - - if( dt == NULL ) - { - dt = (struct datatype *) DBG_alloc(sizeof(struct datatype)); - - if( dt != NULL ) - { - memset(dt, 0, sizeof(*dt)); - - dt->type = xtype; - if( typename != NULL ) - { - dt->name = DBG_strdup(typename); - } - else - { - dt->name = NULL; - } - if( xtype == DT_POINTER ) - { - dt->next = pointer_types; - pointer_types = dt; - } - else - { - dt->next = type_hash_table[hash]; - type_hash_table[hash] = dt; - } - } - } - - return dt; -} - -struct datatype * -DEBUG_FindOrMakePointerType(struct datatype * reftype) -{ - struct datatype * dt = NULL; - - if( reftype != NULL ) - { - for( dt = pointer_types; dt; dt = dt->next ) - { - if( dt->type != DT_POINTER ) - { - continue; - } - - if( dt->un.pointer.pointsto == reftype ) - { - return dt; - } - } - } - - if( dt == NULL ) - { - dt = (struct datatype *) DBG_alloc(sizeof(struct datatype)); - - if( dt != NULL ) - { - dt->type = DT_POINTER; - dt->un.pointer.pointsto = reftype; - dt->next = pointer_types; - pointer_types = dt; - } - } - - return dt; -} - -void -DEBUG_InitTypes(void) -{ - static int beenhere = 0; - - if( beenhere++ != 0 ) - { - return; - } - - /* - * Initialize a few builtin types. - */ - - DEBUG_InitBasic(DT_BASIC_INT,"int",4,1,"%d"); - DEBUG_InitBasic(DT_BASIC_CHAR,"char",1,1,"'%c'"); - DEBUG_InitBasic(DT_BASIC_LONGINT,"long int",4,1,"%d"); - DEBUG_InitBasic(DT_BASIC_UINT,"unsigned int",4,0,"%d"); - DEBUG_InitBasic(DT_BASIC_ULONGINT,"long unsigned int",4,0,"%d"); - DEBUG_InitBasic(DT_BASIC_LONGLONGINT,"long long int",8,1,"%ld"); - DEBUG_InitBasic(DT_BASIC_ULONGLONGINT,"long long unsigned int",8,0,"%ld"); - DEBUG_InitBasic(DT_BASIC_SHORTINT,"short int",2,1,"%d"); - DEBUG_InitBasic(DT_BASIC_USHORTINT,"short unsigned int",2,0,"%d"); - DEBUG_InitBasic(DT_BASIC_SCHAR,"signed char",1,1,"'%c'"); - DEBUG_InitBasic(DT_BASIC_UCHAR,"unsigned char",1,0,"'%c'"); - DEBUG_InitBasic(DT_BASIC_FLOAT,"float",4,0,"%f"); - DEBUG_InitBasic(DT_BASIC_DOUBLE,"long double",12,0,NULL); - DEBUG_InitBasic(DT_BASIC_LONGDOUBLE,"double",8,0,"%lf"); - DEBUG_InitBasic(DT_BASIC_CMPLX_INT,"complex int",8,1,NULL); - DEBUG_InitBasic(DT_BASIC_CMPLX_FLOAT,"complex float",8,0,NULL); - DEBUG_InitBasic(DT_BASIC_CMPLX_DOUBLE,"complex double",16,0,NULL); - DEBUG_InitBasic(DT_BASIC_CMPLX_LONGDOUBLE,"complex long double",24,0,NULL); - DEBUG_InitBasic(DT_BASIC_VOID,"void",0,0,NULL); - DEBUG_InitBasic(DT_BASIC_BOOL1,NULL,1,0,"%B"); - DEBUG_InitBasic(DT_BASIC_BOOL2,NULL,2,0,"%B"); - DEBUG_InitBasic(DT_BASIC_BOOL4,NULL,4,0,"%B"); - - basic_types[DT_BASIC_STRING] = DEBUG_NewDataType(DT_POINTER, NULL); - DEBUG_SetPointerType(basic_types[DT_BASIC_STRING], basic_types[DT_BASIC_CHAR]); - - /* - * Special version of int used with constants of various kinds. - */ - DEBUG_InitBasic(DT_BASIC_CONST_INT,NULL,4,1,"%d"); - - /* - * Now initialize the builtins for codeview. - */ - DEBUG_InitCVDataTypes(); - - DEBUG_InitBasic(DT_BASIC_CONTEXT,NULL,4,0,"%R"); -} - -long long int -DEBUG_GetExprValue(const DBG_VALUE* _value, const char** format) -{ - long long int rtn; - unsigned int rtn2; - struct datatype * type2 = NULL; - struct en_values * e; - const char * def_format = "0x%x"; - DBG_VALUE value = *_value; - - assert(_value->cookie == DV_TARGET || _value->cookie == DV_HOST); - - rtn = 0; rtn2 = 0; - /* FIXME? I don't quite get this... - * if this is wrong, value.addr shall be linearized - */ - value.addr.seg = 0; - assert(value.type != NULL); - - switch (value.type->type) { - case DT_BASIC: - - if (value.type->un.basic.basic_size > sizeof(rtn)) { - WINE_ERR("Size too large (%d)\n", value.type->un.basic.basic_size); - return 0; - } - /* FIXME: following code implies i386 byte ordering */ - if (_value->cookie == DV_TARGET) { - if (!DEBUG_READ_MEM_VERBOSE((void*)value.addr.off, &rtn, - value.type->un.basic.basic_size)) - return 0; - } else { - memcpy(&rtn, (void*)value.addr.off, value.type->un.basic.basic_size); - } - - if ( (value.type->un.basic.b_signed) - && ((value.type->un.basic.basic_size & 3) != 0) - && ((rtn >> (value.type->un.basic.basic_size * 8 - 1)) != 0)) { - rtn = rtn | ((-1) << (value.type->un.basic.basic_size * 8)); - } - /* float type has to be promoted as a double */ - if (value.type->un.basic.basic_type == DT_BASIC_FLOAT) { - float f; - double d; - memcpy(&f, &rtn, sizeof(f)); - d = (double)f; - memcpy(&rtn, &d, sizeof(rtn)); - } - if (value.type->un.basic.output_format != NULL) { - def_format = value.type->un.basic.output_format; - } - - /* - * Check for single character prints that are out of range. - */ - if ( value.type->un.basic.basic_size == 1 - && strcmp(def_format, "'%c'") == 0 - && ((rtn < 0x20) || (rtn > 0x80))) { - def_format = "%d"; - } - break; - case DT_POINTER: - if (_value->cookie == DV_TARGET) { - if (!DEBUG_READ_MEM_VERBOSE((void*)value.addr.off, &rtn2, sizeof(void*))) - return 0; - } else { - rtn2 = *(unsigned int*)(value.addr.off); - } - - type2 = value.type->un.pointer.pointsto; - - if (!type2) { - def_format = "Internal symbol error: unable to access memory location 0x%08x"; - rtn = 0; - break; - } - - if (type2->type == DT_BASIC && type2->un.basic.basic_size == 1) { - if (_value->cookie == DV_TARGET) { - char ch; - def_format = "\"%S\""; - /* FIXME: assuming little endian */ - if (!DEBUG_READ_MEM_VERBOSE((void*)rtn2, &ch, 1)) - return 0; - } else { - def_format = "\"%s\""; - } - } else { - def_format = "0x%8.8x"; - } - rtn = rtn2; - break; - case DT_ARRAY: - case DT_STRUCT: - assert(_value->cookie == DV_TARGET); - if (!DEBUG_READ_MEM_VERBOSE((void*)value.addr.off, &rtn2, sizeof(rtn2))) - return 0; - rtn = rtn2; - def_format = "0x%8.8x"; - break; - case DT_ENUM: - assert(_value->cookie == DV_TARGET); - if (!DEBUG_READ_MEM_VERBOSE((void*)value.addr.off, &rtn2, sizeof(rtn2))) - return 0; - rtn = rtn2; - def_format = "%d"; - for (e = value.type->un.enumeration.members; e; e = e->next) { - if (e->value == rtn) { - rtn = (int)e->name; - def_format = "%s"; - break; - } - } - break; - default: - rtn = 0; - break; - } - - - if (format != NULL) { - *format = def_format; - } - return rtn; -} - -unsigned int -DEBUG_TypeDerefPointer(const DBG_VALUE *value, struct datatype ** newtype) -{ - DBG_ADDR addr = value->addr; - unsigned int val; - - assert(value->cookie == DV_TARGET || value->cookie == DV_HOST); - - *newtype = NULL; - - /* - * Make sure that this really makes sense. - */ - if( value->type->type != DT_POINTER ) - return 0; - - if (value->cookie == DV_TARGET) { - if (!DEBUG_READ_MEM((void*)value->addr.off, &val, sizeof(val))) - return 0; - } else { - val = *(unsigned int*)value->addr.off; - } - - *newtype = value->type->un.pointer.pointsto; - addr.off = val; - return DEBUG_ToLinear(&addr); /* FIXME: is this right (or "better") ? */ -} - -unsigned int -DEBUG_FindStructElement(DBG_VALUE* value, const char * ele_name, int * tmpbuf) -{ - struct member * m; - unsigned int mask; - - assert(value->cookie == DV_TARGET || value->cookie == DV_HOST); - - /* - * Make sure that this really makes sense. - */ - if( value->type->type != DT_STRUCT ) - { - value->type = NULL; - return FALSE; - } - - for(m = value->type->un.structure.members; m; m = m->next) - { - if( strcmp(m->name, ele_name) == 0 ) - { - value->type = m->type; - if( (m->offset & 7) != 0 || (m->size & 7) != 0) - { - /* - * Bitfield operation. We have to extract the field and store - * it in a temporary buffer so that we get it all right. - */ - *tmpbuf = ((*(int* ) (value->addr.off + (m->offset >> 3))) >> (m->offset & 7)); - value->addr.off = (int) tmpbuf; - - mask = 0xffffffff << (m->size); - *tmpbuf &= ~mask; - /* - * OK, now we have the correct part of the number. - * Check to see whether the basic type is signed or not, and if so, - * we need to sign extend the number. - */ - if( m->type->type == DT_BASIC && m->type->un.basic.b_signed != 0 - && (*tmpbuf & (1 << (m->size - 1))) != 0 ) - { - *tmpbuf |= mask; - } - } - else - { - value->addr.off += (m->offset >> 3); - } - return TRUE; - } - } - - value->type = NULL; - return FALSE; -} - -int -DEBUG_SetStructSize(struct datatype * dt, int size) -{ - assert(dt->type == DT_STRUCT); - - if( dt->un.structure.members != NULL ) - { - return FALSE; - } - - dt->un.structure.size = size; - dt->un.structure.members = NULL; - - return TRUE; -} - -int -DEBUG_CopyFieldlist(struct datatype * dt, struct datatype * dt2) -{ - if (!(dt->type == dt2->type && ((dt->type == DT_STRUCT) || (dt->type == DT_ENUM)))) { - DEBUG_Printf("Error: Copyfield list mismatch (%d<>%d): ", dt->type, dt2->type); - DEBUG_PrintTypeCast(dt); - DEBUG_Printf(" "); - DEBUG_PrintTypeCast(dt2); - DEBUG_Printf("\n"); - return FALSE; - } - - if( dt->type == DT_STRUCT ) - { - dt->un.structure.members = dt2->un.structure.members; - } - else - { - dt->un.enumeration.members = dt2->un.enumeration.members; - } - - return TRUE; -} - -int -DEBUG_AddStructElement(struct datatype * dt, char * name, struct datatype * type, - int offset, int size) -{ - struct member * m; - struct member * last; - struct en_values * e; - - if( dt->type == DT_STRUCT ) - { - for(last = dt->un.structure.members; last; last = last->next) - { - if( (last->name[0] == name[0]) - && (strcmp(last->name, name) == 0) ) - { - return TRUE; - } - if( last->next == NULL ) - { - break; - } - } - m = (struct member *) DBG_alloc(sizeof(struct member)); - if( m == NULL ) - { - return FALSE; - } - - m->name = DBG_strdup(name); - m->type = type; - m->offset = offset; - m->size = size; - if( last == NULL ) - { - m->next = dt->un.structure.members; - dt->un.structure.members = m; - } - else - { - last->next = m; - m->next = NULL; - } - /* - * If the base type is bitfield, then adjust the offsets here so that we - * are able to look things up without lots of falter-all. - */ - if( type && type->type == DT_BITFIELD ) - { - m->offset += m->type->un.bitfield.bitoff; - m->size = m->type->un.bitfield.nbits; - m->type = m->type->un.bitfield.basetype; - } - } - else if( dt->type == DT_ENUM ) - { - e = (struct en_values *) DBG_alloc(sizeof(struct en_values)); - if( e == FALSE ) - { - return FALSE; - } - - e->name = DBG_strdup(name); - e->value = offset; - e->next = dt->un.enumeration.members; - dt->un.enumeration.members = e; - } - else - { - assert(FALSE); - } - return TRUE; -} - -struct datatype * -DEBUG_GetPointerType(struct datatype * dt) -{ - if( dt->type == DT_POINTER ) - { - return dt->un.pointer.pointsto; - } - - return NULL; -} - -int -DEBUG_SetPointerType(struct datatype * dt, struct datatype * dt2) -{ - switch(dt->type) - { - case DT_POINTER: - dt->un.pointer.pointsto = dt2; - break; - case DT_FUNC: - dt->un.funct.rettype = dt2; - break; - default: - assert(FALSE); - } - - return TRUE; -} - -int -DEBUG_SetArrayParams(struct datatype * dt, int min, int max, struct datatype * dt2) -{ - assert(dt->type == DT_ARRAY); - dt->un.array.start = min; - dt->un.array.end = max; - dt->un.array.basictype = dt2; - - return TRUE; -} - -int -DEBUG_SetBitfieldParams(struct datatype * dt, int offset, int nbits, - struct datatype * dt2) -{ - assert(dt->type == DT_BITFIELD); - dt->un.bitfield.bitoff = offset; - dt->un.bitfield.nbits = nbits; - dt->un.bitfield.basetype = dt2; - - return TRUE; -} - -int DEBUG_GetObjectSize(struct datatype * dt) -{ - if( dt == NULL ) - { - return 0; - } - - switch(dt->type) - { - case DT_BASIC: - return dt->un.basic.basic_size; - case DT_POINTER: - return sizeof(int *); - case DT_STRUCT: - return dt->un.structure.size; - case DT_ENUM: - return sizeof(int); - case DT_ARRAY: - return (dt->un.array.end - dt->un.array.start) - * DEBUG_GetObjectSize(dt->un.array.basictype); - case DT_BITFIELD: - /* - * Bitfields have to be handled separately later on - * when we insert the element into the structure. - */ - return 0; - case DT_FUNC: - assert(FALSE); - default: - WINE_ERR("Unknown type???\n"); - break; - } - return 0; -} - -unsigned int -DEBUG_ArrayIndex(const DBG_VALUE * value, DBG_VALUE * result, int index) -{ - int size; - - assert(value->cookie == DV_TARGET || value->cookie == DV_HOST); - - /* - * Make sure that this really makes sense. - */ - if( value->type->type == DT_POINTER ) - { - /* - * Get the base type, so we know how much to index by. - */ - size = DEBUG_GetObjectSize(value->type->un.pointer.pointsto); - result->type = value->type->un.pointer.pointsto; - result->addr.off = (DWORD)DEBUG_ReadMemory(value) + size*index; - - /* Contents of array must be on same target */ - result->cookie = value->cookie; - } - else if (value->type->type == DT_ARRAY) - { - size = DEBUG_GetObjectSize(value->type->un.array.basictype); - result->type = value->type->un.array.basictype; - result->addr.off = value->addr.off + size * (index - value->type->un.array.start); - - /* Contents of array must be on same target */ - result->cookie = value->cookie; - } - else - { - assert(FALSE); - } - - return TRUE; -} - -/*********************************************************************** - * DEBUG_Print +/****************************************************************** + * types_extract_as_integer * - * Implementation of the 'print' command. + * Given a lvalue, try to get an integral (or pointer/address) value + * out of it */ -void -DEBUG_Print( const DBG_VALUE *value, int count, char format, int level ) +long int types_extract_as_integer(const struct dbg_lvalue* lvalue) { - DBG_VALUE val1; - int i; - struct member * m; - char * pnt; - int size; - int xval; + long int rtn = 0; + DWORD tag, size, bt; + DWORD linear = (DWORD)memory_to_linear_addr(&lvalue->addr); - assert(value->cookie == DV_TARGET || value->cookie == DV_HOST); + assert(lvalue->cookie == DLV_TARGET || lvalue->cookie == DLV_HOST); - if (count != 1) + if (lvalue->typeid == dbg_itype_none || + !types_get_info(linear, lvalue->typeid, TI_GET_SYMTAG, &tag)) + return 0; + + switch (tag) { - DEBUG_Printf("Count other than 1 is meaningless in 'print' command\n"); - return; - } - - if( value->type == NULL ) - { - /* No type, just print the addr value */ - if (value->addr.seg && (value->addr.seg != 0xffffffff)) - DEBUG_nchar += DEBUG_Printf("0x%04lx: ", value->addr.seg); - DEBUG_nchar += DEBUG_Printf("0x%08lx", value->addr.off); - goto leave; - } - - if( level == 0 ) - { - DEBUG_nchar = 0; - } - - if( DEBUG_nchar > DEBUG_maxchar ) - { - DEBUG_Printf("..."); - goto leave; - } - - if( format == 'i' || format == 's' || format == 'w' || format == 'b' || format == 'g') - { - DEBUG_Printf("Format specifier '%c' is meaningless in 'print' command\n", format); - format = '\0'; - } - - switch(value->type->type) - { - case DT_BASIC: - case DT_ENUM: - case DT_POINTER: - DEBUG_PrintBasic(value, 1, format); - break; - case DT_STRUCT: - DEBUG_nchar += DEBUG_Printf("{"); - for(m = value->type->un.structure.members; m; m = m->next) - { - val1 = *value; - DEBUG_FindStructElement(&val1, m->name, &xval); - DEBUG_nchar += DEBUG_Printf("%s=", m->name); - DEBUG_Print(&val1, 1, format, level + 1); - if( m->next != NULL ) - { - DEBUG_nchar += DEBUG_Printf(", "); - } - if( DEBUG_nchar > DEBUG_maxchar ) - { - DEBUG_Printf("...}"); - goto leave; - } - } - DEBUG_nchar += DEBUG_Printf("}"); - break; - case DT_ARRAY: - /* - * Loop over all of the entries, printing stuff as we go. - */ - size = DEBUG_GetObjectSize(value->type->un.array.basictype); - if( size == 1 ) - { - int len, clen; - - /* - * Special handling for character arrays. - */ - pnt = (char *) value->addr.off; - len = value->type->un.array.end - value->type->un.array.start + 1; - clen = (DEBUG_nchar + len < DEBUG_maxchar) - ? len : (DEBUG_maxchar - DEBUG_nchar); - - DEBUG_nchar += DEBUG_Printf("\""); - switch (value->cookie) - { - case DV_TARGET: - DEBUG_nchar += DEBUG_PrintStringA(&value->addr, clen); - break; - case DV_HOST: - DEBUG_OutputA(pnt, clen); - break; - default: assert(0); - } - DEBUG_nchar += DEBUG_Printf((len > clen) ? "...\"" : "\""); - break; - } - val1 = *value; - val1.type = value->type->un.array.basictype; - DEBUG_nchar += DEBUG_Printf("{"); - for( i=value->type->un.array.start; i <= value->type->un.array.end; i++ ) - { - DEBUG_Print(&val1, 1, format, level + 1); - val1.addr.off += size; - if( i == value->type->un.array.end ) - { - DEBUG_nchar += DEBUG_Printf("}"); - } - else - { - DEBUG_nchar += DEBUG_Printf(", "); - } - if( DEBUG_nchar > DEBUG_maxchar ) - { - DEBUG_Printf("...}"); - goto leave; - } - } - break; - case DT_FUNC: - DEBUG_Printf("Function at ???\n"); - break; - default: - DEBUG_Printf("Unknown type (%d)\n", value->type->type); - assert(FALSE); - break; - } - -leave: - - if( level == 0 ) - { - DEBUG_nchar += DEBUG_Printf("\n"); - } -} - -static void DEBUG_DumpAType(struct datatype* dt, BOOL deep) -{ - const char* name = (dt->name) ? dt->name : "--none--"; - - switch (dt->type) - { - case DT_BASIC: - DEBUG_Printf("BASIC(%s)", name); - break; - case DT_POINTER: - DEBUG_Printf("POINTER(%s)<", name); - DEBUG_DumpAType(dt->un.pointer.pointsto, FALSE); - DEBUG_Printf(">"); - break; - case DT_STRUCT: - DEBUG_Printf("STRUCT(%s) %d {", - name, dt->un.structure.size); - if (dt->un.structure.members != NULL) + case SymTagBaseType: + if (!types_get_info(linear, lvalue->typeid, TI_GET_LENGTH, &size) || + !types_get_info(linear, lvalue->typeid, TI_GET_BASETYPE, &bt)) { - struct member * m; - for (m = dt->un.structure.members; m; m = m->next) - { - DEBUG_Printf(" %s(%d", m->name, m->offset / 8); - if (m->offset % 8 != 0) - DEBUG_Printf(".%d", m->offset / 8); - DEBUG_Printf("/%d", m->size / 8); - if (m->size % 8 != 0) - DEBUG_Printf(".%d", m->size % 8); - DEBUG_Printf(")"); - } + WINE_ERR("Couldn't get information\n"); + RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); + } + if (size > sizeof(rtn)) + { + WINE_ERR("Size too large (%lu)\n", size); + return 0; + } + /* FIXME: we have an ugly & non portable thing here !!! */ + if (!memory_read_value(lvalue, size, &rtn)) return 0; + + /* now let's do some promotions !! */ + switch (bt) + { + case btInt: + /* propagate sign information */ + if (((size & 3) != 0) && (rtn >> (size * 8 - 1)) != 0) + rtn |= (-1) << (size * 8); + break; + case btUInt: + case btChar: + break; + case btFloat: + RaiseException(DEBUG_STATUS_NOT_AN_INTEGER, 0, 0, NULL); } - DEBUG_Printf(" }"); break; - case DT_ARRAY: - DEBUG_Printf("ARRAY(%s)[", name); - DEBUG_DumpAType(dt->un.array.basictype, FALSE); - DEBUG_Printf("]"); + case SymTagPointerType: + if (!memory_read_value(lvalue, sizeof(void*), &rtn)) return 0; break; - case DT_ENUM: - DEBUG_Printf("ENUM(%s)", name); + case SymTagArrayType: + case SymTagUDT: + assert(lvalue->cookie == DLV_TARGET); + if (!memory_read_value(lvalue, sizeof(rtn), &rtn)) return 0; break; - case DT_BITFIELD: - DEBUG_Printf("BITFIELD(%s)", name); - break; - case DT_FUNC: - DEBUG_Printf("FUNC(%s)(", name); - DEBUG_DumpAType(dt->un.funct.rettype, FALSE); - DEBUG_Printf(")"); + case SymTagEnum: + assert(lvalue->cookie == DLV_TARGET); + if (!memory_read_value(lvalue, sizeof(rtn), &rtn)) return 0; break; default: - WINE_ERR("Unknown type???"); + WINE_FIXME("Unsupported tag %lu\n", tag); + rtn = 0; break; } - if (deep) DEBUG_Printf("\n"); + + return rtn; } -int DEBUG_DumpTypes(void) +/****************************************************************** + * types_deref + * + */ +BOOL types_deref(const struct dbg_lvalue* lvalue, struct dbg_lvalue* result) { - struct datatype * dt = NULL; - int hash; + DWORD tag; + DWORD linear = (DWORD)memory_to_linear_addr(&lvalue->addr); - for (hash = 0; hash < NR_TYPE_HASH + 1; hash++) + assert(lvalue->cookie == DLV_TARGET || lvalue->cookie == DLV_HOST); + + memset(result, 0, sizeof(*result)); + result->typeid = dbg_itype_none; + + /* + * Make sure that this really makes sense. + */ + if (!types_get_info(linear, lvalue->typeid, TI_GET_SYMTAG, &tag) || + tag != SymTagPointerType || + memory_read_value(lvalue, sizeof(result->addr.Offset), &result->addr.Offset) || + !types_get_info(linear, lvalue->typeid, TI_GET_TYPE, &result->typeid)) + return FALSE; + + result->cookie = DLV_TARGET; /* see comment on DEREF below */ + result->addr.Mode = AddrModeFlat; + return TRUE; +} + +/****************************************************************** + * types_get_udt_element_lvalue + * + * Implement a structure derefencement + */ +static BOOL types_get_udt_element_lvalue(struct dbg_lvalue* lvalue, DWORD linear, + DWORD typeid, long int* tmpbuf) +{ + DWORD offset, length, bitoffset; + DWORD bt; + unsigned mask; + + types_get_info(linear, typeid, TI_GET_TYPE, &lvalue->typeid); + types_get_info(linear, typeid, TI_GET_OFFSET, &offset); + + if (types_get_info(linear, typeid, TI_GET_BITPOSITION, &bitoffset)) { - for (dt = type_hash_table[hash]; dt; dt = dt->next) - { - DEBUG_DumpAType(dt, TRUE); - } + types_get_info(linear, typeid, TI_GET_LENGTH, &length); + if (length > sizeof(*tmpbuf)) return FALSE; + /* + * Bitfield operation. We have to extract the field and store + * it in a temporary buffer so that we get it all right. + */ + lvalue->addr.Offset += offset; + if (!memory_read_value(lvalue, sizeof(*tmpbuf), tmpbuf)) return FALSE; + mask = 0xffffffff << length; + *tmpbuf >>= bitoffset & 7; + *tmpbuf &= ~mask; + + lvalue->cookie = DLV_HOST; + lvalue->addr.Mode = AddrModeFlat; + lvalue->addr.Offset = (DWORD)tmpbuf; + + /* + * OK, now we have the correct part of the number. + * Check to see whether the basic type is signed or not, and if so, + * we need to sign extend the number. + */ + if (types_get_info(linear, lvalue->typeid, TI_GET_BASETYPE, &bt) && + bt == btInt && (*tmpbuf & (1 << (length - 1)))) + { + *tmpbuf |= mask; + } + return TRUE; + } + if (types_get_info(linear, typeid, TI_GET_OFFSET, &offset)) + { + lvalue->addr.Offset += offset; + return TRUE; + } + return FALSE; +} + +/****************************************************************** + * types_udt_find_element + * + */ +BOOL types_udt_find_element(struct dbg_lvalue* lvalue, const char* name, long int* tmpbuf) +{ + DWORD linear = (DWORD)memory_to_linear_addr(&lvalue->addr); + DWORD tag, count; + char buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)]; + TI_FINDCHILDREN_PARAMS* fcp = (TI_FINDCHILDREN_PARAMS*)buffer; + WCHAR* ptr; + char tmp[256]; + int i; + + assert(lvalue->cookie == DLV_TARGET || lvalue->cookie == DLV_HOST); + + if (!types_get_info(linear, lvalue->typeid, TI_GET_SYMTAG, &tag) || + tag != SymTagUDT) + return FALSE; + + if (types_get_info(linear, lvalue->typeid, TI_GET_CHILDRENCOUNT, &count)) + { + 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++) + { + 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); + if (strcmp(tmp, name)) continue; + + return types_get_udt_element_lvalue(lvalue, linear, + fcp->ChildId[i], tmpbuf); + } + } + count -= min(count, 256); + fcp->Start += 256; + } + } + return FALSE; +} + +/****************************************************************** + * types_array_index + * + * Grab an element from an array + */ +BOOL types_array_index(const struct dbg_lvalue* lvalue, int index, + struct dbg_lvalue* result) +{ + DWORD tag, length, count; + DWORD linear = (DWORD)memory_to_linear_addr(&lvalue->addr); + + assert(lvalue->cookie == DLV_TARGET || lvalue->cookie == DLV_HOST); + + if (!types_get_info(0, lvalue->typeid, TI_GET_SYMTAG, &tag)) + return FALSE; + switch (tag) + { + case SymTagArrayType: + types_get_info(linear, lvalue->typeid, TI_GET_COUNT, &count); + if (index < 0 || index >= count) return FALSE; + /* fall through */ + case SymTagPointerType: + /* + * Get the base type, so we know how much to index by. + */ + types_get_info(linear, lvalue->typeid, TI_GET_TYPE, &result->typeid); + types_get_info(linear, result->typeid, TI_GET_LENGTH, &length); + /* Contents of array must be on same target */ + result->cookie = lvalue->cookie; + result->addr.Mode = lvalue->addr.Mode; + memory_read_value(lvalue, sizeof(result->addr.Offset), &result->addr.Offset); + result->addr.Offset += index * length; + break; + default: + assert(FALSE); } return TRUE; } -enum debug_type DEBUG_GetType(struct datatype * dt) +struct type_find_t { - return dt->type; + unsigned long result; /* out: the found type */ + enum SymTagEnum tag; /* in: the tag to look for */ + union + { + unsigned long typeid; + const char* name; + } u; +}; + +static BOOL CALLBACK types_cb(PSYMBOL_INFO sym, ULONG size, void* _user) +{ + struct type_find_t* user = (struct type_find_t*)_user; + BOOL ret = TRUE; + DWORD typeid; + + if (sym->Tag == user->tag) + { + switch (user->tag) + { + case SymTagUDT: + if (!strcmp(user->u.name, sym->Name)) + { + user->result = sym->TypeIndex; + ret = FALSE; + } + break; + case SymTagPointerType: + types_get_info(sym->ModBase, sym->TypeIndex, TI_GET_TYPE, &typeid); + if (types_get_info(sym->ModBase, sym->TypeIndex, TI_GET_TYPE, &typeid) && + typeid == user->u.typeid) + { + user->result = sym->TypeIndex; + ret = FALSE; + } + default: break; + } + } + return ret; } -const char* DEBUG_GetName(struct datatype * dt) +/****************************************************************** + * types_find_pointer + * + * Should look up in module based at linear whether (typeid*) exists + * Otherwise, we could create it locally + */ +unsigned long types_find_pointer(unsigned long linear, unsigned long typeid) { - return dt->name; + struct type_find_t f; + f.result = dbg_itype_none; + f.tag = SymTagPointerType; + f.u.typeid = typeid; + SymEnumTypes(dbg_curr_process->handle, linear, types_cb, &f); + return f.result; } -struct datatype * -DEBUG_TypeCast(enum debug_type type, const char * name) +/****************************************************************** + * types_find_type + * + * Should look up in the module based at linear address whether a type + * named 'name' and with the correct tag exists + */ +unsigned long types_find_type(unsigned long linear, const char* name, enum SymTagEnum tag) + { - int hash; - - /* - * The last bucket is special, and is used to hold typeless names. - */ - if( name == NULL ) - { - hash = NR_TYPE_HASH; - } - else - { - hash = type_hash(name); - } - - return DEBUG_LookupDataType(type, hash, name); + struct type_find_t f; + f.result = dbg_itype_none; + f.tag = tag; + f.u.name = name; + SymEnumTypes(dbg_curr_process->handle, linear, types_cb, &f); + return f.result; } -int -DEBUG_PrintTypeCast(const struct datatype * dt) +/*********************************************************************** + * print_value + * + * Implementation of the 'print' command. + */ +void print_value(const struct dbg_lvalue* lvalue, char format, int level) { - const char* name = "none"; + struct dbg_lvalue lvalue_field; + int i; + unsigned long linear; + DWORD tag; + DWORD count; + DWORD size; - if(dt == NULL) + assert(lvalue->cookie == DLV_TARGET || lvalue->cookie == DLV_HOST); + linear = (unsigned long)memory_to_linear_addr(&lvalue->addr); + + if (lvalue->typeid == dbg_itype_none) { - DEBUG_Printf("--invalid--"); - return FALSE; + /* No type, just print the addr value */ + print_bare_address(&lvalue->addr); + goto leave; } - if( dt->name != NULL ) + if (format == 'i' || format == 's' || format == 'w' || format == 'b' || format == 'g') { - name = dt->name; + dbg_printf("Format specifier '%c' is meaningless in 'print' command\n", format); + format = '\0'; } - switch(dt->type) + if (!types_get_info(linear, lvalue->typeid, TI_GET_SYMTAG, &tag)) { - case DT_BASIC: - DEBUG_Printf("%s", name); - break; - case DT_POINTER: - DEBUG_PrintTypeCast(dt->un.pointer.pointsto); - DEBUG_Printf("*"); - break; - case DT_STRUCT: - DEBUG_Printf("struct %s", name); - break; - case DT_ARRAY: - DEBUG_Printf("%s[]", name); - break; - case DT_ENUM: - DEBUG_Printf("enum %s", name); - break; - case DT_BITFIELD: - DEBUG_Printf("unsigned %s", name); - break; - case DT_FUNC: - DEBUG_PrintTypeCast(dt->un.funct.rettype); - DEBUG_Printf("(*%s)()", name); - break; + WINE_FIXME("---error\n"); + return; + } + switch (tag) + { + case SymTagBaseType: + case SymTagEnum: + case SymTagPointerType: + print_basic(lvalue, 1, format); + break; + case SymTagUDT: + 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]; + long int tmpbuf; + + dbg_printf("{"); + 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++) + { + 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); + dbg_printf("%s=", tmp); + HeapFree(GetProcessHeap(), 0, ptr); + lvalue_field = *lvalue; + if (types_get_udt_element_lvalue(&lvalue_field, linear, + fcp->ChildId[i], &tmpbuf)) + { + print_value(&lvalue_field, format, level + 1); + } + if (i < min(fcp->Count, count) - 1 || count > 256) dbg_printf(", "); + } + } + count -= min(count, 256); + fcp->Start += 256; + } + dbg_printf("}"); + } + break; + case SymTagArrayType: + /* + * Loop over all of the entries, printing stuff as we go. + */ + count = 1; size = 1; + types_get_info(linear, lvalue->typeid, TI_GET_COUNT, &count); + types_get_info(linear, lvalue->typeid, TI_GET_LENGTH, &size); + + if (size == count) + { + unsigned len; + char buffer[256]; + /* + * Special handling for character arrays. + */ + /* FIXME should check basic type here (should be a char!!!!)... */ + len = min(count, sizeof(buffer)); + memory_get_string(dbg_curr_thread->handle, + memory_to_linear_addr(&lvalue->addr), + lvalue->cookie, TRUE, buffer, len); + dbg_printf("\"%s%s\"", buffer, (len < count) ? "..." : ""); + break; + } + lvalue_field = *lvalue; + types_get_info(linear, lvalue->typeid, TI_GET_TYPE, &lvalue_field.typeid); + dbg_printf("{"); + for (i = 0; i < count; i++) + { + print_value(&lvalue_field, format, level + 1); + lvalue_field.addr.Offset += size / count; + dbg_printf((i == count - 1) ? "}" : ", "); + } + break; + case SymTagFunctionType: + dbg_printf("Function "); + print_bare_address(&lvalue->addr); + dbg_printf(": "); + types_print_type(linear, lvalue->typeid, FALSE); + break; default: - WINE_ERR("Unknown type???\n"); - break; + WINE_FIXME("Unknown tag (%lu)\n", tag); + RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); + break; } - return TRUE; +leave: + + if (level == 0) dbg_printf("\n"); } -int DEBUG_PrintType( const DBG_VALUE *value ) +static BOOL CALLBACK print_types_cb(PSYMBOL_INFO sym, ULONG size, void* ctx) { - assert(value->cookie == DV_TARGET || value->cookie == DV_HOST); - - if (!value->type) - { - DEBUG_Printf("Unknown type\n"); - return FALSE; - } - if (!DEBUG_PrintTypeCast(value->type)) - return FALSE; - DEBUG_Printf("\n"); - return TRUE; + types_print_type(sym->ModBase, sym->TypeIndex, TRUE); + dbg_printf("\n"); + return TRUE; +} + +static BOOL CALLBACK print_types_mod_cb(PSTR mod_name, DWORD base, void* ctx) +{ + return SymEnumTypes(dbg_curr_process->handle, base, print_types_cb, ctx); +} + +int print_types(void) +{ + SymEnumerateModules(dbg_curr_process->handle, print_types_mod_cb, NULL); + return 0; +} + +int types_print_type(DWORD linear, DWORD typeid, BOOL details) +{ + WCHAR* ptr; + char tmp[256]; + const char* name; + DWORD tag, subtype, count; + + if (typeid == dbg_itype_none || !types_get_info(linear, typeid, TI_GET_SYMTAG, &tag)) + { + dbg_printf("--invalid--<%lxh>--", typeid); + return FALSE; + } + + if (types_get_info(linear, typeid, TI_GET_SYMNAME, &ptr) && ptr) + { + WideCharToMultiByte(CP_ACP, 0, ptr, -1, tmp, sizeof(tmp), NULL, NULL); + name = tmp; + HeapFree(GetProcessHeap(), 0, ptr); + } + else name = "--none--"; + + switch (tag) + { + case SymTagBaseType: + if (details) dbg_printf("Basic<%s>", name); else dbg_printf("%s", name); + break; + case SymTagPointerType: + types_get_info(linear, typeid, TI_GET_TYPE, &subtype); + types_print_type(linear, subtype, details); + dbg_printf("*"); + break; + case SymTagUDT: + types_get_info(linear, typeid, TI_GET_UDTKIND, &subtype); + switch (subtype) + { + case UdtStruct: dbg_printf("struct %s", name); break; + case UdtUnion: dbg_printf("union %s", name); break; + case UdtClass: dbg_printf("class %s", name); break; + } + if (details && + types_get_info(linear, 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]; + int i; + + dbg_printf(" {"); + + fcp->Start = 0; + while (count) + { + fcp->Count = min(count, 256); + if (types_get_info(linear, typeid, TI_FINDCHILDREN, fcp)) + { + for (i = 0; i < min(fcp->Count, count); i++) + { + 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); + if (types_get_info(linear, fcp->ChildId[i], TI_GET_TYPE, &subtype)) + { + dbg_printf(":"); + types_print_type(linear, subtype, details); + } + if (i < min(fcp->Count, count) - 1 || count > 256) dbg_printf(", "); + } + } + count -= min(count, 256); + fcp->Start += 256; + } + dbg_printf("}"); + } + break; + case SymTagArrayType: + types_get_info(linear, typeid, TI_GET_TYPE, &subtype); + types_print_type(linear, subtype, details); + dbg_printf(" %s[]", name); + break; + case SymTagEnum: + dbg_printf("enum %s", name); + break; + case SymTagFunctionType: + types_get_info(linear, typeid, TI_GET_TYPE, &subtype); + types_print_type(linear, subtype, FALSE); + dbg_printf(" (*%s)(", name); + if (types_get_info(linear, typeid, TI_GET_CHILDRENCOUNT, &count)) + { + char buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)]; + TI_FINDCHILDREN_PARAMS* fcp = (TI_FINDCHILDREN_PARAMS*)buffer; + int i; + + fcp->Start = 0; + while (count) + { + fcp->Count = min(count, 256); + if (types_get_info(linear, typeid, TI_FINDCHILDREN, fcp)) + { + for (i = 0; i < min(fcp->Count, count); i++) + { + types_print_type(linear, fcp->ChildId[i], FALSE); + if (i < min(fcp->Count, count) - 1 || count > 256) dbg_printf(", "); + } + } + count -= min(count, 256); + fcp->Start += 256; + } + } + dbg_printf(")"); + break; + default: + WINE_ERR("Unknown type %lu for %s\n", tag, name); + break; + } + + return TRUE; +} + +BOOL types_get_info(unsigned long modbase, unsigned long typeid, + IMAGEHLP_SYMBOL_TYPE_INFO ti, void* pInfo) +{ + if (typeid == dbg_itype_none) return FALSE; + if (typeid < dbg_itype_first) + { + BOOL ret; + DWORD tag; + + ret = SymGetTypeInfo(dbg_curr_process->handle, modbase, typeid, ti, pInfo); + if (!ret && ti == TI_GET_LENGTH && + (!SymGetTypeInfo(dbg_curr_process->handle, modbase, typeid, + TI_GET_SYMTAG, &tag) || tag == SymTagData)) + { + WINE_FIXME("get length on symtag data is no longer supported\n"); + assert(0); + } + return ret; + } + assert(modbase); + +/* helper to typecast pInfo to its expected type (_t) */ +#define X(_t) (*((_t*)pInfo)) + + switch (typeid) + { + case dbg_itype_unsigned_int: + switch (ti) + { + case TI_GET_SYMTAG: X(DWORD) = SymTagBaseType; break; + case TI_GET_LENGTH: X(DWORD) = 4; break; + case TI_GET_BASETYPE: X(DWORD) = btUInt; break; + default: WINE_FIXME("unsupported %u for u-int\n", ti); return FALSE; + } + break; + case dbg_itype_signed_int: + switch (ti) + { + case TI_GET_SYMTAG: X(DWORD) = SymTagBaseType; break; + case TI_GET_LENGTH: X(DWORD) = 4; break; + case TI_GET_BASETYPE: X(DWORD) = btInt; break; + default: WINE_FIXME("unsupported %u for s-int\n", ti); return FALSE; + } + break; + case dbg_itype_unsigned_short_int: + switch (ti) + { + case TI_GET_SYMTAG: X(DWORD) = SymTagBaseType; break; + case TI_GET_LENGTH: X(DWORD) = 2; break; + case TI_GET_BASETYPE: X(DWORD) = btUInt; break; + default: WINE_FIXME("unsupported %u for u-short int\n", ti); return FALSE; + } + break; + case dbg_itype_signed_short_int: + switch (ti) + { + case TI_GET_SYMTAG: X(DWORD) = SymTagBaseType; break; + case TI_GET_LENGTH: X(DWORD) = 2; break; + case TI_GET_BASETYPE: X(DWORD) = btInt; break; + default: WINE_FIXME("unsupported %u for s-short int\n", ti); return FALSE; + } + break; + case dbg_itype_unsigned_char_int: + switch (ti) + { + case TI_GET_SYMTAG: X(DWORD) = SymTagBaseType; break; + case TI_GET_LENGTH: X(DWORD) = 1; break; + case TI_GET_BASETYPE: X(DWORD) = btUInt; break; + default: WINE_FIXME("unsupported %u for u-char int\n", ti); return FALSE; + } + break; + case dbg_itype_signed_char_int: + switch (ti) + { + case TI_GET_SYMTAG: X(DWORD) = SymTagBaseType; break; + case TI_GET_LENGTH: X(DWORD) = 1; break; + case TI_GET_BASETYPE: X(DWORD) = btInt; break; + default: WINE_FIXME("unsupported %u for s-char int\n", ti); return FALSE; + } + break; + case dbg_itype_char: + switch (ti) + { + case TI_GET_SYMTAG: X(DWORD) = SymTagBaseType; break; + case TI_GET_LENGTH: X(DWORD) = 1; break; + case TI_GET_BASETYPE: X(DWORD) = btChar; break; + default: WINE_FIXME("unsupported %u for char int\n", ti); return FALSE; + } + break; + case dbg_itype_astring: + switch (ti) + { + case TI_GET_SYMTAG: X(DWORD) = SymTagPointerType; break; + case TI_GET_LENGTH: X(DWORD) = 4; break; + case TI_GET_TYPE: X(DWORD) = dbg_itype_char; break; + default: WINE_FIXME("unsupported %u for a string\n", ti); return FALSE; + } + break; + default: WINE_FIXME("unsupported typeid 0x%lx\n", typeid); + } + +#undef X + return TRUE; } diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index 78bea5ab24e..733f68fd282 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -1,8 +1,6 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ - /* Wine internal debugger * Interface to Windows debugger API - * 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 @@ -23,90 +21,99 @@ #include "wine/port.h" #include -#include #include #include #include "debugger.h" -#include "wincon.h" -#include "winreg.h" -#include "wingdi.h" -#include "winuser.h" #include "winternl.h" -#include "excpt.h" #include "wine/exception.h" #include "wine/library.h" -#include "winnls.h" #include "wine/debug.h" +/* TODO list: + * + * - minidump + * + allow winedbg in automatic mode to create a minidump (or add another option + * for that) + * + set a mode where winedbg would start (postmortem debugging) from a minidump + * - CPU adherence + * + we always assume the stack grows has an i386 (ie downwards) + * - UI + * + enable back the limited output (depth of structure printing and number of + * lines) + * - symbol management: + * + in most of the module enumeration for symbol lookup, we don't search in + * the ELF modules (should we turn wine extented flag for ELF modules on ?) + * + symbol table loading is broken + * - type management: + * + some bits of internal types are missing (like type casts and the address + * operator) + * + the type for an enum's value is always inferred as int (winedbg & dbghelp) + * + most of the code implies that sizeof(void*) = sizeof(int) + * + all computations should be made on long long + * o expr computations are in int:s + * o bitfield size is on a 4-bytes + * + some bits of internal types are missing (like type casts and the address + * operator) + * - execution + * + set a better fix for gdb (proxy mode) than the step-mode hack + * + implement function call in debuggee + * + trampoline management is broken when getting 16 <=> 32 thunk destination + * address + * + thunking of delayed imports doesn't work as expected (ie, when stepping, + * it currently stops at first insn with line number during the library + * loading). We should identify this (__wine_delay_import) and set a + * breakpoint instead of single stepping the library loading. + * + Ctrl-C (in debugger) doesn't work if we've attached to the debuggee (but + * works if winedbg started the debuggee) + */ + WINE_DEFAULT_DEBUG_CHANNEL(winedbg); -DBG_PROCESS* DEBUG_CurrProcess = NULL; -DBG_THREAD* DEBUG_CurrThread = NULL; -DWORD DEBUG_CurrTid; -DWORD DEBUG_CurrPid; -CONTEXT DEBUG_context; -BOOL DEBUG_InteractiveP = FALSE; -static BOOL DEBUG_InException = FALSE; -int curr_frame = 0; -static char* DEBUG_LastCmdLine = NULL; +struct dbg_process* dbg_curr_process = NULL; +struct dbg_thread* dbg_curr_thread = NULL; +DWORD dbg_curr_tid; +DWORD dbg_curr_pid; +CONTEXT dbg_context; +int dbg_curr_frame = 0; +BOOL dbg_interactiveP = FALSE; +static unsigned dbg_in_exception = FALSE; +static char* dbg_last_cmd_line = NULL; -static DBG_PROCESS* DEBUG_ProcessList = NULL; -static enum {none_mode = 0, winedbg_mode, automatic_mode, gdb_mode} local_mode; +static struct dbg_process* dbg_process_list = NULL; +static enum {none_mode = 0, winedbg_mode, automatic_mode, gdb_mode} dbg_action_mode; -DBG_INTVAR DEBUG_IntVars[DBG_IV_LAST]; +struct dbg_internal_var dbg_internal_vars[DBG_IV_LAST]; +const struct dbg_internal_var* dbg_context_vars; +static HANDLE dbg_houtput; -static HANDLE hOutput; -void DEBUG_OutputA(const char* buffer, int len) +void dbg_outputA(const char* buffer, int len) { - WriteFile(hOutput, buffer, len, NULL, NULL); + WriteFile(dbg_houtput, buffer, len, NULL, NULL); } -void DEBUG_OutputW(const WCHAR* buffer, int len) +void dbg_outputW(const WCHAR* buffer, int len) { - char* ansi = NULL; - int newlen; + char* ansi = NULL; + int newlen; - /* do a serious Unicode to ANSI conversion - FIXME: should CP_ACP be GetConsoleCP()? */ - newlen = WideCharToMultiByte(CP_ACP, 0, buffer, len, NULL, 0, NULL, NULL); - if(newlen) - { - ansi = (char*)DBG_alloc(newlen); - if(ansi) - { - WideCharToMultiByte(CP_ACP, 0, buffer, len, ansi, newlen, NULL, NULL); - } - } - - /* fall back to a simple Unicode to ANSI conversion in case WC2MB failed */ - if(!ansi) - { - ansi = DBG_alloc(len); - if(ansi) - { - int i; - for(i = 0; i < len; i++) - { - ansi[i] = (char)buffer[i]; - } - - newlen = len; - } - /* else we are having REALLY bad luck today */ - } - - if(ansi) - { - DEBUG_OutputA(ansi, newlen); - DBG_free(ansi); - } + /* do a serious Unicode to ANSI conversion + * FIXME: should CP_ACP be GetConsoleCP()? + */ + newlen = WideCharToMultiByte(CP_ACP, 0, buffer, len, NULL, 0, NULL, NULL); + if (newlen) + { + if (!(ansi = HeapAlloc(GetProcessHeap(), 0, newlen))) return; + WideCharToMultiByte(CP_ACP, 0, buffer, len, ansi, newlen, NULL, NULL); + dbg_outputA(ansi, newlen); + HeapFree(GetProcessHeap(), 0, ansi); + } } -int DEBUG_Printf(const char* format, ...) +int dbg_printf(const char* format, ...) { -static char buf[4*1024]; + static char buf[4*1024]; va_list valist; int len; @@ -114,84 +121,107 @@ static char buf[4*1024]; len = vsnprintf(buf, sizeof(buf), format, valist); va_end(valist); - if (len <= -1 || len >= sizeof(buf)) { + if (len <= -1 || len >= sizeof(buf)) + { len = sizeof(buf) - 1; buf[len] = 0; buf[len - 1] = buf[len - 2] = buf[len - 3] = '.'; } - DEBUG_OutputA(buf, len); + dbg_outputA(buf, len); return len; } -static BOOL DEBUG_IntVarsRW(int read) +static unsigned dbg_load_internal_vars(void) { - HKEY hkey; - DWORD type = REG_DWORD; - DWORD val; - DWORD count = sizeof(val); - int i; - DBG_INTVAR* div = DEBUG_IntVars; + HKEY hkey; + DWORD type = REG_DWORD; + DWORD val; + DWORD count = sizeof(val); + int i; + struct dbg_internal_var* div = dbg_internal_vars; - if (read) { /* initializes internal vars table */ -#define INTERNAL_VAR(_var,_val,_ref,_typ) \ +#define INTERNAL_VAR(_var,_val,_ref,_tid) \ div->val = _val; div->name = #_var; div->pval = _ref; \ - div->type = DEBUG_GetBasicType(_typ); div++; + div->typeid = _tid; div++; #include "intvar.h" #undef INTERNAL_VAR - } - if (RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey)) { + if (RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey)) + { WINE_ERR("Cannot create WineDbg key in registry\n"); return FALSE; } - for (i = 0; i < DBG_IV_LAST; i++) { - if (read) { - if (!DEBUG_IntVars[i].pval) { - if (!RegQueryValueEx(hkey, DEBUG_IntVars[i].name, 0, - &type, (LPSTR)&val, &count)) - DEBUG_IntVars[i].val = val; - DEBUG_IntVars[i].pval = &DEBUG_IntVars[i].val; - } else { - *DEBUG_IntVars[i].pval = 0; - } - } else { - /* FIXME: type should be infered from basic type -if any- of intvar */ - if (DEBUG_IntVars[i].pval == &DEBUG_IntVars[i].val) - RegSetValueEx(hkey, DEBUG_IntVars[i].name, 0, - type, (LPCVOID)DEBUG_IntVars[i].pval, count); - } + for (i = 0; i < DBG_IV_LAST; i++) + { + if (!dbg_internal_vars[i].pval) + { + if (!RegQueryValueEx(hkey, dbg_internal_vars[i].name, 0, + &type, (LPSTR)&val, &count)) + dbg_internal_vars[i].val = val; + dbg_internal_vars[i].pval = &dbg_internal_vars[i].val; + } + } + RegCloseKey(hkey); + /* set up the debug variables for the CPU context */ + dbg_context_vars = be_cpu->init_registers(&dbg_context); + return TRUE; +} + +static unsigned dbg_save_internal_vars(void) +{ + HKEY hkey; + int i; + + if (RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey)) + { + WINE_ERR("Cannot create WineDbg key in registry\n"); + return FALSE; + } + + for (i = 0; i < DBG_IV_LAST; i++) + { + /* FIXME: type should be infered from basic type -if any- of intvar */ + if (dbg_internal_vars[i].pval == &dbg_internal_vars[i].val) + RegSetValueEx(hkey, dbg_internal_vars[i].name, 0, + REG_DWORD, (const void*)dbg_internal_vars[i].pval, + sizeof(*dbg_internal_vars[i].pval)); } RegCloseKey(hkey); return TRUE; } -DBG_INTVAR* DEBUG_GetIntVar(const char* name) +const struct dbg_internal_var* dbg_get_internal_var(const char* name) { - int i; + const struct dbg_internal_var* div; - for (i = 0; i < DBG_IV_LAST; i++) { - if (!strcmp(DEBUG_IntVars[i].name, name)) - return &DEBUG_IntVars[i]; + for (div = &dbg_internal_vars[DBG_IV_LAST - 1]; div >= dbg_internal_vars; div--) + { + if (!strcmp(div->name, name)) return div; } + for (div = dbg_context_vars; div->name; div++) + { + if (!strcasecmp(div->name, name)) return div; + } + return NULL; } -DBG_PROCESS* DEBUG_GetProcess(DWORD pid) +struct dbg_process* dbg_get_process(DWORD pid) { - DBG_PROCESS* p; + struct dbg_process* p; - for (p = DEBUG_ProcessList; p; p = p->next) + for (p = dbg_process_list; p; p = p->next) if (p->pid == pid) break; return p; } -DBG_PROCESS* DEBUG_AddProcess(DWORD pid, HANDLE h, const char* imageName) +struct dbg_process* dbg_add_process(DWORD pid, HANDLE h, const char* imageName) { - DBG_PROCESS* p; + struct dbg_process* p; - if ((p = DEBUG_GetProcess(pid))) + if ((p = dbg_get_process(pid))) { if (p->handle != 0) { @@ -200,86 +230,94 @@ DBG_PROCESS* DEBUG_AddProcess(DWORD pid, HANDLE h, const char* imageName) else { p->handle = h; - p->imageName = imageName ? DBG_strdup(imageName) : NULL; + p->imageName = imageName ? strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(imageName) + 1), imageName) : NULL; } return p; } - if (!(p = DBG_alloc(sizeof(DBG_PROCESS)))) return NULL; + if (!(p = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_process)))) return NULL; p->handle = h; p->pid = pid; - p->imageName = imageName ? DBG_strdup(imageName) : NULL; + p->imageName = imageName ? strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(imageName) + 1), imageName) : NULL; p->threads = NULL; - p->num_threads = 0; p->continue_on_first_exception = FALSE; - p->modules = NULL; - p->num_modules = 0; - p->next_index = 0; - p->dbg_hdr_addr = 0; + p->next_bp = 1; /* breakpoint 0 is reserved for step-over */ + memset(p->bp, 0, sizeof(p->bp)); p->delayed_bp = NULL; p->num_delayed_bp = 0; - p->next = DEBUG_ProcessList; + p->next = dbg_process_list; p->prev = NULL; - if (DEBUG_ProcessList) DEBUG_ProcessList->prev = p; - DEBUG_ProcessList = p; + if (dbg_process_list) dbg_process_list->prev = p; + dbg_process_list = p; return p; } -void DEBUG_DelProcess(DBG_PROCESS* p) +void dbg_del_process(struct dbg_process* p) { int i; - while (p->threads) DEBUG_DelThread(p->threads); + while (p->threads) dbg_del_thread(p->threads); for (i = 0; i < p->num_delayed_bp; i++) if (p->delayed_bp[i].is_symbol) - DBG_free(p->delayed_bp[i].u.symbol.name); + HeapFree(GetProcessHeap(), 0, p->delayed_bp[i].u.symbol.name); - DBG_free(p->delayed_bp); + HeapFree(GetProcessHeap(), 0, p->delayed_bp); if (p->prev) p->prev->next = p->next; if (p->next) p->next->prev = p->prev; - if (p == DEBUG_ProcessList) DEBUG_ProcessList = p->next; - if (p == DEBUG_CurrProcess) DEBUG_CurrProcess = NULL; - DBG_free((char*)p->imageName); - DBG_free(p); + if (p == dbg_process_list) dbg_process_list = p->next; + if (p == dbg_curr_process) dbg_curr_process = NULL; + HeapFree(GetProcessHeap(), 0, (char*)p->imageName); + HeapFree(GetProcessHeap(), 0, p); } -static void DEBUG_InitCurrProcess(void) +static void dbg_init_current_process(void) { } -BOOL DEBUG_ProcessGetString(char* buffer, int size, HANDLE hp, LPSTR addr) +struct mod_loader_info { - DWORD sz; - *(WCHAR*)buffer = 0; - return (addr && ReadProcessMemory(hp, addr, buffer, size, &sz)); -} + HANDLE handle; + IMAGEHLP_MODULE* imh_mod; +}; -BOOL DEBUG_ProcessGetStringIndirect(char* buffer, int size, HANDLE hp, LPVOID addr, BOOL unicode) +static BOOL CALLBACK mod_loader_cb(PSTR mod_name, DWORD base, void* ctx) { - LPVOID ad; - DWORD sz; + struct mod_loader_info* mli = (struct mod_loader_info*)ctx; - if (addr && ReadProcessMemory(hp, addr, &ad, sizeof(ad), &sz) && sz == sizeof(ad) && ad) + if (!strcmp(mod_name, "")) { - if (!unicode) ReadProcessMemory(hp, ad, buffer, size, &sz); - else - { - WCHAR *buffW = DBG_alloc( size * sizeof(WCHAR) ); - ReadProcessMemory(hp, ad, buffW, size*sizeof(WCHAR), &sz); - WideCharToMultiByte( CP_ACP, 0, buffW, sz/sizeof(WCHAR), buffer, size, NULL, NULL ); - DBG_free(buffW); - } - return TRUE; + if (SymGetModuleInfo(mli->handle, base, mli->imh_mod)) + return FALSE; /* stop enum */ } - *(WCHAR*)buffer = 0; - return FALSE; + return TRUE; } -DBG_THREAD* DEBUG_GetThread(DBG_PROCESS* p, DWORD tid) +BOOL dbg_get_debuggee_info(HANDLE hProcess, IMAGEHLP_MODULE* imh_mod) { - DBG_THREAD* t; + struct mod_loader_info mli; + DWORD opt; + + /* this will resynchronize builtin dbghelp's internal ELF module list */ + SymLoadModule(hProcess, 0, 0, 0, 0, 0); + mli.handle = hProcess; + mli.imh_mod = imh_mod; + imh_mod->SizeOfStruct = sizeof(*imh_mod); + imh_mod->BaseOfImage = 0; + /* this is a wine specific options to return also ELF modules in the + * enumeration + */ + SymSetOptions((opt = SymGetOptions()) | 0x40000000); + SymEnumerateModules(hProcess, mod_loader_cb, (void*)&mli); + SymSetOptions(opt); + + return imh_mod->BaseOfImage != 0; +} + +struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid) +{ + struct dbg_thread* t; if (!p) return NULL; for (t = p->threads; t; t = t->next) @@ -287,25 +325,24 @@ DBG_THREAD* DEBUG_GetThread(DBG_PROCESS* p, DWORD tid) return t; } -DBG_THREAD* DEBUG_AddThread(DBG_PROCESS* p, DWORD tid, - HANDLE h, LPVOID start, LPVOID teb) +struct dbg_thread* dbg_add_thread(struct dbg_process* p, DWORD tid, + HANDLE h, void* teb) { - DBG_THREAD* t = DBG_alloc(sizeof(DBG_THREAD)); + struct dbg_thread* t = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_thread)); + if (!t) return NULL; t->handle = h; t->tid = tid; - t->start = start; t->teb = teb; t->process = p; t->wait_for_first_exception = 0; - t->exec_mode = EXEC_CONT; + t->exec_mode = dbg_exec_cont; t->exec_count = 0; - snprintf(t->name, sizeof(t->name), "%08lx", tid); + snprintf(t->name, sizeof(t->name), "0x%08lx", tid); - p->num_threads++; t->next = p->threads; t->prev = NULL; if (p->threads) p->threads->prev = t; @@ -314,100 +351,104 @@ DBG_THREAD* DEBUG_AddThread(DBG_PROCESS* p, DWORD tid, return t; } -static void DEBUG_InitCurrThread(void) +static void dbg_init_current_thread(void* start) { - if (DEBUG_CurrThread->start) { - if (DEBUG_CurrThread->process->num_threads == 1 || - DBG_IVAR(BreakAllThreadsStartup)) { - DBG_VALUE value; + if (start) + { + if (dbg_curr_thread->process->threads && + !dbg_curr_thread->process->threads->next && /* first thread ? */ + DBG_IVAR(BreakAllThreadsStartup)) + { + ADDRESS addr; - DEBUG_SetBreakpoints(FALSE); - value.type = NULL; - value.cookie = DV_TARGET; - value.addr.seg = 0; - value.addr.off = (DWORD)DEBUG_CurrThread->start; - DEBUG_AddBreakpointFromValue(&value); - DEBUG_SetBreakpoints(TRUE); + break_set_xpoints(FALSE); + addr.Mode = AddrModeFlat; + addr.Offset = (DWORD)start; + break_add_break(&addr, TRUE); + break_set_xpoints(TRUE); } - } else { - DEBUG_CurrThread->wait_for_first_exception = 1; + } + else + { + dbg_curr_thread->wait_for_first_exception = 1; } } -void DEBUG_DelThread(DBG_THREAD* t) +void dbg_del_thread(struct dbg_thread* t) { if (t->prev) t->prev->next = t->next; if (t->next) t->next->prev = t->prev; if (t == t->process->threads) t->process->threads = t->next; - t->process->num_threads--; - if (t == DEBUG_CurrThread) DEBUG_CurrThread = NULL; - DBG_free(t); + if (t == dbg_curr_thread) dbg_curr_thread = NULL; + HeapFree(GetProcessHeap(), 0, t); } -static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de); +static unsigned dbg_handle_debug_event(DEBUG_EVENT* de); /****************************************************************** - * DEBUG_Attach + * dbg_attach_debuggee * * Sets the debuggee to * cofe instructs winedbg what to do when first exception is received * (break=FALSE, continue=TRUE) - * wfe is set to TRUE if DEBUG_Attach should also proceed with all debug events + * wfe is set to TRUE if dbg_attach_debuggee should also proceed with all debug events * until the first exception is received (aka: attach to an already running process) */ -BOOL DEBUG_Attach(DWORD pid, BOOL cofe, BOOL wfe) +BOOL dbg_attach_debuggee(DWORD pid, BOOL cofe, BOOL wfe) { DEBUG_EVENT de; - if (!(DEBUG_CurrProcess = DEBUG_AddProcess(pid, 0, NULL))) return FALSE; + if (!(dbg_curr_process = dbg_add_process(pid, 0, NULL))) return FALSE; - if (!DebugActiveProcess(pid)) { - DEBUG_Printf("Can't attach process %lx: error %ld\n", pid, GetLastError()); - DEBUG_DelProcess(DEBUG_CurrProcess); + if (!DebugActiveProcess(pid)) + { + dbg_printf("Can't attach process %lx: error %ld\n", pid, GetLastError()); + dbg_del_process(dbg_curr_process); return FALSE; } - DEBUG_CurrProcess->continue_on_first_exception = cofe; + dbg_curr_process->continue_on_first_exception = cofe; if (wfe) /* shall we proceed all debug events until we get an exception ? */ { - DEBUG_InteractiveP = FALSE; - while (DEBUG_CurrProcess && WaitForDebugEvent(&de, INFINITE)) + dbg_interactiveP = FALSE; + while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE)) { - if (DEBUG_HandleDebugEvent(&de)) break; + if (dbg_handle_debug_event(&de)) break; } - if (DEBUG_CurrProcess) DEBUG_InteractiveP = TRUE; + if (dbg_curr_process) dbg_interactiveP = TRUE; } return TRUE; } -BOOL DEBUG_Detach(void) +BOOL dbg_detach_debuggee(void) { /* remove all set breakpoints in debuggee code */ - DEBUG_SetBreakpoints(FALSE); + break_set_xpoints(FALSE); /* needed for single stepping (ugly). - * should this be handled inside the server ??? */ -#ifdef __i386__ - DEBUG_context.EFlags &= ~STEP_FLAG; -#endif - SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context); - DebugActiveProcessStop(DEBUG_CurrProcess->pid); - DEBUG_DelProcess(DEBUG_CurrProcess); - /* FIXME: should zero out the symbol table too */ + * should this be handled inside the server ??? + */ + be_cpu->single_step(&dbg_context, FALSE); + SetThreadContext(dbg_curr_thread->handle, &dbg_context); + if (dbg_in_exception) + ContinueDebugEvent(dbg_curr_pid, dbg_curr_tid, DBG_CONTINUE); + if (!DebugActiveProcessStop(dbg_curr_pid)) return FALSE; + dbg_del_process(dbg_curr_process); + return TRUE; } -static BOOL DEBUG_FetchContext(void) +static unsigned dbg_fetch_context(void) { - DEBUG_context.ContextFlags = CONTEXT_CONTROL - | CONTEXT_INTEGER + dbg_context.ContextFlags = CONTEXT_CONTROL + | CONTEXT_INTEGER #ifdef CONTEXT_SEGMENTS - | CONTEXT_SEGMENTS + | CONTEXT_SEGMENTS #endif #ifdef CONTEXT_DEBUG_REGISTERS - | CONTEXT_DEBUG_REGISTERS + | CONTEXT_DEBUG_REGISTERS #endif - ; - if (!GetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context)) + ; + if (!GetThreadContext(dbg_curr_thread->handle, &dbg_context)) { WINE_WARN("Can't get thread's context\n"); return FALSE; @@ -415,112 +456,99 @@ static BOOL DEBUG_FetchContext(void) return TRUE; } -static BOOL DEBUG_ExceptionProlog(BOOL is_debug, BOOL force, DWORD code) +static unsigned dbg_exception_prolog(BOOL is_debug, BOOL force, DWORD code) { - DBG_ADDR addr; - int newmode; + ADDRESS addr; - DEBUG_InException = TRUE; - DEBUG_GetCurrentAddress(&addr); - DEBUG_SuspendExecution(); + dbg_in_exception = TRUE; + memory_get_current_pc(&addr); + break_suspend_execution(); if (!is_debug) { - if (!addr.seg) - DEBUG_Printf(" in 32-bit code (0x%08lx)", addr.off); - else - switch (DEBUG_GetSelectorType(addr.seg)) - { - case MODE_32: - DEBUG_Printf(" in 32-bit code (%04lx:%08lx)", addr.seg, addr.off); - break; - case MODE_16: - DEBUG_Printf(" in 16-bit code (%04lx:%04lx)", addr.seg, addr.off); - break; - case MODE_VM86: - DEBUG_Printf(" in vm86 code (%04lx:%04lx)", addr.seg, addr.off); - break; - case MODE_INVALID: - DEBUG_Printf(" bad CS (%lx)", addr.seg); - break; + switch (addr.Mode) + { + case AddrModeFlat: dbg_printf(" in 32-bit code (0x%08lx)", addr.Offset); break; + case AddrModeReal: dbg_printf(" in vm86 code (%04x:%04lx)", addr.Segment, addr.Offset); break; + case AddrMode1616: dbg_printf(" in 16-bit code (%04x:%04lx)", addr.Segment, addr.Offset); break; + default: dbg_printf(" bad address"); } - DEBUG_Printf(".\n"); + dbg_printf(".\n"); } - DEBUG_LoadEntryPoints("Loading new modules symbols:\n"); + /* this will resynchronize builtin dbghelp's internal ELF module list */ + SymLoadModule(dbg_curr_process->handle, 0, 0, 0, 0, 0); + /* * Do a quiet backtrace so that we have an idea of what the situation * is WRT the source files. */ - DEBUG_BackTrace(DEBUG_CurrTid, FALSE); + stack_backtrace(dbg_curr_tid, FALSE); if (!force && is_debug && - DEBUG_ShouldContinue(&addr, code, - &DEBUG_CurrThread->exec_count)) + break_should_continue(&addr, code, &dbg_curr_thread->exec_count)) return FALSE; - if ((newmode = DEBUG_GetSelectorType(addr.seg)) == MODE_INVALID) newmode = MODE_32; - if (newmode != DEBUG_CurrThread->dbg_mode) + if (addr.Mode != dbg_curr_thread->addr_mode) { - static const char * const names[] = { "???", "16-bit", "32-bit", "vm86" }; - DEBUG_Printf("In %s mode.\n", names[newmode] ); - DEBUG_CurrThread->dbg_mode = newmode; + const char* name = NULL; + + switch (addr.Mode) + { + case AddrMode1616: name = "16 bit"; break; + case AddrMode1632: name = "X?X??X"; break; + case AddrModeReal: name = "vm86"; break; + case AddrModeFlat: name = "32 bit"; break; + } + + dbg_printf("In %s mode.\n", name); + dbg_curr_thread->addr_mode = addr.Mode; } - DEBUG_DoDisplay(); + display_print(); - if (!is_debug && !force) { + if (!is_debug && !force) + { /* This is a real crash, dump some info */ - DEBUG_InfoRegisters(&DEBUG_context); - DEBUG_InfoStack(); -#ifdef __i386__ - if (DEBUG_CurrThread->dbg_mode == MODE_16) { - DEBUG_InfoSegments(DEBUG_context.SegDs >> 3, 1); - if (DEBUG_context.SegEs != DEBUG_context.SegDs) - DEBUG_InfoSegments(DEBUG_context.SegEs >> 3, 1); - } - DEBUG_InfoSegments(DEBUG_context.SegFs >> 3, 1); -#endif - DEBUG_BackTrace(DEBUG_CurrTid, TRUE); + be_cpu->print_context(dbg_curr_thread->handle, &dbg_context); + stack_info(); + be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context); + stack_backtrace(dbg_curr_tid, TRUE); } if (!is_debug || - (DEBUG_CurrThread->exec_mode == EXEC_STEPI_OVER) || - (DEBUG_CurrThread->exec_mode == EXEC_STEPI_INSTR)) { - - struct list_id list; - - /* Show where we crashed */ - curr_frame = 0; - DEBUG_DisassembleInstruction(&addr); - - /* resets list internal arguments so we can look at source code when needed */ - DEBUG_FindNearestSymbol(&addr, TRUE, NULL, 0, &list); - if (list.sourcefile) DEBUG_List(&list, NULL, 0); + dbg_curr_thread->exec_mode == dbg_exec_step_over_insn || + dbg_curr_thread->exec_mode == dbg_exec_step_into_insn) + { + /* Show where we crashed */ + dbg_curr_frame = 0; + memory_disasm_one_insn(&addr); + source_list_from_addr(&addr, 0); } return TRUE; } -static void DEBUG_ExceptionEpilog(void) +static void dbg_exception_epilog(void) { - DEBUG_RestartExecution(DEBUG_CurrThread->exec_count); + break_restart_execution(dbg_curr_thread->exec_count); /* * This will have gotten absorbed into the breakpoint info * if it was used. Otherwise it would have been ignored. * In any case, we don't mess with it any more. */ - if (DEBUG_CurrThread->exec_mode == EXEC_CONT) - DEBUG_CurrThread->exec_count = 0; - DEBUG_InException = FALSE; + if (dbg_curr_thread->exec_mode == dbg_exec_cont) + dbg_curr_thread->exec_count = 0; + dbg_in_exception = FALSE; } -static DWORD DEBUG_HandleException(EXCEPTION_RECORD *rec, BOOL first_chance, BOOL force) +static DWORD dbg_handle_exception(EXCEPTION_RECORD* rec, BOOL first_chance, + BOOL force) { - BOOL is_debug = FALSE; - THREADNAME_INFO *pThreadName; - DBG_THREAD *pThread; + BOOL is_debug = FALSE; + THREADNAME_INFO* pThreadName; + struct dbg_thread* pThread; - assert(DEBUG_CurrThread); + assert(dbg_curr_thread); switch (rec->ExceptionCode) { @@ -531,14 +559,14 @@ static DWORD DEBUG_HandleException(EXCEPTION_RECORD *rec, BOOL first_chance, BOO case EXCEPTION_NAME_THREAD: pThreadName = (THREADNAME_INFO*)(rec->ExceptionInformation); if (pThreadName->dwThreadID == -1) - pThread = DEBUG_CurrThread; + pThread = dbg_curr_thread; else - pThread = DEBUG_GetThread(DEBUG_CurrProcess, pThreadName->dwThreadID); + pThread = dbg_get_thread(dbg_curr_process, pThreadName->dwThreadID); - if (ReadProcessMemory(DEBUG_CurrThread->process->handle, pThreadName->szName, + if (ReadProcessMemory(dbg_curr_thread->process->handle, pThreadName->szName, pThread->name, 9, NULL)) - DEBUG_Printf("Thread ID=0x%lx renamed using MS VC6 extension (name==\"%s\")\n", - pThread->tid, pThread->name); + dbg_printf("Thread ID=0x%lx renamed using MS VC6 extension (name==\"%s\")\n", + pThread->tid, pThread->name); return DBG_CONTINUE; } @@ -551,145 +579,146 @@ static DWORD DEBUG_HandleException(EXCEPTION_RECORD *rec, BOOL first_chance, BOO if (!is_debug) { /* print some infos */ - DEBUG_Printf("%s: ", - first_chance ? "First chance exception" : "Unhandled exception"); + dbg_printf("%s: ", + first_chance ? "First chance exception" : "Unhandled exception"); switch (rec->ExceptionCode) { case EXCEPTION_INT_DIVIDE_BY_ZERO: - DEBUG_Printf("divide by zero"); + dbg_printf("divide by zero"); break; case EXCEPTION_INT_OVERFLOW: - DEBUG_Printf("overflow"); + dbg_printf("overflow"); break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - DEBUG_Printf("array bounds"); + dbg_printf("array bounds"); break; case EXCEPTION_ILLEGAL_INSTRUCTION: - DEBUG_Printf("illegal instruction"); + dbg_printf("illegal instruction"); break; case EXCEPTION_STACK_OVERFLOW: - DEBUG_Printf("stack overflow"); + dbg_printf("stack overflow"); break; case EXCEPTION_PRIV_INSTRUCTION: - DEBUG_Printf("privileged instruction"); + dbg_printf("privileged instruction"); break; case EXCEPTION_ACCESS_VIOLATION: if (rec->NumberParameters == 2) - DEBUG_Printf("page fault on %s access to 0x%08lx", - rec->ExceptionInformation[0] ? "write" : "read", - rec->ExceptionInformation[1]); + dbg_printf("page fault on %s access to 0x%08lx", + rec->ExceptionInformation[0] ? "write" : "read", + rec->ExceptionInformation[1]); else - DEBUG_Printf("page fault"); + dbg_printf("page fault"); break; case EXCEPTION_DATATYPE_MISALIGNMENT: - DEBUG_Printf("Alignment"); + dbg_printf("Alignment"); break; case DBG_CONTROL_C: - DEBUG_Printf("^C"); + dbg_printf("^C"); break; case CONTROL_C_EXIT: - DEBUG_Printf("^C"); + dbg_printf("^C"); break; case STATUS_POSSIBLE_DEADLOCK: - { - DBG_ADDR addr; + { + ADDRESS addr; - addr.seg = 0; - addr.off = rec->ExceptionInformation[0]; + addr.Mode = AddrModeFlat; + addr.Offset = rec->ExceptionInformation[0]; - DEBUG_Printf("wait failed on critical section "); - DEBUG_PrintAddress(&addr, DEBUG_CurrThread->dbg_mode, FALSE); - } - if (!DBG_IVAR(BreakOnCritSectTimeOut)) - { - DEBUG_Printf("\n"); - return DBG_EXCEPTION_NOT_HANDLED; - } - break; + dbg_printf("wait failed on critical section "); + print_address(&addr, FALSE); + } + if (!DBG_IVAR(BreakOnCritSectTimeOut)) + { + dbg_printf("\n"); + return DBG_EXCEPTION_NOT_HANDLED; + } + break; case EXCEPTION_WINE_STUB: - { - char dll[32], name[64]; - DEBUG_ProcessGetString( dll, sizeof(dll), DEBUG_CurrThread->process->handle, - (char *)rec->ExceptionInformation[0] ); - DEBUG_ProcessGetString( name, sizeof(name), DEBUG_CurrThread->process->handle, - (char *)rec->ExceptionInformation[1] ); - DEBUG_Printf("unimplemented function %s.%s called", dll, name ); - } - break; + { + char dll[32], name[64]; + memory_get_string(dbg_curr_thread->process->handle, + (void*)rec->ExceptionInformation[0], DLV_TARGET, FALSE, + dll, sizeof(dll)); + memory_get_string(dbg_curr_thread->process->handle, + (void*)rec->ExceptionInformation[1], DLV_TARGET, FALSE, + name, sizeof(name)); + dbg_printf("unimplemented function %s.%s called", dll, name); + } + break; case EXCEPTION_WINE_ASSERTION: - DEBUG_Printf("assertion failed"); + dbg_printf("assertion failed"); break; case EXCEPTION_VM86_INTx: - DEBUG_Printf("interrupt %02lx in vm86 mode", - rec->ExceptionInformation[0]); + dbg_printf("interrupt %02lx in vm86 mode", rec->ExceptionInformation[0]); break; case EXCEPTION_VM86_STI: - DEBUG_Printf("sti in vm86 mode"); + dbg_printf("sti in vm86 mode"); break; case EXCEPTION_VM86_PICRETURN: - DEBUG_Printf("PIC return in vm86 mode"); + dbg_printf("PIC return in vm86 mode"); break; case EXCEPTION_FLT_DENORMAL_OPERAND: - DEBUG_Printf("denormal float operand"); + dbg_printf("denormal float operand"); break; case EXCEPTION_FLT_DIVIDE_BY_ZERO: - DEBUG_Printf("divide by zero"); + dbg_printf("divide by zero"); break; case EXCEPTION_FLT_INEXACT_RESULT: - DEBUG_Printf("inexact float result"); + dbg_printf("inexact float result"); break; case EXCEPTION_FLT_INVALID_OPERATION: - DEBUG_Printf("invalid float operation"); + dbg_printf("invalid float operation"); break; case EXCEPTION_FLT_OVERFLOW: - DEBUG_Printf("floating pointer overflow"); + dbg_printf("floating pointer overflow"); break; case EXCEPTION_FLT_UNDERFLOW: - DEBUG_Printf("floating pointer underflow"); + dbg_printf("floating pointer underflow"); break; case EXCEPTION_FLT_STACK_CHECK: - DEBUG_Printf("floating point stack check"); + dbg_printf("floating point stack check"); break; default: - DEBUG_Printf("%08lx", rec->ExceptionCode); + dbg_printf("0x%08lx", rec->ExceptionCode); break; } } - if (local_mode == automatic_mode) + if (dbg_action_mode == automatic_mode) { - DEBUG_ExceptionProlog(is_debug, FALSE, rec->ExceptionCode); - DEBUG_ExceptionEpilog(); + dbg_exception_prolog(is_debug, FALSE, rec->ExceptionCode); + dbg_exception_epilog(); return 0; /* terminate execution */ } - if (DEBUG_ExceptionProlog(is_debug, force, rec->ExceptionCode)) + if (dbg_exception_prolog(is_debug, force, rec->ExceptionCode)) { - DEBUG_InteractiveP = TRUE; + dbg_interactiveP = TRUE; return 0; } - DEBUG_ExceptionEpilog(); + dbg_exception_epilog(); return DBG_CONTINUE; } -static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de) +static unsigned dbg_handle_debug_event(DEBUG_EVENT* de) { char buffer[256]; DWORD cont = DBG_CONTINUE; - DEBUG_CurrPid = de->dwProcessId; - DEBUG_CurrTid = de->dwThreadId; + dbg_curr_pid = de->dwProcessId; + dbg_curr_tid = de->dwThreadId; - if ((DEBUG_CurrProcess = DEBUG_GetProcess(de->dwProcessId)) != NULL) - DEBUG_CurrThread = DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId); + if ((dbg_curr_process = dbg_get_process(de->dwProcessId)) != NULL) + dbg_curr_thread = dbg_get_thread(dbg_curr_process, de->dwThreadId); else - DEBUG_CurrThread = NULL; + dbg_curr_thread = NULL; switch (de->dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: - if (!DEBUG_CurrThread) + if (!dbg_curr_thread) { WINE_ERR("%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n", de->dwProcessId, de->dwThreadId); @@ -700,156 +729,136 @@ static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de) de->dwProcessId, de->dwThreadId, de->u.Exception.ExceptionRecord.ExceptionCode); - if (DEBUG_CurrProcess->continue_on_first_exception) + if (dbg_curr_process->continue_on_first_exception) { - DEBUG_CurrProcess->continue_on_first_exception = FALSE; + dbg_curr_process->continue_on_first_exception = FALSE; if (!DBG_IVAR(BreakOnAttach)) break; } - if (DEBUG_FetchContext()) + if (dbg_fetch_context()) { - cont = DEBUG_HandleException(&de->u.Exception.ExceptionRecord, + cont = dbg_handle_exception(&de->u.Exception.ExceptionRecord, de->u.Exception.dwFirstChance, - DEBUG_CurrThread->wait_for_first_exception); - if (cont && DEBUG_CurrThread) + dbg_curr_thread->wait_for_first_exception); + if (cont && dbg_curr_thread) { - DEBUG_CurrThread->wait_for_first_exception = 0; - SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context); + dbg_curr_thread->wait_for_first_exception = 0; + SetThreadContext(dbg_curr_thread->handle, &dbg_context); } } break; - case CREATE_THREAD_DEBUG_EVENT: - WINE_TRACE("%08lx:%08lx: create thread D @%08lx\n", de->dwProcessId, de->dwThreadId, - (unsigned long)(LPVOID)de->u.CreateThread.lpStartAddress); - - if (DEBUG_CurrProcess == NULL) - { - WINE_ERR("Unknown process\n"); - break; - } - if (DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId) != NULL) - { - WINE_TRACE("Thread already listed, skipping\n"); - break; - } - - DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess, - de->dwThreadId, - de->u.CreateThread.hThread, - de->u.CreateThread.lpStartAddress, - de->u.CreateThread.lpThreadLocalBase); - if (!DEBUG_CurrThread) - { - WINE_ERR("Couldn't create thread\n"); - break; - } - DEBUG_InitCurrThread(); - break; - case CREATE_PROCESS_DEBUG_EVENT: - DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), - de->u.CreateProcessInfo.hProcess, - de->u.CreateProcessInfo.lpImageName, - de->u.CreateProcessInfo.fUnicode); - + memory_get_string_indirect(de->u.CreateProcessInfo.hProcess, + de->u.CreateProcessInfo.lpImageName, + de->u.CreateProcessInfo.fUnicode, + buffer, sizeof(buffer)); WINE_TRACE("%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n", de->dwProcessId, de->dwThreadId, buffer, de->u.CreateProcessInfo.lpImageName, - (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress, + (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress, de->u.CreateProcessInfo.dwDebugInfoFileOffset, de->u.CreateProcessInfo.nDebugInfoSize); - DEBUG_CurrProcess = DEBUG_AddProcess(de->dwProcessId, - de->u.CreateProcessInfo.hProcess, - buffer[0] ? buffer : ""); - if (DEBUG_CurrProcess == NULL) + dbg_curr_process = dbg_add_process(de->dwProcessId, + de->u.CreateProcessInfo.hProcess, + buffer[0] ? buffer : ""); + if (dbg_curr_process == NULL) { WINE_ERR("Couldn't create process\n"); break; } + if (!SymInitialize(dbg_curr_process->handle, NULL, TRUE)) + dbg_printf("Couldn't initiate DbgHelp\n"); WINE_TRACE("%08lx:%08lx: create thread I @%08lx\n", de->dwProcessId, de->dwThreadId, - (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress); + (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress); - DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess, - de->dwThreadId, - de->u.CreateProcessInfo.hThread, - de->u.CreateProcessInfo.lpStartAddress, - de->u.CreateProcessInfo.lpThreadLocalBase); - if (!DEBUG_CurrThread) + dbg_curr_thread = dbg_add_thread(dbg_curr_process, + de->dwThreadId, + de->u.CreateProcessInfo.hThread, + de->u.CreateProcessInfo.lpThreadLocalBase); + if (!dbg_curr_thread) { WINE_ERR("Couldn't create thread\n"); break; } - else - { - struct elf_info elf_info; - - DEBUG_InitCurrProcess(); - DEBUG_InitCurrThread(); - - elf_info.flags = ELF_INFO_MODULE; - - if (DEBUG_ReadWineLoaderDbgInfo(DEBUG_CurrProcess->handle, &elf_info) != DIL_ERROR && - DEBUG_SetElfSoLoadBreakpoint(&elf_info)) - { - /* then load the main module's symbols */ - DEBUG_LoadPEModule(DEBUG_CurrProcess->imageName, - de->u.CreateProcessInfo.hFile, - de->u.CreateProcessInfo.lpBaseOfImage); - } - else - { - DEBUG_DelThread(DEBUG_CurrProcess->threads); - DEBUG_DelProcess(DEBUG_CurrProcess); - DEBUG_Printf("Couldn't load process\n"); - } - } - break; - - case EXIT_THREAD_DEBUG_EVENT: - WINE_TRACE("%08lx:%08lx: exit thread (%ld)\n", - de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode); - - if (DEBUG_CurrThread == NULL) - { - WINE_ERR("Unknown thread\n"); - break; - } - /* FIXME: remove break point set on thread startup */ - DEBUG_DelThread(DEBUG_CurrThread); + dbg_init_current_process(); + dbg_init_current_thread(de->u.CreateProcessInfo.lpStartAddress); break; case EXIT_PROCESS_DEBUG_EVENT: WINE_TRACE("%08lx:%08lx: exit process (%ld)\n", de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode); - if (DEBUG_CurrProcess == NULL) + if (dbg_curr_process == NULL) { WINE_ERR("Unknown process\n"); break; } + if (!SymCleanup(dbg_curr_process->handle)) + dbg_printf("Couldn't initiate DbgHelp\n"); /* just in case */ - DEBUG_SetBreakpoints(FALSE); + break_set_xpoints(FALSE); /* kill last thread */ - DEBUG_DelThread(DEBUG_CurrProcess->threads); - DEBUG_DelProcess(DEBUG_CurrProcess); + dbg_del_thread(dbg_curr_process->threads); + dbg_del_process(dbg_curr_process); - DEBUG_Printf("Process of pid=%08lx has terminated\n", DEBUG_CurrPid); + dbg_printf("Process of pid=0x%08lx has terminated\n", dbg_curr_pid); break; - case LOAD_DLL_DEBUG_EVENT: - if (DEBUG_CurrThread == NULL) + case CREATE_THREAD_DEBUG_EVENT: + WINE_TRACE("%08lx:%08lx: create thread D @%08lx\n", + de->dwProcessId, de->dwThreadId, + (unsigned long)(void*)de->u.CreateThread.lpStartAddress); + + if (dbg_curr_process == NULL) + { + WINE_ERR("Unknown process\n"); + break; + } + if (dbg_get_thread(dbg_curr_process, de->dwThreadId) != NULL) + { + WINE_TRACE("Thread already listed, skipping\n"); + break; + } + + dbg_curr_thread = dbg_add_thread(dbg_curr_process, + de->dwThreadId, + de->u.CreateThread.hThread, + de->u.CreateThread.lpThreadLocalBase); + if (!dbg_curr_thread) + { + WINE_ERR("Couldn't create thread\n"); + break; + } + dbg_init_current_thread(de->u.CreateThread.lpStartAddress); + break; + + case EXIT_THREAD_DEBUG_EVENT: + WINE_TRACE("%08lx:%08lx: exit thread (%ld)\n", + de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode); + + if (dbg_curr_thread == NULL) { WINE_ERR("Unknown thread\n"); break; } - DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), - DEBUG_CurrThread->process->handle, - de->u.LoadDll.lpImageName, - de->u.LoadDll.fUnicode); + /* FIXME: remove break point set on thread startup */ + dbg_del_thread(dbg_curr_thread); + break; + + case LOAD_DLL_DEBUG_EVENT: + if (dbg_curr_thread == NULL) + { + WINE_ERR("Unknown thread\n"); + break; + } + memory_get_string_indirect(dbg_curr_thread->process->handle, + de->u.LoadDll.lpImageName, + de->u.LoadDll.fUnicode, + buffer, sizeof(buffer)); WINE_TRACE("%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n", de->dwProcessId, de->dwThreadId, @@ -857,33 +866,38 @@ static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de) de->u.LoadDll.dwDebugInfoFileOffset, de->u.LoadDll.nDebugInfoSize); _strupr(buffer); - DEBUG_LoadPEModule(buffer, de->u.LoadDll.hFile, de->u.LoadDll.lpBaseOfDll); - DEBUG_CheckDelayedBP(); + SymLoadModule(dbg_curr_process->handle, de->u.LoadDll.hFile, buffer, NULL, + (unsigned long)de->u.LoadDll.lpBaseOfDll, 0); + break_set_xpoints(FALSE); + break_check_delayed_bp(); + break_set_xpoints(TRUE); if (DBG_IVAR(BreakOnDllLoad)) { - DEBUG_Printf("Stopping on DLL %s loading at %08lx\n", - buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll); - if (DEBUG_FetchContext()) cont = 0; + dbg_printf("Stopping on DLL %s loading at 0x%08lx\n", + buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll); + if (dbg_fetch_context()) cont = 0; } break; case UNLOAD_DLL_DEBUG_EVENT: - WINE_TRACE("%08lx:%08lx: unload DLL @%08lx\n", de->dwProcessId, de->dwThreadId, + WINE_TRACE("%08lx:%08lx: unload DLL @%08lx\n", + de->dwProcessId, de->dwThreadId, (unsigned long)de->u.UnloadDll.lpBaseOfDll); + break_delete_xpoints_from_module((unsigned long)de->u.UnloadDll.lpBaseOfDll); + SymUnloadModule(dbg_curr_process->handle, + (unsigned long)de->u.UnloadDll.lpBaseOfDll); break; case OUTPUT_DEBUG_STRING_EVENT: - if (DEBUG_CurrThread == NULL) + if (dbg_curr_thread == NULL) { WINE_ERR("Unknown thread\n"); break; } - DEBUG_ProcessGetString(buffer, sizeof(buffer), - DEBUG_CurrThread->process->handle, - de->u.DebugString.lpDebugStringData); - - /* FIXME unicode de->u.DebugString.fUnicode ? */ + memory_get_string(dbg_curr_thread->process->handle, + de->u.DebugString.lpDebugStringData, DLV_TARGET, + de->u.DebugString.fUnicode, buffer, sizeof(buffer)); WINE_TRACE("%08lx:%08lx: output debug string (%s)\n", de->dwProcessId, de->dwThreadId, buffer); break; @@ -903,90 +917,86 @@ static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de) return FALSE; /* continue execution */ } -static void DEBUG_ResumeDebuggee(DWORD cont) +static void dbg_resume_debuggee(DWORD cont) { - if (DEBUG_InException) + if (dbg_in_exception) { - DEBUG_ExceptionEpilog(); -#ifdef __i386__ - WINE_TRACE("Exiting debugger PC=%lx EFL=%08lx mode=%d count=%d\n", - DEBUG_context.Eip, DEBUG_context.EFlags, - DEBUG_CurrThread->exec_mode, DEBUG_CurrThread->exec_count); -#else - WINE_TRACE("Exiting debugger PC=%lx EFL=%08lx mode=%d count=%d\n", - 0L, 0L, - DEBUG_CurrThread->exec_mode, DEBUG_CurrThread->exec_count); -#endif - if (DEBUG_CurrThread) + ADDRESS addr; + + dbg_exception_epilog(); + memory_get_current_pc(&addr); + WINE_TRACE("Exiting debugger PC=0x%lx mode=%d count=%d\n", + addr.Offset, dbg_curr_thread->exec_mode, + dbg_curr_thread->exec_count); + if (dbg_curr_thread) { - if (!SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context)) - DEBUG_Printf("Cannot set ctx on %lu\n", DEBUG_CurrTid); - DEBUG_CurrThread->wait_for_first_exception = 0; + if (!SetThreadContext(dbg_curr_thread->handle, &dbg_context)) + dbg_printf("Cannot set ctx on %lu\n", dbg_curr_tid); + dbg_curr_thread->wait_for_first_exception = 0; } } - DEBUG_InteractiveP = FALSE; - if (!ContinueDebugEvent(DEBUG_CurrPid, DEBUG_CurrTid, cont)) - DEBUG_Printf("Cannot continue on %lu (%lu)\n", DEBUG_CurrTid, cont); + dbg_interactiveP = FALSE; + if (!ContinueDebugEvent(dbg_curr_pid, dbg_curr_tid, cont)) + dbg_printf("Cannot continue on %lu (%lu)\n", dbg_curr_tid, cont); } -void DEBUG_WaitNextException(DWORD cont, int count, int mode) +void dbg_wait_next_exception(DWORD cont, int count, int mode) { DEBUG_EVENT de; + ADDRESS addr; if (cont == DBG_CONTINUE) { - DEBUG_CurrThread->exec_count = count; - DEBUG_CurrThread->exec_mode = mode; + dbg_curr_thread->exec_count = count; + dbg_curr_thread->exec_mode = mode; } - DEBUG_ResumeDebuggee(cont); + dbg_resume_debuggee(cont); - while (DEBUG_CurrProcess && WaitForDebugEvent(&de, INFINITE)) + while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE)) { - if (DEBUG_HandleDebugEvent(&de)) break; + if (dbg_handle_debug_event(&de)) break; } - if (!DEBUG_CurrProcess) return; - DEBUG_InteractiveP = TRUE; -#ifdef __i386__ - WINE_TRACE("Entering debugger PC=%lx EFL=%08lx mode=%d count=%d\n", - DEBUG_context.Eip, DEBUG_context.EFlags, - DEBUG_CurrThread->exec_mode, DEBUG_CurrThread->exec_count); -#else - WINE_TRACE("Entering debugger PC=%lx EFL=%08lx mode=%d count=%d\n", - 0L, 0L, - DEBUG_CurrThread->exec_mode, DEBUG_CurrThread->exec_count); -#endif + if (!dbg_curr_process) return; + dbg_interactiveP = TRUE; + + memory_get_current_pc(&addr); + WINE_TRACE("Exiting debugger PC=0x%lx mode=%d count=%d\n", + addr.Offset, dbg_curr_thread->exec_mode, + dbg_curr_thread->exec_count); } -static DWORD DEBUG_MainLoop(void) +static DWORD dbg_main_loop(void) { DEBUG_EVENT de; - DEBUG_Printf("WineDbg starting on pid %lx\n", DEBUG_CurrPid); + if (dbg_curr_process) + dbg_printf("WineDbg starting on pid 0x%lx\n", dbg_curr_pid); /* wait for first exception */ while (WaitForDebugEvent(&de, INFINITE)) { - if (DEBUG_HandleDebugEvent(&de)) break; + if (dbg_handle_debug_event(&de)) break; } - if (local_mode == automatic_mode) + switch (dbg_action_mode) { + case automatic_mode: /* print some extra information */ - DEBUG_Printf("Modules:\n"); - DEBUG_WalkModules(); - DEBUG_Printf("Threads:\n"); - DEBUG_WalkThreads(); + dbg_printf("Modules:\n"); + info_win32_module(0); /* print all modules */ + dbg_printf("Threads:\n"); + info_win32_threads(); + break; + default: + dbg_interactiveP = TRUE; + if (dbg_curr_process) source_list_from_addr(NULL, 0); + parser(NULL); } - else - { - DEBUG_InteractiveP = TRUE; - DEBUG_Parser(NULL); - } - DEBUG_Printf("WineDbg terminated on pid %lx\n", DEBUG_CurrPid); + dbg_printf("WineDbg terminated on pid 0x%lx\n", dbg_curr_pid); return 0; } -static BOOL DEBUG_Start(LPSTR cmdLine) +static unsigned dbg_start_debuggee(LPSTR cmdLine) { PROCESS_INFORMATION info; STARTUPINFOA startup; @@ -1000,141 +1010,145 @@ static BOOL DEBUG_Start(LPSTR cmdLine) * while GUI:s don't */ if (!CreateProcess(NULL, cmdLine, NULL, NULL, - FALSE, DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE, + FALSE, + DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE, NULL, NULL, &startup, &info)) { - DEBUG_Printf("Couldn't start process '%s'\n", cmdLine); + dbg_printf("Couldn't start process '%s'\n", cmdLine); return FALSE; } - DEBUG_CurrPid = info.dwProcessId; - if (!(DEBUG_CurrProcess = DEBUG_AddProcess(DEBUG_CurrPid, 0, NULL))) return FALSE; + dbg_curr_pid = info.dwProcessId; + if (!(dbg_curr_process = dbg_add_process(dbg_curr_pid, 0, NULL))) return FALSE; return TRUE; } -void DEBUG_Run(const char* args) +void dbg_run_debuggee(const char* args) { - DBG_MODULE* wmod = DEBUG_GetProcessMainModule(DEBUG_CurrProcess); - const char* pgm = (wmod) ? wmod->module_name : "none"; + if (args) + { + WINE_FIXME("Re-running current program with %s as args is broken\n", args); + return; + } + else + { + DEBUG_EVENT de; - if (args) { - DEBUG_Printf("Run (%s) with '%s'\n", pgm, args); - } else { - if (!DEBUG_LastCmdLine) { - DEBUG_Printf("Cannot find previously used command line.\n"); + if (!dbg_last_cmd_line) + { + dbg_printf("Cannot find previously used command line.\n"); return; } - DEBUG_Start(DEBUG_LastCmdLine); + dbg_start_debuggee(dbg_last_cmd_line); + while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE)) + { + if (dbg_handle_debug_event(&de)) break; + } + source_list_from_addr(NULL, 0); } } -BOOL DEBUG_InterruptDebuggee(void) +BOOL dbg_interrupt_debuggee(void) { - DEBUG_Printf("Ctrl-C: stopping debuggee\n"); + dbg_printf("Ctrl-C: stopping debuggee\n"); /* FIXME: since we likely have a single process, signal the first process * in list */ - if (!DEBUG_ProcessList) return FALSE; - DEBUG_ProcessList->continue_on_first_exception = FALSE; - return DebugBreakProcess(DEBUG_ProcessList->handle); + if (!dbg_process_list) return FALSE; + dbg_process_list->continue_on_first_exception = FALSE; + return DebugBreakProcess(dbg_process_list); } -static BOOL WINAPI DEBUG_CtrlCHandler(DWORD dwCtrlType) +static BOOL WINAPI ctrl_c_handler(DWORD dwCtrlType) { if (dwCtrlType == CTRL_C_EVENT) { - return DEBUG_InterruptDebuggee(); + return dbg_interrupt_debuggee(); } return FALSE; } -static void DEBUG_InitConsole(void) +static void dbg_init_console(void) { /* set our control-C handler */ - SetConsoleCtrlHandler(DEBUG_CtrlCHandler, TRUE); + SetConsoleCtrlHandler(ctrl_c_handler, TRUE); /* set our own title */ SetConsoleTitle("Wine Debugger"); } -static int DEBUG_Usage(void) +static int dbg_winedbg_usage(void) { - DEBUG_Printf("Usage: winedbg [--debugmsg dbgoptions] [--auto] [--gdb] cmdline\n" ); + dbg_printf("Usage: winedbg [--auto] [--gdb] cmdline\n"); return 1; } +struct backend_cpu* be_cpu; +extern struct backend_cpu be_i386; + int main(int argc, char** argv) { DWORD retv = 0; unsigned gdb_flags = 0; + /* FIXME: correctly setup the CPU backend */ + be_cpu = &be_i386; /* Initialize the output */ - hOutput=GetStdHandle(STD_OUTPUT_HANDLE); + dbg_houtput = GetStdHandle(STD_OUTPUT_HANDLE); - /* Initialize the type handling stuff. */ - DEBUG_InitTypes(); - DEBUG_InitCVDataTypes(); - - /* Initialize internal vars (types must have been initialized before) */ - if (!DEBUG_IntVarsRW(TRUE)) return -1; + /* Initialize internal vars */ + if (!dbg_load_internal_vars()) return -1; /* parse options */ while (argc > 1 && argv[1][0] == '-') { - if (!strcmp( argv[1], "--auto" )) + if (!strcmp(argv[1], "--auto")) { - if (local_mode != none_mode) return DEBUG_Usage(); - local_mode = automatic_mode; - hOutput=GetStdHandle(STD_ERROR_HANDLE); + if (dbg_action_mode != none_mode) return dbg_winedbg_usage(); + dbg_action_mode = automatic_mode; /* force some internal variables */ DBG_IVAR(BreakOnDllLoad) = 0; argc--; argv++; + dbg_houtput = GetStdHandle(STD_ERROR_HANDLE); continue; } - if (!strcmp( argv[1], "--gdb" )) + if (!strcmp(argv[1], "--gdb")) { - if (local_mode != none_mode) return DEBUG_Usage(); - local_mode = gdb_mode; + if (dbg_action_mode != none_mode) return dbg_winedbg_usage(); + dbg_action_mode = gdb_mode; argc--; argv++; continue; } - if (strcmp( argv[1], "--no-start") == 0 && local_mode == gdb_mode) + if (strcmp(argv[1], "--no-start") == 0 && dbg_action_mode == gdb_mode) { gdb_flags |= 1; argc--; argv++; /* as we don't use argv[0] */ continue; } - if (strcmp(argv[1], "--with-xterm") == 0 && local_mode == gdb_mode) + if (strcmp(argv[1], "--with-xterm") == 0 && dbg_action_mode == gdb_mode) { gdb_flags |= 2; argc--; argv++; /* as we don't use argv[0] */ continue; } - if (!strcmp( argv[1], "--debugmsg" ) && argv[2]) - { - wine_dbg_parse_options( argv[2] ); - argc -= 2; - argv += 2; - continue; - } - return DEBUG_Usage(); + return dbg_winedbg_usage(); } - if (local_mode == none_mode) local_mode = winedbg_mode; + if (dbg_action_mode == none_mode) dbg_action_mode = winedbg_mode; /* try the form pid */ - if (DEBUG_CurrPid == 0 && argc == 2) + if (dbg_curr_pid == 0 && argc == 2) { char* ptr; - DEBUG_CurrPid = strtol(argv[1], &ptr, 10); - if (DEBUG_CurrPid == 0 || ptr == NULL || - !DEBUG_Attach(DEBUG_CurrPid, local_mode != gdb_mode, FALSE)) - DEBUG_CurrPid = 0; + dbg_curr_pid = strtol(argv[1], &ptr, 10); + if (dbg_curr_pid == 0 || ptr == NULL || + !dbg_attach_debuggee(dbg_curr_pid, dbg_action_mode != gdb_mode, FALSE)) + dbg_curr_pid = 0; } /* try the form pid evt (Win32 JIT debugger) */ - if (DEBUG_CurrPid == 0 && argc == 3) + if (dbg_curr_pid == 0 && argc == 3) { HANDLE hEvent; DWORD pid; @@ -1143,7 +1157,7 @@ int main(int argc, char** argv) if ((pid = strtol(argv[1], &ptr, 10)) != 0 && ptr != NULL && (hEvent = (HANDLE)strtol(argv[2], &ptr, 10)) != 0 && ptr != NULL) { - if (!DEBUG_Attach(pid, TRUE, FALSE)) + if (!dbg_attach_debuggee(pid, TRUE, FALSE)) { /* don't care about result */ SetEvent(hEvent); @@ -1155,49 +1169,52 @@ int main(int argc, char** argv) goto leave; } CloseHandle(hEvent); - DEBUG_CurrPid = pid; + dbg_curr_pid = pid; } } - if (DEBUG_CurrPid == 0 && argc > 1) + if (dbg_curr_pid == 0 && argc > 1) { int i, len; LPSTR cmdLine; - if (!(cmdLine = DBG_alloc(len = 1))) goto oom_leave; + if (!(cmdLine = HeapAlloc(GetProcessHeap(), 0, len = 1))) goto oom_leave; cmdLine[0] = '\0'; for (i = 1; i < argc; i++) { len += strlen(argv[i]) + 1; - if (!(cmdLine = DBG_realloc(cmdLine, len))) goto oom_leave; + if (!(cmdLine = HeapReAlloc(GetProcessHeap(), 0, cmdLine, len))) + goto oom_leave; strcat(cmdLine, argv[i]); cmdLine[len - 2] = ' '; cmdLine[len - 1] = '\0'; } - if (!DEBUG_Start(cmdLine)) + if (!dbg_start_debuggee(cmdLine)) { - DEBUG_Printf("Couldn't start process '%s'\n", cmdLine); + dbg_printf("Couldn't start process '%s'\n", cmdLine); goto leave; } - DBG_free(DEBUG_LastCmdLine); - DEBUG_LastCmdLine = cmdLine; + dbg_last_cmd_line = cmdLine; } /* don't save local vars in gdb mode */ - if (local_mode == gdb_mode && DEBUG_CurrPid) - return DEBUG_GdbRemote(gdb_flags); + if (dbg_action_mode == gdb_mode && dbg_curr_pid) + return gdb_remote(gdb_flags); - DEBUG_InitConsole(); + dbg_init_console(); - retv = DEBUG_MainLoop(); + SymSetOptions(SymGetOptions() | + SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_AUTO_PUBLICS); + + retv = dbg_main_loop(); /* don't save modified variables in auto mode */ - if (local_mode != automatic_mode) DEBUG_IntVarsRW(FALSE); + if (dbg_action_mode != automatic_mode) dbg_save_internal_vars(); - leave: +leave: return retv; - oom_leave: - DEBUG_Printf("Out of memory\n"); - goto leave; +oom_leave: + dbg_printf("Out of memory\n"); + return retv; } diff --git a/programs/winedbg/winedbg.man b/programs/winedbg/winedbg.man new file mode 100644 index 00000000000..716d5013993 --- /dev/null +++ b/programs/winedbg/winedbg.man @@ -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\ \fR +Adds condition \fB\fR to (break|watch)-point +#\fBN\fR. \fB\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\ \fR +Adds a breakpoint at the address of symbol \fB\fR +.IP \fBbreak N\fR +Adds a breakpoint at the line \fBN\fR inside symbol \fB\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\ \fR +Adds a watch command (on write) at the address of symbol +\fB\fR. Size depends on size of \fB\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\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\ \fR +Adds \fB\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\ \fR +Loads external symbol definition symbolfile \fB\fR +.IP \fBsymbolfile\ \ N\fR +Loads external symbol definition symbolfile \fB\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\ :N\fR +Lists 10 source lines from line #\fBN\fR in file \fB\fR +.IP \fBlist\ \fR +Lists 10 source lines of function \fB\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\ \fR +Adds a display for expression \f\fR +.IP \fBdisplay\ /fmt\ \fR +Adds a display for expression \fB\fR. Printing evaluated +\fB\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\ \fR +Disassemble from address \fB\fR +.IP \fBdisas\ ,\fR +Disassembles code between addresses specified by the two \fB\fR:s +.PP +\fIMemory\ (reading,\ writing,\ typing)\fR +.IP \fBx\ \fR +Examines memory at \fB\fR address +.IP \fBx\ /fmt\ \fR +Examines memory at \fB\fR address using format \fI/fmt\fR +.IP \fBprint\ \fR +Prints the value of \fB\fR (possibly using its type) +.IP \fBprint\ /fmt\ \fR +Prints the value of \fB\fR (possibly using its type) +.IP \fBset\ \ =\ \fR +Writes the value of \fB\fR in \fB\fR variable. +.IP \fBwhatis\ \fR +Prints the C type of expression \fB\fR +.PP +.IP \fI/fmt\fR +is either \fI/\fR or \fI/\fR. \fI\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\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\ \fR +Prints information on Windows's class \fB\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