GDB for WinDbg Users (Part 6)
Sunday, July 22nd, 2007Once we get backtrace in GDB or stack trace in WinDbg we are interested in concrete stack frames, their arguments and local variables. I slightly modified the program used in the previous part to include some local variables:
#include <stdio.h>
void func_1(int param_1, char param_2, int *param_3, char *param_4);
void func_2(int param_1, char param_2, int *param_3, char *param_4);
void func_3(int param_1, char param_2, int *param_3, char *param_4);
void func_4();
int g_val_1;
char g_val_2;
int *g_pval_1 = &g_val_1;
char *g_pval_2 = &g_val_2;
int main()
{
int local_0 = 0;
char *hello = "Hello World!";
g_val_1 = 1;
g_val_2 = '1';
func_1(g_val_1, g_val_2, (int *)g_pval_1, (char *)g_pval_2);
return 0;
}
void func_1(int param_1, char param_2, int *param_3, char *param_4)
{
int local_1 = 1;
g_val_1 = 2;
g_val_2 = '2';
param_3 = &local_1;
func_2(g_val_1, g_val_2, param_3, param_4);
}
void func_2(int param_1, char param_2, int *param_3, char *param_4)
{
int local_2 = 2;
g_val_1 = 3;
g_val_2 = '3';
param_3 = &local_2;
func_3(g_val_1, g_val_2, param_3, param_4);
}
void func_3(int param_1, char param_2, int *param_3, char *param_4)
{
int local_3 = 3;
*g_pval_1 += param_1;
*g_pval_2 += param_2;
func_4();
}
void func_4()
{
puts("Hello World!");
}
In GDB the frame command is used to set the current stack frame. Then info args command can be used to list function arguments and info locals command can be used to list local variables:
(gdb) break func_4
Breakpoint 1 at 0x401455: file test.c, line 61.
(gdb) run
Starting program: C:\MinGW\examples/test.exe
Breakpoint 1, func_4 () at test.c:61
61 puts("Hello World!");
(gdb) bt
#0 func_4 () at test.c:61
#1 0x0040144d in func_3 (param_1=3, param_2=51 '3', param_3=0x22ff10,
param_4=0x404070 "f") at test.c:56
#2 0x0040140c in func_2 (param_1=2, param_2=50 '2', param_3=0x22ff10,
param_4=0x404070 "f") at test.c:46
#3 0x004013ba in func_1 (param_1=1, param_2=49 '1', param_3=0x22ff30,
param_4=0x404070 "f") at test.c:34
#4 0x00401363 in main () at test.c:21
(gdb) frame
#0 func_4 () at test.c:61
61 puts("Hello World!");
(gdb) frame 0
#0 func_4 () at test.c:61
61 puts("Hello World!");
(gdb) info args
No arguments.
(gdb) info locals
No locals.
(gdb) frame 1
#1 0x0040144d in func_3 (param_1=3, param_2=51 '3', param_3=0x22ff10,
param_4=0x404070 "f") at test.c:56
56 func_4();
(gdb) info args
param_1 = 3
param_2 = 51 '3'
param_3 = (int *) 0x22ff10
param_4 = 0x404070 "f"
(gdb) info locals
local_3 = 3
param_2 = 51 '3'
(gdb) frame 2
#2 0x0040140c in func_2 (param_1=2, param_2=50 '2', param_3=0x22ff10,
param_4=0x404070 "f") at test.c:46
46 func_3(g_val_1, g_val_2, param_3, param_4);
(gdb) info args
param_1 = 2
param_2 = 50 '2'
param_3 = (int *) 0x22ff10
param_4 = 0x404070 "f"
(gdb) info locals
local_2 = 2
param_2 = 50 '2'
(gdb) frame 3
#3 0x004013ba in func_1 (param_1=1, param_2=49 '1', param_3=0x22ff30,
param_4=0x404070 "f") at test.c:34
34 func_2(g_val_1, g_val_2, param_3, param_4);
(gdb) info args
param_1 = 1
param_2 = 49 '1'
param_3 = (int *) 0x22ff30
param_4 = 0x404070 "f"
(gdb) info locals
local_1 = 1
param_2 = 49 '1'
(gdb) frame 4
#4 0x00401363 in main () at test.c:21
21 func_1(g_val_1, g_val_2, (int *)g_pval_1, (char *)g_pval_2);
(gdb) info args
No arguments.
(gdb) info locals
local_0 = 0
hello = 0x403000 "Hello World!"
(gdb)
In WinDbg kn command shows stack trace with frame numbers, knL command additionally omits source code references, .frame command switches to particular stack frame, dv command shows parameters and local variables together, dv /i command classifies them into categories, parameters or locals, dv /V command shows their addresses and offsets for the relevant base frame register, usually EBP, dv /t command shows type information:
Microsoft (R) Windows Debugger Version 6.7.0005.1
Copyright (c) Microsoft Corporation. All rights reserved.
CommandLine: C:\dmitri\test\release\test.exe
Symbol search path is: SRV*c:\websymbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
ModLoad: 00400000 0040f000 test.exe
ModLoad: 7d4c0000 7d5f0000 NOT_AN_IMAGE
ModLoad: 7d600000 7d6f0000 C:\W2K3\SysWOW64\ntdll32.dll
ModLoad: 7d4c0000 7d5f0000 C:\W2K3\syswow64\kernel32.dll
(e38.ac0): Break instruction exception - code 80000003 (first chance)
eax=7d600000 ebx=7efde000 ecx=00000005 edx=00000020 esi=7d6a01f4 edi=00221f38
eip=7d61002d esp=0012fb4c ebp=0012fcac iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
ntdll32!DbgBreakPoint:
7d61002d cc int 3
0:000> bp func_4
0:000> g
ModLoad: 71c20000 71c32000 C:\W2K3\SysWOW64\tsappcmp.dll
ModLoad: 77ba0000 77bfa000 C:\W2K3\syswow64\msvcrt.dll
ModLoad: 00410000 004ab000 C:\W2K3\syswow64\ADVAPI32.dll
ModLoad: 7da20000 7db00000 C:\W2K3\syswow64\RPCRT4.dll
ModLoad: 7d8d0000 7d920000 C:\W2K3\syswow64\Secur32.dll
Breakpoint 0 hit
eax=0040c9d4 ebx=7d4d8df9 ecx=0040c9d4 edx=00000066 esi=00000002 edi=00000ece
eip=00408be0 esp=0012ff10 ebp=0012ff18 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
test!func_4:
00408be0 55 push ebp
0:000> knL
# ChildEBP RetAddr
00 0012ff0c 00408c38 test!func_4
01 0012ff18 00408c7c test!func_3+0x38
02 0012ff34 00408ccc test!func_2+0x3c
03 0012ff50 00408d24 test!func_1+0x3c
04 0012ff70 00401368 test!main+0x44
05 0012ffc0 7d4e7d2a test!__tmainCRTStartup+0x15f
06 0012fff0 00000000 kernel32!BaseProcessStart+0x28
0:000> .frame
00 0012ff0c 00408c38 test!func_4 [c:\dmitri\test\test\test.cpp @ 60]
0:000> .frame 0
00 0012ff0c 00408c38 test!func_4 [c:\dmitri\test\test\test.cpp @ 60]
0:000> dv
0:000> .frame 1
01 0012ff18 00408c7c test!func_3+0x38 [c:\dmitri\test\test\test.cpp @ 57]
0:000> dv
param_1 = 3
param_2 = 51 '3'
param_3 = 0x0012ff30
param_4 = 0x0040c9d4 "f"
local_3 = 3
0:000> dv /i
prv param param_1 = 3
prv param param_2 = 51 '3'
prv param param_3 = 0x0012ff30
prv param param_4 = 0x0040c9d4 "f"
prv local local_3 = 3
0:000> dv /i /V
prv param 0012ff20 @ebp+0x08 param_1 = 3
prv param 0012ff24 @ebp+0x0c param_2 = 51 '3'
prv param 0012ff28 @ebp+0x10 param_3 = 0x0012ff30
prv param 0012ff2c @ebp+0x14 param_4 = 0x0040c9d4 "f"
prv local 0012ff14 @ebp-0x04 local_3 = 3
0:000> .frame 4
04 0012ff70 00401368 test!main+0x44 [c:\dmitri\test\test\test.cpp @ 21]
0:000> dv
local_0 = 0
hello = 0x0040a274 "Hello World!"
0:000> dv /i
prv local local_0 = 0
prv local hello = 0x0040a274 "Hello World!"
0:000> dv /i /V
prv local 0012ff68 @ebp-0x08 local_0 = 0
prv local 0012ff6c @ebp-0x04 hello = 0x0040a274 "Hello World!"
0:000> dv /t
int local_0 = 0
char * hello = 0x0040a274 "Hello World!"
Our comparison table grows a bit:
Action | GDB | WinDbg ---------------------------------------------------------------- Start the process | run | g Exit | (q)uit | q Disassemble (forward) | (disas)semble | uf, u Disassemble N instructions | x/<N>i | - Disassemble (backward) | - | ub Stack trace | backtrace (bt) | k Full stack trace | bt full | kv Stack trace with parameters | bt full | kP Partial trace (innermost) | bt <N> | k <N> Partial trace (outermost) | bt -<N> | - Stack trace for all threads | thread apply all bt | ~*k Breakpoint | break | bp Frame numbers | any bt command | kn Select frame | frame | .frame Display parameters | info args | dv /t /i /V Display locals | info locals | dv /t /i /V
- Dmitry Vostokov @ DumpAnalysis.org -