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"
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
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.
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.
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
...
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.
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.
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.
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
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.
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
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
As can be seen in this thread (http://www.masm32.com/board/index.php?topic=16552.0) 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
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
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.
I have added the Watch/EndWatch functions to MASM/GoAsm 32 bit and GoAsm 64 bit.
QuoteWatch - (SPY_TYPE_XXX,Var) Uses a page guard to monitor a specific varaible in the data section. SPY_TYPE_REGXXX values are not valid for this function
EndWatch - No parameters. Ends watching the variable
Sample output:
----------------------------------------
Line 71: Watching SomeDouble
----------------------------------------
SomeDouble accessed at SOMELABEL+0x0 (0x0040106D): Value = 1.2345
SomeDouble accessed at SomeSubroutine+0xA (0x004010E3): Value = 1.2345
----------------------------------------
Line 84: End Watching SomeDouble
----------------------------------------
Unlike Spy, Watch does not single step the program, making it practical to call subroutines etc...
Warning: This function uses the pvArbitrary field of the TIB and does not preserve its value.
For MASM users, all remaining requirements for the NTDLL import library have been changed to explicit loading so that lib is no longer distributed or needed with the tools.
There were a few fix ups in the 64 bit macros.
Quote from: donkey on May 11, 2011, 04:55:13 AM
This function uses the pvArbitrary field of the TIB and does not preserve its value.
Now that explains it :bg
Clever idea :U
Quote from: jj2007 on May 11, 2011, 07:40:22 AM
Quote from: donkey on May 11, 2011, 04:55:13 AM
This function uses the pvArbitrary field of the TIB and does not preserve its value.
Now that explains it :bg
Clever idea :U
Thanks Jochen,
I should also note that as with the other SEH based tools, you cannot mix or nest them, for example you cannot use a Try in a Watch block. Also if you are using pvArbitrary (which is unlikely as I have never seen it used before) changing the value within a Watch block will most likely cause an access violation. The Watch tool and other debug tools are designed to be run in a single threaded application, their behavior in multithreaded applications is unpredictable.
Finally, with work getting more demanding of my time I have less opportunity to add features, I had started an expression evaluator for the upcoming Assert function but now have little hope that I will finish it. If I do manage to get it up and running it will be a nice addition to the tools.
I have decided it is best to preserve the value of fs:[14h] (gs:[28h] in x64) so the Watch/EndWatch tool now does that. The preservation is across the Watch block so it is saved when Watch is executed and restored when EndWatch is executed. Do not rely on or change the value within the Watch block. This update applies to MASM/GoAsm 32 bit macros and GoAsm 64 bit macros.
There are a few issues with the lstrxxx group of functions and most likely some others when using page guards. Since those functions use SEH and page guards to determine if they need to expand buffers and do not check the status of the memory page before entry and reset the flag on exit regardless of its original value, consequently they will disable the Watch function if called from within a Watch block. This will not effect the run of the program but the tool will stop watching the memory location. I am currently trying to find a solution to the problem but it may take some time as work/life is more demanding of my time now that spring is here (not to mention the Stanley Cup playoffs).
Added an ASSERT function for GoAsm 32 bit and MASM 32 bit, no equivalent for 64 bit yet but it will be along eventually. There was also an error in the 32 bit Debug library when using MASM, some defines were omitted, its been fixed.
Syntax:
GoAsm: ASSERT("ebx=15+9")
MASM: ASSERT "ebx=15+9"
ASSERT uses a separate library so it must be included.
MASM:
PRESERVEXMMREGS equ 1
includelib c:\librarypath\Debug32.lib
includelib C:\librarypath\Assert32.lib
DBG32LIB equ 1
ASSERT32LIB equ 1
DEBUGEXE textequ <'c:\librarypath\DbgWin.exe'>
include c:\includepath\debug32.inc
GoAsm:
#define DEBUGEXE "C:\librarypath\DbgWin.exe"
#define DBG64LIB "C:\librarypath\Debug64.lib"
#define DBG32LIB "C:\librarypath\Debug32.lib"
#define ASSERT32LIB "C:\librarypath\Assert32.lib"
#IF X64
#include "C:\includepath\Debug64.a"
#ELSE
#define PRESERVEXMMREGS
#include "C:\includepath\Debug32.a"
#ENDIF
Edgar
Some notes about ASSERT:
ASSERT enforces a subset of GoAsm syntax, when a symbol is inserted into an expression the address is used unless the symbol is enclosed in square brackets [] in which case the value is used. For registers only the value is used, they cannot be dereferenced. When using a symbol by value an optional type indicator can be used (B,W,D) for example to get the low order WORD from hInstance use W[hInstance], there can be no space between the type indicator and the opening square bracket, if no type indicator is specified D (DWORD) is assumed.
Evaluation is strictly left to right, there is no precedence. If you need to enforce precedence use parenthesis, for example ASSERT("EAX=2*(4+5)") will test EAX=18.
You must use a debug build if you need to have symbols in your ASSERT expression, the function will search the symbol table and extract the necessary data. The function will fail with "Error in expression" if no symbol table is found and you used one in your expression or the symbol itself is not found.
All expressions resolve to TRUE or FALSE, TRUE will allow the debuggee to continue, FALSE will terminate the process.
Defining SIGNEDOP will allow for signed comparisons and MUL/DIV. For example without signed operations -1 is greater than 1, with signed operations it is less.
When an error is found in an expression the macro will output the error code in hex, you will have to check it against the following to find out what happened. Most errors just report CALC_FAIL
#define CALC_FAIL -2
#define CALC_SUCCESS -1
#define CALC_DIVBYZERO -3
#define CALC_OVERFLOW -4
#define CALC_SYMNOTFOUND -5
Edgar
I neglected to add a usage file to the upload so I'll just put it here
operators:
| boolean OR
& boolean AND
^ boolean XOR
* Multiply
/ Divide
+ Add
- Subtract (also indicates a negative number)
! NOT (unary operator)
( Open parenthesis for precedence
) Close parenthesis for precedence
comparisons:
!= Does not equal
!< Is not less than
!> Is not greater than
<> Does not equal
>= Greater than or equal
<= Less than or equal
= Equal
< Less than
> Greater than
other:
[] Used to dereference a label or register
type indicators
B BYTE
W WORD
D DWORD
keywords:
TRUE = 1
FALSE = 0
All x86-32 registers are reserved symbols
All data and code symbols defined in your debug build symbol table
build options:
SIGNEDOP When defined will cause comparisons and MUL/DIV to be signed operations
All expressions will resolve to TRUE or FALSE, TRUE will allow execution to continue with a Success message FALSE will terminate execution.
Syntax:
The syntax for an ASSERT expression is fairly straightforward, it uses natural formulas and resolves them. A label or number can be by itself in the formula or an equation can be one sided (no comparison) in that case it will resolve to FALSE if the result of the calculation is zero. When a comparison is used the two sides of the equation are tested against each other based on the comparison operator and the SIGNEDOP flag and if the comparison fails the expression will resolve to FALSE. The expression must be enclosed in quotes. The negative sign (-) cannot be used to change the sign of a register or symbol, only integers can be resigned.
Examples:
ASSERT("EAX") Checks EAX<>0
ASSERT("[EAX]") Checks the DWORD data at the address contained in EAX for nonzero
ASSERT("W[EAX]") Checks the WORD data at the address contained in EAX for nonzero
ASSERT("EAX=1234") Checks to see if EAX equals 1234
ASSERT("hInstance") Checks the address of hInstance for nonzero
ASSERT("[hInstance]") Checks the value of hInstance for nonzero
ASSERT("B[hInstance]") Checks the low order BYTE of hInstance for nonzero
ASSERT("[hInstance]=1234") Checks if the value of hInstance equals 1234
ASSERT(EAX<>256*4) Checks that EAX does not equal 1024
ASSERT("EAX=2*(4+5)") will test that EAX=18
ASSERT("2+-1") Adds -1 to 2 and checks for nonzero
Note in MASM, the expression does not have to be bracketed for example:
ASSERT "EAX"
The operation stack is 60 deep, this should be more than enough for any reasonable expression.
Report any bugs to this thread
Here's the ASSERT function for GoAsm 64 bit builds. Syntax and usage is the same as for the 32 bit version. Both the 32 and 64 bit versions and the original debug libraries are included in the upload. To use the tools in a project include the following directives:
#DEFINE SIGNEDOP // Optional
#define DEBUGEXE "C:\SomePath\DbgWin.exe"
#define DBG64LIB "C:\SomePath\Debug64.lib"
#define DBG32LIB "C:\SomePath\Debug32.lib"
#DEFINE ASSERT32LIB "C:\SomePath\Assert32.lib"
#DEFINE ASSERT64LIB "C:\SomePath\Assert64.lib"
#IF X64
S=8
#include "C:\SomePath\Debug64.a"
#ELSE
S=4
#define PRESERVEXMMREGS
#include "C:\SomePath\Debug32.a"
#ENDIF
Note that with the 64 bit ASSERT the default data type is QWORD and the type indicator Q has been added. Also, as with the 32 bit version you must have a debug build in order to use symbols in an expression, however with 64 bit the debug data must be COFF
GoAsm /c /x64 "project.Asm"
GoLink "project.obj" /Debug coff
Well, OK maybe one more fix. I have fixed a couple of issues with the MASM version of the macros as well as changed the way the DbgBreak function works. There are no longer any parameters, the message box will prompt you for what you wish to do. As well it displays a bit more information about the DbgBreak to fall a little more in line with the Visual Studio version of the function. The following message box is displayed:
(http://www.masm32.com/board/index.php?action=dlattach;topic=16317.0;id=10303)
You have only to select the option you want and it will either ignore it, stop the program and display some info or execute an INT 3 and whatever default handler you have can take care of it.
Included are GoAsm 32 and 64 bit versions as well as a MASM 32 bit version.
(note that DbgBreak.jpg.zip is just the image above, there is no need to download it)
EDIT: Added the capability to turn off the debug functions without having to remove them from your program. For example if you have a DbgBreak in your source code you can have it not insert any code in a release build but insert the break in a debug build. To turn off the macros just define NODEBUGTOOLS:
GoAsm: #DEFINE NODEBUGTOOLS
MASM: NODEBUGTOOLS equ 1
And the macros will not insert any code or data.
Bugifx for the debug window when not using RadAsm, the output would be all on one line. This only affected the 32 bit version but I did a full upload anyway.
Today I was using ASSERT and thought to myself "I can't believe that I didn't allow for HEX numbers !". For whatever reason it never occurred to me until today. Anyway the format for HEX numbers is C style:
0xFFFF
The MASM format of 0FFFFh is not supported (I don't really use it so I didn't bother adding it).
Example:
ASSERT("[hInstance]=0x00400000")
For Assert32 the largest HEX number is 0xFFFFFFFF (-1), for Assert64 it is 0xFFFFFFFFFFFFFFFF (-1)
Edgar