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 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.
"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

jj2007

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

donkey

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.
"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 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.

"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

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).
"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

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
"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

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
"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 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
"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 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
"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

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:



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.
"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

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.

"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

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
"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