Debugging a Program With dbx HomeContentsPreviousNextIndex


Chapter 6

Event Management

Event management refers to the capability of dbx to perform actions when events take place in the program being debugged.

This chapter is organized into the following sections:

Event Handlers

Event management is based on the concept of a handler. The name comes from an analogy with hardware interrupt handlers. Each event management command typically creates a handler, which consists of an event specification and a series of side-effect actions. (See Setting Event Specifications.) The event specification specifies the event that will trigger the handler.

When the event occurs and the handler is triggered, the handler evaluates the event according to any modifiers included in the event specification. (See Event Specification Modifiers.) If the event meets the conditions imposed by the modifiers, the handler's side-effect actions are performed (that is, the handler "fires").

An example of the association of a program event with a dbx action is setting a breakpoint on a particular line.

The most generic form of creating a handler is by using the when command.

when event-specification {action; ... }

Examples in this chapter show how you can write a command (like stop, step, or ignore) in terms of when. These examples are meant to illustrate the flexibility of when and the underlying handler mechanism, but they are not always exact replacements.

Creating Event Handlers

Use the commands when, stop, and trace to create event handlers.

stop is shorthand for a common when idiom.

when event-specification { stop -update; whereami; }

An event-specification is used by the event management commands stop, when, and trace to specify an event of interest. (see Setting Event Specifications).

Most of the trace commands can be handcrafted using the when command, ksh functionality, and event variables. This is especially useful if you want stylized tracing output.

For detailed information, see "when Command," "stop Command," and "trace Command" in the Using dbx Commands section of the Sun WorkShop online help.

Every command returns a number known as a handler id (hid). You can access this number using the predefined variable $newhandlerid.

An attempt has been made to make the stop and when commands conform to the handler model. However, backward compatibility with previous dbx releases forces some deviations.

For example, the following samples from an earlier dbx release are equivalent.

Old New
when cond body when step -if cond body
when cond in func body when next -if cond -in func body


These samples illustrate that cond is not a pure event; there is no internal handler for conditions.

Manipulating Event Handlers

You can use the following commands to manipulate event handlers. For more information on each command, see the cited topic in the Using dbx Commands section of the Sun WorkShop online help.

Using Event Counters

An event handler has a trip counter, which has a count limit. Whenever the specified event occurs, the counter is incremented. The action associated with the handler is performed only if the count reaches the limit, at which point the counter is automatically reset to 0. The default limit is 1. Whenever a process is rerun, all event counters are reset.

You can set the count limit using the -count modifier with a stop, when, or trace command (see -count n -count infinity). Otherwise, use the handler command to individually manipulate event handlers:.

handler [ -count | -reset ] hid new-count new-count-limit

Setting Event Specifications

Event specifications are used by the stop, when, and trace commands to denote event types and parameters. The format consists of a keyword representing the event type and optional parameters. For more information, see "Event Specification" in the Using dbx Commands section of the Sun WorkShop online help.

Breakpoint Event Specifications

The following are event specifications for breakpoint events.

in function

The function has been entered, and the first line is about to be executed. If the -instr modifier is used (see -instr), it is the first instruction of the function about to be executed. The func specification can take a formal parameter signature to help with overloaded function names or template instance specification. For example:

 stop in mumble(int, float, struct Node *)


Note – Do not confuse in function with the -in function modifier.

at [filename:]lineno

The designated line is about to be executed. If you specify filename, then the designated line in the specified file is about to be executed. The file name can be the name of a source file or an object file. Although quotation marks are not required, they may be necessary if the file name contains special characters. If the designated line is in template code, a breakpoint is placed on all instances of that template.

infunction function

Equivalent to in function for all overloaded functions named function or all template instantiations thereof.

inmember function
inmethod function

Equivalent to in function for the member function named function for every class.

inclass classname

Equivalent to in function for all member functions that are members of classname.

inobject object-expression

A member function called on the specific object at the address denoted by object-expression has been called.

Watchpoint Event Specifications

The following are event specifications for watchpoint events. For more information, see "Watchpoint Specification" in the Using dbx Commands section of the Sun WorkShop online help.

