You are on page 1of 3

Very Advanced Debugging tips - Calvin Hsia's WebLog - Site Home ...

1 de 3

http://blogs.msdn.com/b/calvin_hsia/archive/2004/10/22/246382.aspx

Very Advanced Debugging tips


CalvinH 22 Oct 2004 9:56 AM

While debugging code, it might take very many complicated steps to reproduce an issue. The following applies to
debugging both Visual FoxPro and Visual Studio Native code debugging, except where noted. The VFP
debugger is modeled after the VS debugger, with the same plethora of windows: call stack, output, watch, locals,
etc.)
Stepping through from breakpoint to breakpoint, you might accidentally step over a function/method call rather
than into it. Just right click on the desired line and choose Set Next Statement (or Shift-Ctrl-F10 in VS) This is
changing the Instruction Pointer (IP). Keep in mind this executes the function again, and it may have had side
effects. Also, you cant just change the Instruction Pointer arbitrarily. Both VS and VFP give a warning when you
try to do something bad, like Set Next Statement into a different function, bypassing function initialization, local
variable declarations, etc.
The Call stack is your friend. Its very important to see how the code youre looking at got called. You can click on
the call stack at various levels to examine variables and code at those levels.
Many times, debugging causes the application to behave differently. For example, put a breakpoint on the VFP
Activate Method or the Window Procedure WM_ACTIVATE and it will be fired every time you resume from the
debugger. In this and many other cases, its important to use the Debug Output window to show values
dynamically.
In VFP, DEBUGOUT "this is a test",_vfp.Caption will output to the Debug Output window. For native
code, the OutputDebugString API will do the trick.
Another useful technique is to modify the code and continue debugging. In certain versions of VB and VC# you
could do that with native VS support called Edit and Continue. In FoxPro, you can do that by stepping out of the
compiled code (PRG or VCX) , recompiling just that part, then stepping back in (via Set Next Statement). FoxPro
does not require you to build an APP or EXE to run your code, so your code compile granularity is quite small. In
VS Native code debugging, you can do that by stepping out until the module you want to modify is unloaded, then
it can be recompiled and reloaded. Same idea as VFP, but the compiled unit granularity is quite coarse.
However, in VS there is another simple way if the code you want to c change is fairly minor.
The rest of this blog concerns only VS debugging: not VFP.
(Tip: Make sure you have debug symbols loaded: heres how)
Just right click and choose Go To Disassembly(Ctrl-F11) and make sure addresses and code bytes are displayed
(context menu).
Heres an example
if (sysusr >= MNPUSHFROMDEFAULT_MENU_BAR) {
cmp
dword ptr [sysusr],64h
jl
MNPushMenu2+1AEh (94E29Eh)
miPtr->iStatus &= ~(IONSELSET | IONENTRYSET | IONEXITSET);
0094E28A 8B 45 EC
mov
eax,dword ptr [miPtr]
0094E28D 8B 48 04
mov
ecx,dword ptr [eax+4]
0094E290 81 E1 7F CF FF FF and
ecx,0FFFFCF7Fh
0094E296 8B 55 EC
mov
edx,dword ptr [miPtr]
0094E299 89 4A 04
mov
dword ptr [edx+4],ecx
} else {
0094E29C EB 12
jmp
MNPushMenu2+1C0h (94E2B0h)
niPtr->iStatus &= ~(IONSELSET | IONENTRYSET | IONEXITSET);
0094E29E 8B 45 E8
mov
eax,dword ptr [niPtr]
0094E2A1 8B 48 04
mov
ecx,dword ptr [eax+4]
0094E2A4 81 E1 7F CF FF FF and
ecx,0FFFFCF7Fh
0094E2AA 8B 55 E8
mov
edx,dword ptr [niPtr]
0094E2AD 89 4A 04
mov
dword ptr [edx+4],ecx
}
0094E284 83 7D 10 64
0094E288 7C 14

In this code, I want to change the code to do the code in the else clause always (remove the else line). Its a
simple modification without recompiling.
Open a memory window via Debug->Window->Memory or Ctrl-Alt-M1 for Whidbey (I think its Ctrl-Alt-M for
VS.Net 2003, which only had 1 memory window, instead of the 4 for Whidbey).
Drag the desired address and drop it on the memory window.
0x0094E29C
0x0094E2A4
0x0094E2AC
0x0094E2B4

