Updated vKim like tools for GoAsm 64/32 bit (Now for MASM too)

Started by donkey, March 25, 2011, 05:45:15 AM

Previous topic - Next topic

donkey

I've made a couple of changes and added a few features to the run-time debugging tool for GoAsm 64. I will be making it cross platform compatible to 32 bits over the next while so some macros had to be renamed (eg PrintDec becomes PrintQWORDDec), there are no more assumed types since the macros have to be compatible (or close to) regardless of data width. The Try/EndTry block has been enhanced to include the module name where the exception occurred:

Try
mov ecx,0
mov B[ecx],12
EndTry

Output:
EXCEPTION_ACCESS_VIOLATION encountered at address 00000000004011D9 in test64.exe writing to 0000000000000000


The following is a current list of macros.

PrintQWORD - (Num) - Print a qword in decimal notation, accepts a register, memory location or immediate value
PrintQWORDHex - (Num) - Print a qword in hex notation, accepts a register, memory location or immediate value
PrintDWORD - (Num) - Print a dword in decimal notation, accepts a register, memory location or immediate value
PrintDWORDHex - (Num) - Print a dword in hex notation, accepts a register, memory location or immediate value
PrintDouble - (Num) - Print a double precision value, accepts a register, memory location (no immediate value)
PrintFloat - (Num) - Print a single precision value, accepts a register, memory location or immediate value

PrintString - (Label) Prints a string variable
PrintStringByAddr - (Addr) Prints a string pointed to by Addr
PrintText - ("Str") Prints an immediate quoted string

PrintError - No parameters. Prints the last error message
PrintOleError - (Erno) Prints the system defined message identified by Erno
PrintModMessage- (pszModulePath, Erno) Prints the message from the message table in pszModulePath identified by Erno
PrintLine - No Parameters. Prints a dashed line

DumpMem - (pStart, nLength) Dumps a hex representation of memory beginning at pStart for nLength bytes
DbgDump - (pStart, nLength) Equivalent to DumpMem
DumpFPU - No parameters - Displays the contents of the FPU
DumpMMX - No parameters - Displays the contents of the MMX registers
DumpEFlags - No parameters - Displays the contents of the EFlag register
DumpSymbols - No Parameters - Dumps the symbol table

Try() - Parameter optional - Starts a Try/EndTry block. Optionally an address to a VectoredHandler procedure can be used or the brackets left empty to use the default handler.
EndTry - No parameters. Ends a Try/EndTry block. Will print exception info if one occurs within the block
Disassemble - (pTarget,nLines) - Disassembles nLines of code beginning at pTarget
Spy - (SPY_TYPE_XXX,Var) - Single steps a block of code displaying Var on each step. SPY_TYPE_XXX is one of the constants below. If using one of the SPY_TYPE_REGxx types do not include a second parameter
StopSpy - No Parameters - Stops spying a variable

SPY_TYPE_FLOAT = 0
SPY_TYPE_DOUBLE = 1
SPY_TYPE_QWORD = 2
SPY_TYPE_DWORD = 3
SPY_TYPE_QWORDHEX = 4
SPY_TYPE_DWORDHEX = 5
SPY_TYPE_STRING = 6
SPY_TYPE_REGRAX = 7
SPY_TYPE_REGRBX = 8
SPY_TYPE_REGRCX = 9
SPY_TYPE_REGRDX = 10
SPY_TYPE_REGRSI = 11
SPY_TYPE_REGRDI = 12
SPY_TYPE_REGRSP = 13
SPY_TYPE_REGRBP = 14
SPY_TYPE_REGR8 = 15
SPY_TYPE_REGR9 = 16
SPY_TYPE_REGR10 = 17
SPY_TYPE_REGR11 = 18
SPY_TYPE_REGR12 = 19
SPY_TYPE_REGR13 = 20
SPY_TYPE_REGR14 = 21
SPY_TYPE_REGR15 = 22

These are macros and so do not use them with invoke, for example:

PrintText("Hello")

To use them add the following to your code (change the paths to match your system)


#define DBG64LIB "C:\RadASM30\GoAsm\dbg\Debug64.lib"
#define DEBUGEXE "C:\RadASM30\GoAsm\dbg\DbgWin.exe"
#include "C:\RadASM30\GoAsm\dbg\Debug64.a"
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

#1
I have updated the debug tool to no longer require the /mix switch. Also added a stack trace and register dumpto the Try/EndTry block output and an external debug window when Radasm is not running. A major bug fix was that qword outputs in some functions were having the high order 32 bits truncated, its been corrected.

Output of Try/EndTry

