The Science of Debugging
Chapter 6


6.4.3 Examining the Stack

As we discussed above, the 'Stack' is the collection of all the frames from the program's execution, and each has all the information about what happened at that level. Your debugger will show you what the problem is, but you often must traverse the stack to locate it's origin. First though, lets take a look at a stack. From the gdb command line, type 'backtrace'.

(gdb) backtrace
#0  0x80483a6 in main (argc=1, argv=0xbffffd14) at gdbex1.c:7
(gdb)






Well, this seems to be a rather uncomplicated stack - it's only 1 level deep. Not much to look at there, so I'm going to use a more complicated example. I'm going to add a call to strcmp with a NULL pointer in the function do_date() from the CircleMUD codebase. This will give us a more detailed backtrace, and will let us see what a 'real' program looks like. Note that I've abbreviated backtrace as 'bt'. Many of the commands in gdb have shortcuts, and after a while, it's a habit to type that instead. In anycase though, here's our output:

Program received signal SIGSEGV, Segmentation fault.
0x8063322 in do_date (ch=0x82ab598, argument=0xbffff94c "", cmd=52, subcmd=0)
    at act.wizard.c:1564
1564       strcmp(NULL,NULL);
(gdb) bt
#0  0x8063322 in do_date (ch=0x82ab598, argument=0xbffff94c "", cmd=52,
     subcmd=0) at act.wizard.c:1564
#1  0x807d12a in command_interpreter (ch=0x82ab598, argument=0xbffff948
     "date") at interpreter.c:644
#2 0x806d83b in game_loop (mother_desc=6) at comm.c:720
#3 0x806cef8 in init_game (port=4000) at comm.c:353
#4 0x806ce75 in main (argc=3, argv=0xbffffcd4) at comm.c:317
(gdb)
















This is a bit more complex, but it is more like what you're going to see on a day to day basis. Here we see 5 different frames, and as you can see, each corresponds to a function call; do_date(), command_interpreter(), game_loop(),init_game(), and of course, main(). As we said a few times before, each frame in the stack has it's own seperate variables. For example, do_date's frame 0 and frame 1 both have a ch variable, and an argument variable. We can tell just by looking at the backtrace that the ch variable points to the same memory location, 0x82ab598. However, the argument variables are different. The question then, is how do we differentiate between the two? The answer is by using the 'frame' command.

(gdb) print argument
$1 = 0xbffff94c ""
(gdb) frame 1
#1  0x807d12a in command_interpreter (ch=0x82ab598, argument=0xbffff948
   "date") at interpreter.c:644
644       ((*cmd_info[cmd].command_pointer) (ch, line, cmd,
   cmd_info[cmd].submd));
(gdb) print argument
$2 = 0xbffff948 "date"
(gdb)













It's a simple command that only takes one argument, a number, and sets up that frame to examine. That lets you switch frames.

To actually display the information in the stack, we have one last command; info. There are many (MANY) possible arguments to the info command, but we're just going to concentrate on three; frame, locals, args. In brief, they show information about the frame, the local variables, and the arguments to the function in the current frame. Here's an example;

Frame:
(gdb) info frame
Stack level 0, frame at 0xbffff85c:
eip = 0x8063322 in do_date (act.wizard.c:1564); saved eip 0x807d12a
called by frame at 0xbffff894
source language c.
Arglist at 0xbffff85c, args: ch=0x82ab598, argument=0xbffff94c "",
cmd=52, subcmd=0
Locals at 0xbffff85c, Previous frame's sp is 0x0
Saved registers:
ebx at 0xbffff840, ebp at 0xbffff85c, esi at 0xbffff844, edi at
0xbffff848,
eip at 0xbffff860
(gdb)















Locals:
(gdb) info locals
__s1_len = 134624012
__s2_len = 4294967295
subcmd = 0
tmstr = 0x80aaa68 ""
mytime = 1040
d = 0
h = 0
(gdb)











Args:
(gdb) info args
ch = (struct char_data *) 0x82ab598
argument = 0xbffff94c ""
cmd = 52
subcmd = 0
(gdb)










Index
6.1.3.2 Examining Variables 6.1.4 Run Time Debugging