eb
81
e8
ff

12
e1
89
8b

8b
7f
4a
45

45
cf
04
f4

e8
ff
e9
83

8b
ff
28
38

48
8b
ff
02

04
55
ff
74

You see the else being a 2 byte jmp instruction.


We just want to replace these 2 bytes with a NOP (No Operation: Op Code= 0x90) which does nothing. Just
change the eb 12 in the memory window (it even has UnDo) to 90 90
The disassembly reflects this nicely:
0094E299 89 4A 04
0094E29C 90
0094E29D 90

mov
} else {
nop
nop

dword ptr [edx+4],ecx

Now the currently loaded code has been changed and the modified version of this code will be executed. The
disk version of the module has not been changed.

30/03/2015 7:22

Very Advanced Debugging tips - Calvin Hsia's WebLog - Site Home ...

http://blogs.msdn.com/b/calvin_hsia/archive/2004/10/22/246382.aspx

Not only can you change OP codes, but you can change data too. For example, the 0FFFFCF7F from above can
be changed: you can see the value in the memory window.
Armed with this technique, you can reduce the number of times you need to execute the repro scenario.

Another technique is to keep your register window open. (Debug->Windows->Registers). The return value of a
native code function call is in register EAX. If youre stepping through assembly code, you can see it easily. If
youre stepping through C++ code, it might not be seen as easily (destructors or overloaded operators might fire
after the function call)
If the IP is on the first line above (0094E284) the register window shows this: (you might have to use the context
menu to show Effective Address)
EAX
EDX
EIP
EFL

=
=
=
=

022D0B0C EBX = 7FFDF000 ECX = 00080B00


022D0B0C ESI = 0012DA14 EDI = 0012D618
0094E284 ESP = 0012CC84 EBP = 0012CCA4
00000206

CS = 0000 DS = 0023 ES = 0023 SS = 0023 FS = 003B


GS = 0000
0012CCB4 = 00000065

The red values show the changes each time you step. The last value shows the effective address. Since this is a
CMP instruction, it shows the value of dword ptr [sysusr] which is 0x65

Another example is dword ptr [eax+4], which is handy to see in the register window.
You can do other fancy things in the register window, like change the IP register directly (EIP means Extended
Instruction Pointer, the 32 bit version of the 16 bit IP register found on the 8080. Same all the registers starting
with E, like EAX, EBX, etc.)
41561

Comments

Garry Trinder 3 Dec 2004 4:49 PM #

Garry Trinder 3 Dec 2004 6:56 PM #

Garry Trinder 6 Feb 2006 4:04 PM #

As a software developer, I spend much of my time looking at code, learning how it works, and figuring...

Garry Trinder 3 May 2006 2:32 PM #

I received a comment on this post: Will GetLastError ever work properly in VFP8.0?.  I was
consistently...

Arya 16 Aug 2006 3:00 PM #

In case of debugging watson crash dumps ... what do we need to look for in the disassembly! I am new
at this, so please explain in detail...
Thanks!

Mr. Raybell 10 Oct 2006 5:09 PM #

Does modifying the registers only work in native debugging, or can you modify them in managed
debugging as well? If so, I can't manage to figure out how to work it, so perhaps I'm missing
something? It'd be horribly handy for what I'm doing right now.

Garry Trinder 26 Feb 2007 1:44 PM #

Lets log all the calls that Excel makes to open or create a file. Start Visual Studio (any version),

Rajeev 3 Mar 2007 6:03 AM #

While I am dubugging a very large code (15000 lines) in VC++, for some of the local variables, it does
NOT show the value while debugging. Is there some setting I need to do so that I can see the values of
all the variables while debugging?

2 de 3

30/03/2015 7:22

Very Advanced Debugging tips - Calvin Hsia's WebLog - Site Home ...

3 de 3

http://blogs.msdn.com/b/calvin_hsia/archive/2004/10/22/246382.aspx

Garry Trinder 19 Jan 2009 9:48 PM #

There are various leak detection methods for memory allocators. A popular one is to tag each allocation

30/03/2015 7:22

You might also like