EXCEPTION_PRIV_INSTRUCTION encountered at address 0000000000401276 in module test64.exe
----------------------------------------
Registers
----------------------------------------
RAX 0000000076BD6520 RBX 000000FFFFFFFFFF RCX 000007FFFFFD6000 RDX 0000000000401165
RSI 0000000000000000 RDI 000000000031D578 RBP 0000000000000000 RSP 000000000012FF58
R8  000007FFFFFD6000 R9  0000000000401165 R10 0000000000000000 R11 0000000000000000
R12 0000000000000000 R13 0000000000000000 R14 0000000000000000 R15 0000000000000000
----------------------------------------
Stack trace
----------------------------------------
# Child-SP          RetAddr           Call Site
00 00000000`0012ff58 00000000`76bd652d test64+0x1276
01 00000000`0012ff60 00000000`76d0c521 kernel32!BaseThreadInitThunk+0xd
02 00000000`0012ff90 00000000`00000000 ntdll!RtlUserThreadStart+0x21

"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

#2
In some of my tests I ran into a problem that if the user enters an incorrect path for the debug window (when RadAsm is not running) the tools will dump into an infinite loop. It is corrected with this update.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

#3
I found that it was convenient to sometimes use a custom exception handler with the Try/EndTry block instead of the default one in the LIB file. So I added an optional parameter to the Try macro that allows you to pass it the address to a local VectoredHandler or you can leave the brackets empty and the default one will be used...

; use default handler
Try()
    ud2
EndTry

;Use custom local handler
Try(offset MyHandler)
    ud2
EndTry


Note that the brackets are mandatory even if empty.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

#4
I recently needed to examine some open handles while debugging a program. This is a fairly easy thing to do but it was a pain to have to load my exe in a separate debugger when I just need a few bits of information about open file handles. So I decided to add it to the 64 bit debug tool.

DumpHandles will output:

HANDLE #00000004 = Key = \REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
HANDLE #00000008 = Directory = \KnownDlls
HANDLE #0000000C = File = \Device\HarddiskVolume1\Programming\RadASM3\GoAsm\Projects\test64
HANDLE #00000010 = File = \Device\HarddiskVolume1\Windows\winsxs\amd64_microsoft.windows.common-controls_6595b64144ccf1df_5.82.7601.17514_none_a4d6a923711520a9
HANDLE #00000014 = Key = \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Nls\Sorting\Versions
HANDLE #00000018 = ALPC Port
...


"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

WillASM

I'll say it once again Edgar, Thanks!
Your hard work is always appreciated!

I'm not using 64 bit right now, but these will come in handy eventually.
Is there any chance of adding DumpHandles to your 32 version of the macros?
I can see using that occasionally for sure.

Thanks again, WillASM.

PS: How's the race track deal you were working on going?
Hope it works out for you, might be worth a trip down to
check it out with both the flames and oilers out of the play-offs.

donkey

#6
Hi Will,

I had some time today and rewrote the library for 32 bits, everything should work but I lost interest in extensive tests. The only thing that's missing is the stack trace, it seems to have issues that I can't find as of yet, I believe they are related to attaching to the process when it is suspended due to error but it doesn't affect the X64 version so I'm stumped for now. Beyond that there are a few things to remember, since the base size is now DWORDs there are some differences in how QWORDs are handled, specifically immediates are not allowed (for obvious reasons), there are a few others but they escape me at the moment. I will write a help file when I get a chance, until then I imagine you can figure it out, for the most part you can use the 64 bit help file.

This LIB will only function with XP or greater, 9x and Win2K are not supported.

add the following to your code (correcting the path to match your system)

#define DEBUGEXE "C:\RadASM30\GoAsm\dbg\DbgWin.exe"
#IF X64
    #define DBG32LIB "C:\RadASM30\GoAsm\dbg\Debug64.lib"
    #include "C:\RadASM30\GoAsm\dbg\Debug64.a"
#ELSE
    #define DBG32LIB "C:\RadASM30\GoAsm\dbg\Debug32.lib"
    #include "C:\RadASM30\GoAsm\dbg\Debug32.a"
#ENDIF


Note that the includes and defs are exactly the same just change 64<>32. Also the names and syntax of the macros has not changed, all macros in the 64 bit version are supported in 32 bits as well as all data types (with the exception of registers R8 to R15). The same external debug window is used for both the 32 and 64 bit versions so if you already have that there's no need to copy over it.

Edit: Put the Win2K thing in bold red so no-one misses it

Edit: There was an issue that an XMM register would be changed when printing FLOATs, this has been corrected.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

I was cleaning up the 32 bit code today and came away amazed that it didn't crash every time it was run. I did not always clean up the stack after wsprintf which is not necessary in X64 Windows but has to be done in X86. Also one of the macros referenced RAX which is not an issue unless you tried to build without compatibility mode turned on. For whatever reason the PrintLine macro was defined twice, this generated a warning from GoAsm but did not affect any builds. In both the 32 and 64 bit builds I added a call to detach WinDbg from the process when its done disassembling, this didn't seem to have any affect but better safe than sorry.