access mode addr-expression [, byte-size-expression]

The memory specified by addr-expression has been accessed.

mode specifies that the memory was accessed. It can be composed of one or all of the letters:

r The memory has been read.
w The memory has been written to.
x The memory has been executed.


mode can also contain either of the following:

a Stops the process after the access (default).
b Stops the process before the access.


In both cases the program counter will point at the offending instruction. The "before" and "after" refer to the side effect.

address-expression is any expression that can be evaluated to produce an address. If you give a symbolic expression, the size of the region to be watched is automatically deduced; you can override it by specifying byte-size-expression. You can also use nonsymbolic, typeless address expressions; in which case, the size is mandatory. For example:

stop access 0x5678, sizeof(Complex)

The access command has the limitation that no two matched regions may overlap.


Note – The access event specification is a replacement for the modify event specification. While both syntaxes work on Solaris 2.6, Solaris 7, and Solaris 8, on all of these operating environments except Solaris 2.6, access suffers the same limitations as modify and accepts only a mode of wa.

change variable

The value of variable has changed.

cond condition-expression

The condition denoted by cond-expression evaluates to true. You can specify any expression for cond-expression, but it must evaluate to an integral type.

modify address-expression [,byte-size-expression]

The specified address range has been modified. This is the older watchpoint facility.

address-expression is any expression that can be evaluated to produce an address. If you give a symbolic expression, the size of the region to be watched is automatically deduced; you can override it by specifying byte-size-expression. You can also use nonsymbolic, typeless address expressions; in which case, the size is mandatory. For example:

stop modify 0x5678, sizeof(Complex)


Note – Multithreaded applications are prone to deadlock so mt watchpoints are nominally disallowed. They can be turned on by setting the dbx environment variable mt_watchpoints.

System Event Specifications

The following are event specifications for system events.

dlopen [ lib-path ] | dlclose [ lib-path ]

These events occur after a dlopen() or a dlclose() call succeeds. A dlopen() or dlclose() call can cause more than one library to be loaded. The list of these libraries is always available in the predefined variable $dllist. The first word in $dllist is a "+" or a "-", indicating whether the list of libraries is being added or deleted.

lib-path is the name of a shared library. If it is specified, the event occurs only if the given library was loaded or unloaded. In that case, $dlobj contains the name of the library. $dllist is still available.

If lib-path begins with a /, a full string match is performed. Otherwise, only the tails of the paths are compared.

If lib-path is not specified, then the events always occur whenever there is any dl-activity. In this case, $dlobj is empty but $dllist is valid.

fault fault

The fault event occurs when the specified fault is encountered. The faults are architecture-dependent. The following set of faults known to dbx is defined in the proc(4) man page.

Fault Description
FLTILL Illegal instruction
FLTPRIV Privileged instruction
FLTBPT Breakpoint trap
FLTTRACE* Trace trap (single step)
FLTWATCH Watchpoint trap
FLTACCESS* Memory access (such as alignment)
FLTBOUNDS* Memory bounds (invalid address)
FLTIOVF Integer overflow
FLTIZDIV Integer zero divide
FLTPE Floating-point exception
FLTSTACK Irrecoverable stack fault
FLTPAGE Recoverable page fault



Note – BPT, TRACE, and BOUNDS are used by dbx to implement breakpoints, single-stepping, and watchpoints. Handling them might interfere with how dbx works.

These faults are taken from /sys/fault.h. fault can be any of those listed above, in uppercase or lowercase, with or without the FLT- prefix, or the actual numerical code.

lwp_exit

The lwp_exit event occurs when lwp has been exited. $lwp contains the id of the exited LWP (lightweight process).

sig sig

The sig sig event occurs when the signal is first delivered to the program being debugged. sig can be either a decimal number or the signal name in uppercase or lowercase; the prefix is optional. This is completely independent of the catch/ignore commands, although the catch command can be implemented as follows:

function simple_catch {
	 when sig $1 {
	 	 	 stop;
	 	 	 echo Stopped due to $sigstr $sig
	 	 	 whereami
	 }
}


Note – When the sig event is received, the process has not seen it yet. Only if you continue the process with the specified signal is the signal forwarded to it.

