Sun Studio 12: Debugging a Program With dbx

Chapter 7 Using the Call Stack

This chapter discusses how dbx uses the call stack, and how to use the where command, hide command, unhide command, and pop command when working with the call stack.

The call stack represents all currently active routines—routines that have been called but have not yet returned to their respective caller. A stack frame is a section to the call stack allocated for use by a single function.

Because the call stack grows from higher memory (larger addresses) to lower memory, up means going toward the caller’s frame (and eventually main()) and down means going toward the frame of the called function (and eventually the current function). The frame for the routine executing when the program stopped at a breakpoint, after a single-step, or when a fault occurs and produces a core file, is in lower memory. A caller routine, such as main(), is located in higher memory.

This chapter is organized into the following sections:

Finding Your Place on the Stack

Use the where command to find your current location on the stack.


where [-f] [-h] [-l] [-q] [-v] number_id

When debugging an application that is a mixture of JavaTM code and C JNI (Java Native Interface) code or C++ JNI code, the syntax of the where command is:


where [-f] [-q] [-v] [ thread_id ] number_id

The where command is also useful for learning about the state of a program that has crashed and produced a core file. When this occurs, you can load the core file into dbx (see Debugging a Core File)

For more information on the where command, see where Command.

Walking the Stack and Returning Home

Moving up or down the stack is referred to as “walking the stack.” When you visit a function by moving up or down the stack, dbx displays the current function and the source line. The location from which you start, home, is the point where the program stopped executing. From home, you can move up or down the stack using the up command, down command, or frame command.

The dbx commands up and down both accept a number argument that instructs dbx to move a number of frames up or down the stack from the current frame. If number is not specified, the default is 1. The -h option includes all hidden frames in the count.

Moving Up and Down the Stack

You can examine the local variables in functions other than the current one.

Moving Up the Stack

To move up the call stack (toward main) number levels:


up [-h] [ number ]

If you do not specify number, the default is one level. For more information, see up Command.

Moving Down the Stack

To move down the call stack (toward the current stopping point) number levels:


down [-h] [ number ]

If you do not specify number, the default is one level. For more information, see down Command.

Moving to a Specific Frame

The frame command is similar to the up command and down command. It lets you go directly to the frame as given by numbers displayed by the where command.


frame
frame -h
frame [-h] number
frame [-h] +[number]
frame [-h] -[number]

The frame command without an argument displays the current frame number. With number, the command lets you go directly to the frame indicated by the number. By including a + (plus sign) or - (minus sign), the command lets you move an increment of one level up (+) or down (-). If you include a plus or minus sign with a number, you can move up or down the specified number of levels. The- h option includes any hidden frames in the count.

You can also move to a specific frame using the pop command (see Popping the Call Stack).

Popping the Call Stack

You can remove the stopped in function from the call stack, making the calling function the new stopped in function.

Unlike moving up or down the call stack, popping the stack changes the execution of your program. When the stopped in function is removed from the stack, it returns your program to its previous state, except for changes to global or static variables, external files, shared members, and similar global states.

The pop command removes one or more frames from the call stack. For example, to pop five frames from the stack, type:


pop 5

You can also pop to a specific frame. To pop to frame 5, type:


pop -f 5

For more information, see pop Command.

Hiding Stack Frames

Use the hide command to list the stack frame filters currently in effect.

To hide or delete all stack frames matching a regular expression, type:


hide [ regular_expression ]

The regular_expression matches either the function name, or the name of the loadobject, and uses sh or ksh syntax for file matching.

Use the unhide to delete all stack frame filters.


unhide 0

Because the hide command lists the filters with numbers, you can also use the unhide command with the filter number.


unhide [ number | regular_expression ]

Displaying and Reading a Stack Trace

A stack trace shows where in the program flow execution stopped and how execution reached this point. It provides the most concise description of your program’s state.

To display a stack trace, use the where command.

For functions that were compiled with the -g option, the names and types of the arguments are known so accurate values are displayed. For functions without debugging information hexadecimal numbers are displayed for the arguments. These numbers are not necessarily meaningful. When a function call is made through function pointer 0, the function value is shown as a low hexadecimal number instead of a symbolic name.

You can stop in a function that was not compiled with the -g option. When you stop in such a function dbx searches down the stack for the first frame whose function is compiled with the -g option and sets the current scope (see Program Scope) to it. This is denoted by the arrow symbol (=>).

In the following example, main() was compiled with the -g option, so the symbolic names as well as the values of the arguments are displayed The library functions called by main() were not compiled with -g, so the symbolic names of the functions are displayed but the hexadecimal contents of the SPARC input registers $i0 through $i5 are shown for the arguments.


(dbx) where
  [1] _libc_poll(0xffbef3b0, 0x1, 0xffffffff, 0x0, 0x10, 0xffbef604), at 0xfef9437c
  [2] _select(0xffbef3b8, 0xffbef580, 0xffbef500, 0xffbef584, 0xffbef504, 0x4), at 0xfef4e3dc
  [3] _XtWaitForSomething(0x5a418, 0x0, 0x0, 0xf4240, 0x0, 0x1), at 0xff0bdb6c
  [4] XtAppNextEvent(0x5a418, 0x2, 0x2, 0x0, 0xffbef708, 0x1), at 0xff0bd5ec
  [5] XtAppMainLoop(0x5a418, 0x0, 0x1, 0x5532d, 0x3, 0x1), at 0xff0bd424
=>[6] main(argc = 1, argv = 0xffbef83c), line 48 in "main.cc"
:

In this example, the program has crashed with a segmentation fault. Again only main() has been compiled with the -g option, so the arguments to the library functions are displayed as hexadecimal without symbolic names. The cause of the crash is most likely the null arguments to strlen() in SPARC input registers $i0 and $i1


(dbx) run
Running: Cdlib
(process id 6723)

CD Library Statistics:

 Titles:         1

 Total time:     0:00:00
 Average time:   0:00:00

signal SEGV (no mapping at the fault address) in strlen at 0xff2b6c5c
0xff2b6c5c: strlen+0x0080:    ld      [%o1], %o2
Current function is main
(dbx) where
  [1] strlen(0x0, 0x0, 0x11795, 0x7efefeff, 0x81010100, 0xff339323), at 0xff2b6c5c
  [2] _doprnt(0x11799, 0x0, 0x0, 0x0, 0x0, 0xff00), at 0xff2fec18
  [3] printf(0x11784, 0xff336264, 0xff336274, 0xff339b94, 0xff331f98, 0xff00), at 0xff300780
=>[4] main(argc = 1, argv = 0xffbef894), line 133 in "Cdlib.c"
(dbx)

For more examples of stack traces, see Looking at the Call Stack and Tracing Calls.