Finally if it wasn't for the lousy hockey games last night I wouldn't have had to go to the pub to avoid throwing a table through my TV (Will knows what I mean) and as a result didn't get time to work on the stack trace issue.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

#8
Sorry about this guys but I had an epiphany, I have solved the stack trace issue and WOW, I was going to leave it out but in 32 bit mode the SEH stuff is all there and the trace is amazing if you do a debug build...

The following code:
Start:

invoke TestTry,1
invoke ExitProcess,0

TestTry FRAME somepar
invoke TestTry2,1
ret
endf

TestTry2 FRAME somepar
Try()
mov eax,3
mov eax,[eax]
EndTry
ret
endf


Will give you this stack trace:
----------------------------------------
EXCEPTION_ACCESS_VIOLATION encountered at address 0040105D in TestDbg32.exe reading from 00000003
----------------------------------------
Registers
----------------------------------------
EAX 00000003 EBX 7EFDE000 ECX 00000000 EDX 00401000
ESI 00000000 EDI 00000000 EBP 0018FF74 ESP 0018FF74
----------------------------------------
EFLAGS = PF ZF IF
----------------------------------------
Stack trace
----------------------------------------
# ChildEBP RetAddr 
00 0018ff74 0040103a TestDbg32!TestTry2+0x1f
01 0018ff80 00401007 TestDbg32!TestTry+0xa
02 0018ff94 76f79ed2 TestDbg32!Start+0x7
03 0018ffd4 76f79ea5 ntdll!RtlInitializeExceptionChain+0x63
04 0018ffec 00000000 ntdll!RtlInitializeExceptionChain+0x36


So you can understand the quick update. BTW the solution was just to attach to the process before there was an error and detach if there was none. Can't think of anything else that's not working so this will be the last update for a while unless someone finds a bug.

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

I've rewritten much of the 32 bit tools to also be MASM compatible. The library is written in GoAsm however the functions and calls have been decorated for use with MASM, this has no affect on GoAsm so you can use the same lib with both assemblers, just use the right set of macros. For GoAsm the macros are in Debug32.a while the MASM version of the macros  are in Debug32.inc. Both versions use the same debug window.

All macros available to GoAsm are also available to MASM (and also to the 64 bit GoAsm only version). All syntax and parameters are the same with the exception that MASM does not require brackets enclosing the parameters. To use the library with MASM you must enable .MMX since it uses the movq instruction in a few of the macros. DbgHelp.dll and DbgEng.dll should already be on your system, if they aren't they can be downloaded with debugging tools for Windows. There was a lot of room to improve the functionality given MASM's more powerful macro system however I chose to stick to routines that would work in both assemblers and give the same results in both. Because of the way publics work in MASM it was necessary to move some variables to the inc file, this was necessary in the GoAsm macros so the Debug32.a file from previous versions will not work properly with it.

When using the debugging tools I would suggest a Debug build, it will help you get the most out it, especially stack traces, disassembly and symbol dumps.

If you use library for MASM, MASM32 is missing a couple of import libraries, they are included in the package.

I may take on the task of converting the 64 bit library, however because of RIP relative addressing issues GoAsm libraries are not at all compatible with MASM64, it will need to be a complete rewrite.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

Here's some sample output from MASM:

This LIB will only function with XP or greater, 9x and Win2K are not supported.

Executing:
"TestDbg32.exe"

----------------------------------------
Line 29: FPU Dump
----------------------------------------
FPU Levels : 1
Conditional: ST > Source
Exception  : e s p u o z d i
St(0)      : 1.23456700000000
----------------------------------------
Line 32: SomeReal8 = 1.234567000
----------------------------------------
Line 36: Begin spying p_sprintf
----------------------------------------
ADDRESS             DATA
0x010710D9: p_sprintf = 0
0x010710DF: p_sprintf = 1
0x010710E5: p_sprintf = 2
0x010710EB: p_sprintf = 3
0x010710F1: p_sprintf = 4
----------------------------------------
End spying p_sprintf
----------------------------------------
Line 43: Error 0 > The operation completed successfully.