sig sig sub-code

When the specified signal with the specified sub-code is first delivered to the child, the sig sig sub-code event occurs. As with signals, you can type the sub-code as a decimal number, in uppercase or lowercase; the prefix is optional.

sysin code | name

The specified system call has just been initiated, and the process has entered kernel mode.

The concept of system call supported by dbx is that provided by traps into the kernel as enumerated in /usr/include/sys/syscall.h.

This is not the same as the ABI notion of system calls. Some ABI system calls are partially implemented in user mode and use non-ABI kernel traps. However, most of the generic system calls (the main exception being signal handling) are the same between syscall.h and the ABI.

sysout code | name

The specified system call is finished, and the process is about to return to user mode.

sysin | sysout

Without arguments, all system calls are traced. Certain dbx features, for example, the modify event and runtime checking, cause the child to execute system calls for its own purposes and show up if traced.

Execution Progress Event Specifications

The following are event specifications for events pertaining to execution progress.

next

The next event is similar to the step event except that functions are not stepped into.

returns

The returns event is a breakpoint at the return point of the current visited function. The visited function is used so that you can use the returns event specification after giving a number of step up commands. The returns event is always -temp and can only be created in the presence of a live process.

returns func

The returns func event executes each time the given function returns to its call site. This is not a temporary event. The return value is not provided, but you can find integral return values by accessing the following registers:

Sparc $o0
Intel $eax


The event is another way of saying:

when in func { stop returns; }

step

The step event occurs when the first instruction of a source line is executed. For example, you can get simple tracing with:

when step { echo $lineno: $line; }

When enabling a step event, you instruct dbx to single-step automatically next time the cont command is used. You can implement the step command as follows:

alias step="when step -temp { whereami; stop; }; cont"

Other Event Specifications

The following are event specifications for other types of events.

attach

dbx has successfully attached to a process.

detach

dbx has successfully detached from the program being debugged.

lastrites

The process being debugged is about to expire. This can happen for the following reasons:

proc_gone

The proc_gone event occurs when dbx is no longer associated with a debugged process. The predefined variable $reason may be signal, exit, kill, or detach.

prog_new

The prog_new event occurs when a new program has been loaded as a result of follow exec.


Note – Handlers for this event are always permanent.

stop

The process has stopped. The stop event occurs whenever the process stops such that the user receives a prompt, particularly in response to a stop handler. For example, the following commands are equivalent:

display x
when stop {print x;}

sync

The process being debugged has just been executed with exec(). All memory specified in a.out is valid and present, but preloaded shared libraries have not been loaded. For example, printf, although available to dbx, has not been mapped into memory.

A stop on this event is ineffective; however, you can use the sync event with the when command.

syncrtld

The syncrtld event occurs after a sync (or attach if the process being debugged has not yet processed shared libraries). It executes after the dynamic linker startup code has executed and the symbol tables of all preloaded shared libraries have been loaded, but before any code in the .init section has run.

A stop on this event is ineffective; however, you can use the syncrtld event with the when command.

throw

The throw event occurs whenever any exception that is not unhandled or unexpected is thrown by the application.

throw type

If an exception type is specified with the throw event, only exceptions of that type cause the throw event to occur.

throw -unhandled

-unhandled is a special exception type signifying an exception that is thrown but for which there is no handler.

throw -unexpected

-unexpected is a special exception type signifying an exception that does not satisfy the exception specification of the function that threw it.

timer seconds

The timer event occurs when the program being debugged has been running for seconds. The timer used with this event is shared with collector command. The resolution is in milliseconds, so a floating point value for seconds is acceptable.

Event Specification Modifiers

An event specification modifier sets additional attributes of a handler, the most common kind being event filters. Modifiers must appear after the keyword portion of an event specification. A modifier begins with a dash (-). The following are the valid event specification modifiers.

-if condition

The condition is evaluated when the event specified by the event specification occurs. The side effect of the handler is allowed only if the condition evaluates to nonzero.

If the -if modifier is used with an event that has an associated singular source location, such as in or at, condition is evaluated in the scope corresponding to that location. Otherwise, qualify it with the desired scope.

-in function

The handler is active only while within the given function or any function called from function. The number of times the function is entered is reference counted to properly deal with recursion.

-disable

The -disable modifier creates the handler in the disabled state.

-count n
-count infinity

The -count n and -count infinity modifiers have the handler count from 0 (see Using Event Counters). Each time the event occurs, the count is incremented until it reaches n. Once that happens, the handler fires and the counter is reset to zero.

Counts of all enabled handlers are reset when a program is run or rerun. More specifically, they are reset when the sync event occurs.

-temp

Creates a temporary handler. Once the event has occurred it is automatically deleted. By default, handlers are not temporary. If the handler is a counting handler, it is automatically deleted only when the count reaches 0 (zero).

Use the delete -temp command to delete all temporary handlers.

-instr

Makes the handler act at an instruction level. This event replaces the traditional 'i' suffix of most commands. It usually modifies two aspects of the event handler:

-thread thread_ID

The action is executed only if the thread that caused the event matches thread_ID.

-lwp lwp_ID

The action is executed only if the thread that caused the event matches lwp_ID.

-hidden

Hides the handler in a regular status command. Use status -h to see hidden handlers.

-perm

Normally all handlers are thrown away when a new program is loaded. Using the -perm modifier retains the handler across debuggings. A plain delete command does not delete a permanent handler. Use delete -p to delete a permanent handler.

Parsing and Ambiguity

The syntax for event specifications and modifiers is:

Expressions can have spaces embedded in them, causing ambiguous situations. For example, consider the following two commands:

when a -temp
when a-temp

In the first example, even though the application might have a variable named temp, the dbx parser resolves the event specification in favor of -temp being a modifier. In the second example, a-temp is collectively passed to a language-specific expression parser. There must be variables named a and temp or an error occurs. Use parentheses to force parsing.

Using Predefined Variables

Certain read-only ksh predefined variables are provided. The following variables are always valid:

Variable Definition
$ins Disassembly of the current instruction.
$lineno Current line number in decimal.
$vlineno Current "visiting" line number in decimal.
$line Contents of the current line.
$func Name of the current function.
$vfunc Name of the current "visiting" function.
$class Name of the class to which $func belongs.
$vclass Name of the class to which $vfunc belongs.
$file Name of the current file.
$vfile Name of the current file being visited.
$loadobj Name of the current loadable object.
$vloadobj Name of the current loadable object being visited.
$scope Scope of the current PC in back-quote notation.
$vscope Scope of the visited PC in back-quote notation.
$funcaddr Address of $func in hex.
$caller Name of the function calling $func.
$dllist After a dlopen or dlclose event, contains the list of load objects just loaded or unloaded. The first word of dllist is a "+" or a "-" depending on whether a dlopen or a dlclose has occurred.
$newhandlerid ID of the most recently created handler
$firedhandlers List of handler ids that caused the most recent stoppage. The handlers on the list are marked with "*" in the output of the status command.
$proc Process ID of the current process being debugged.
$lwp Lwp ID of the current LWP.
$thread Thread ID of the current thread.
$prog Full path name of the program being debugged.
$oprog Old, or original value of $prog. This is used to get back to what you were debugging following an exec().
$exitcode Exit status from the last run of the program. The value is an empty string if the process has not exited.


As an example, consider that whereami can be implemented as:

function whereami {
  echo Stopped in $func at line $lineno in file $(basename $file)
  echo "$lineno\t$line"
}

Variables Valid for when Command

The following variables are valid only within the body of a when command.

$handlerid

During the execution of the body, $handlerid is the id of the when command to which the body belongs. These commands are equivalent:

when X -temp { do_stuff; }
when X  { do_stuff; delete $handlerid; }

$booting

$booting is set to true if the event occurs during the boot process. Whenever a new program is debugged, it is first run without the user's knowledge so that the list and location of shared libraries can be ascertained. The process is then killed. This sequence is termed booting.

While booting is occurring, all events are still available. Use this variable to distinguish the sync and the syncrtld events occurring during a debug and the ones occurring during a normal run.

Variables Valid for Specific Events

Certain variables are valid only for specific events as shown in the following tables.

TABLE 6-1   Variables Valid for sig Event
Variable Description
$sig Signal number that caused the event
$sigstr Name of $sig
$sigcode Subcode of $sig if applicable
$sigcodestr Name of $sigcode
$sigsender Process ID of sender of the signal, if appropriate


TABLE 6-2   Variable Valid for exit Event
Variable Description
$exitcode Value of the argument passed to _exit(2) or exit(3) or the return value of main


TABLE 6-3   Variable Valid for dlopen and dlclose Events
Variable Description
$dlobj Pathname of the load object dlopened or dlclosed


TABLE 6-4   Variables Valid for sysin and sysout Events
Variable Description
$syscode System call number
$sysname System call name


TABLE 6-5   Variable Valid for proc_gone Events
Variable Description
$reason One of signal, exit, kill, or detach


Setting Event Handler Examples

The following are some examples of setting event handlers.

Setting a Watchpoint for Store to an Array Member

To set a watchpoint on array[99], type:

(dbx) stop access w &array[99]
(2) stop access w &array[99], 4
(dbx) run
Running: watch.x2
watchpoint array[99] (0x2ca88[4]) at line 22 in file "watch.c"	 
   22	 array[i] = i;

Implementing a Simple Trace

To implement a simple trace, type:

(dbx) when step { echo at line $lineno; }

Enabling a Handler While Within a Function (in function)

To enable a handler while within a function, type:

<dbx> trace step -in foo

This is equivalent to:

    # create handler in disabled state
    when step -disable { echo Stepped to $line; } 
    t=$newhandlerid    # remember handler id
    when in foo {
     # when entered foo enable the trace
     handler -enable "$t"
     # arrange so that upon returning from foo,
     # the trace is disabled.
     when returns { handler -disable "$t"; };
    }

Determining the Number of Lines Executed

To see how many lines have been executed in a small program, type:

(dbx) stop step -count infinity	  # step and stop when count=inf
(2) stop step -count 0/infinity
(dbx) run
...
(dbx) status
(2) stop step -count 133/infinity

The program never stops--the program terminates. The number of lines executed is 133. This process is very slow. It is most useful with breakpoints on functions that are called many times.

Determining the Number of Instructions Executed by a Source Line

To count how many instructions a line of code executes, type:

(dbx) ...                        # get to the line in question
(dbx) stop step -instr -count infinity
(dbx) step ...
(dbx)status
(3) stop step -count 48/infinity # 48 instructions were executed

If the line you are stepping over makes a function call, the lines in the function are counted as well. You can use the next event instead of step to count instructions, excluding called functions.

Enabling a Breakpoint After An Event Occurs

Enable a breakpoint only after another event has occurred. For example, if your program begins to execute incorrectly in function hash, but only after the 1300'th symbol lookup, you would type:

(dbx) when in lookup -count 1300 {
	 stop in hash
	 hash_bpt=$newhandlerid
	 when proc_gone -temp { delete $hash_bpt; }
}


Note – $newhandlerid is referring to the just executed stop in command.

Resetting Application Files for replay

If your application processes files that need to be reset during a replay, you can write a handler to do that each time you run the program:

(dbx) when sync { sh regen ./database; }
(dbx) run < ./database...	 # during which database gets clobbered
(dbx) save
...              # implies a RUN, which implies the SYNC event which
(dbx) restore	    # causes regen to run

Checking Program Status

To see quickly where the program is while it is running, type:

(dbx) ignore sigint
(dbx) when sig sigint { where; cancel; }

Then type ^C to see a stack trace of the program without stopping it.

This is basically what the collector hand sample mode does (and more). Use SIGQUIT (^\) to interrupt the program because ^C is now used up.

Catch Floating Point Exceptions

To catch only specific floating point exceptions, for example, IEEE underflow, type:

(dbx) ignore FPE               # turn off default handler 
(dbx) help signals | grep FPE  # can't remember the subcode name
...
(dbx) stop sig fpe FPE_FLTUND
... 


Sun Microsystems, Inc.
Copyright information. All rights reserved.
Feedback
Library   |   Contents   |   Previous   |   Next   |   Index