----------------------------------------
Disassembling 10 lines beginning at 01071086
----------------------------------------
01071086 33c0            xor     eax,eax
01071088 60              pushad
01071089 9c              pushfd
0107108a fc              cld
0107108b 6837810701      push    offset TestDbg32!p_sprintf (01078137)
01071090 8f051b800701    pop     dword ptr [TestDbg32!RDBG_SPYVARADDR (0107801b)]
01071096 50              push    eax
01071097 b823800701      mov     eax,offset TestDbg32!RDBG_SPYVARNAME (01078023)
0107109c c700705f7370    mov     dword ptr [eax],70735F70h
010710a2 c7400472696e74  mov     dword ptr [eax+4],offset GDI32!GetStringBitmapA+0x129 (746e6972)
----------------------------------------
Disassembly ended, next instruction at 010710A9
----------------------------------------
----------------------------------------
EXCEPTION_ACCESS_VIOLATION encountered at address 01071170 in TestDbg32.exe reading from 00000003
----------------------------------------
Registers
----------------------------------------
EAX 00000003 EBX 7EFDE000 ECX 00000000 EDX 01071020
ESI 00000000 EDI 00000000 EBP 003FFC2C ESP 003FFC2C
----------------------------------------
EFLAGS = IF
----------------------------------------
Stack trace
----------------------------------------
# ChildEBP RetAddr 
00 003ffc2c 0107114d TestDbg32!EssaiTry2+0x1f
01 003ffc38 01071130 TestDbg32!EssaiTry+0xa
02 003ffc4c 76f79ed2 TestDbg32!_start+0x110
03 003ffc8c 76f79ea5 ntdll!RtlInitializeExceptionChain+0x63
04 003ffca4 00000000 ntdll!RtlInitializeExceptionChain+0x36
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

I've bundled the 32 bit and 64 bit libraries and source together in one zip. The 32 bit library is compatible with MASM and GoAsm, the 64 bit library is for GoAsm only. I have added the following functions to both:

PrintWORD
PrintBYTE
PrintWORDHex
PrintBYTEHex

The PrintXXXHex stuff is a bit outdated as I have now changed the decimal output to include HEX in brackets but if you're not interested in decimal output I left them in, the PrintXXXHex versions are slightly faster.

I also added a PrintDec wrapper that prints out either a QWORD or a DWORD depending on whether you're using the 32 or 64 bit version. Modified a bit of the formatting of the 64 bit version to fall in line with the 32 bit one.

For MASM users the macros would generate a TYPE error if you passed an incorrect type to the PrintXXXX numerical functions, that has been corrected, they are no longer TYPE specific so you can pass a QWORD to PrintDWORD and it will print the low order DWORD only.

I've pretty much run out of ideas of what to include in the tools so if anyone has a suggestion I'd be glad to take a crack at it.

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

As can be seen in this thread I was unaware that the XMM registers were FTZ'ed by the Windows API. In order to keep the debug tools as transparent as possible to the process they run in I have saved/restored the XMM registers using FXSAVE/FXRSTOR. Since some older processors do not support this instruction it is switchable in the 32 bit version of the macros by defining PRESERVEXMMREGS, which will turn the feature on. I have also made a few changes to the MASM version of the macros allowing you to redefine some of the hard coded data in the INC file. You can now set an alternate path for the debug32.lib file as well as the path to the external debug window. For example

.686
.MMX
.XMM

.model flat, stdcall
option casemap :none

PRESERVEXMMREGS equ 1
includelib c:\RadAsm30\GoAsm\Projects\debug32\Debug32.lib
DBG32LIB equ 1
DEBUGEXE textequ <'c:\RadAsm30\GoAsm\Projects\debug32\DbgWin.exe'>
include c:\RadAsm30\GoAsm\Projects\debug32\debug32.inc


For whatever reason you have to have the single quotes (') in the DEBUGEXE textequ, I couldn't make it work with double quotes.

For GoAsm users:

#IF X64
#define DBG64LIB "c:\RadAsm30\GoAsm\dbg\Debug64.lib"
#define DEBUGEXE "c:\RadAsm30\GoAsm\dbg\DbgWin.exe"
#include "c:\RadAsm30\GoAsm\dbg\Debug64.a"
#ELSE
#define PRESERVEXMMREGS
#define DBG32LIB "c:\RadAsm30\GoAsm\dbg\Debug32.lib"
#define DEBUGEXE "c:\RadAsm30\GoAsm\dbg\DbgWin.exe"
#include "c:\RadAsm30\GoAsm\dbg\Debug32.a"
#ENDIF

"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

WillASM

Thank you Edgar for the updated macros!

Sorry for not replying earlier, have been far too busy at work recently.
You did far more than I was hoping for. That really is appreciated!
I have been testing them this morning, and they all seem to be working
as expected. These are a big improvement over the old macros!
Now I will have to program the macro keys on my keyboard again...

Who needs a debugger now?

Much appreciated, Willie

donkey

Thanks Will,

There was a problem with the MASM macros where some would incorrectly display the values in the volatile registers, it has been corrected and a new attachment has been uploaded.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable