Sun Studio 12 Update 1:使用 dbx 调试程序

附录 B 事件管理

事件管理是指 dbx 在所调试的程序中发生事件时执行操作的能力。发生事件时,可利用 dbx 停止进程、执行任意命令或打印信息。例如,断点便是最简单的事件。另外,故障、信号、系统调用、dlopen() 调用以及数据更改(请参见 设置数据更改断点)等都是事件。

本附录由以下部分组成:

事件处理程序

事件管理是建立在处理程序概念的基础上。该名称的命名源自硬件中断处理程序。每个事件管理命令通常都会创建一个处理程序,它由事件规范和一系列副作用操作组成。(请参见设置事件规范。)事件规范指定将触发处理程序的事件。

发生事件并触发了处理程序时,处理程序会根据事件规范中包括的修饰符来评估事件。(请参见事件规范修饰符。)如果事件满足修饰符施加的条件,则将执行处理程序的副作用操作(即处理程序“触发”)。

在特定行设置断点便是一个将程序事件与 dbx 操作关联的示例。

最普通的创建处理程序的方式是使用 when 命令。


when event-specification {action; ... }

本章中的示例说明如何使用 when 语句编写命令(如 stopstepignore)。这些示例的目的在于说明 when 命令与底层处理程序机制的灵活性,但实际应用中并不一定要严格遵循这些示例。

事件安全

尽管 dbx 向您提供了通过事件机制实现的一组丰富的断点类型,但它还会在内部使用许多事件。通过在发生其中一些内部事件时停止,可以很容易地中止 dbx 的内部操作。 如果在这些情况下修改进程状态,中止的可能性会更高。请参见附录 A调用安全性

dbx 可以保护自身在某些情况下(但不是所有情况下)中止操作。一些事件按照低级别事件来实现。例如,所有步进操作都是基于 fault FLTTRACE 事件。因此,发出 stop fault FLTTRACE 命令会中止步进操作。

在以下调试阶段,dbx 不能处理用户事件,因为这些事件会干扰某些需要非常谨慎的内部协调操作。这些阶段包括:

在许多情况下,可以使用 when 命令而非 stop 命令,以及回显以其他方式交互获得的信息。

dbx 通过以下方式保护自身:

例如:...stopped in munmap at 0xff3d503c 0xff3d503c: munmap+0x0004: ta %icc,0x00000008 dbx76: warning: 'stop' ignored -- while doing rtld handshake

仅忽略中断作用(包括 $firedhandlers 变量中的记录)。计数器或过滤器仍发挥作用。要在这种情况下停止,请将环境变量 event_safety 设置为 off

创建事件处理程序

使用 when 命令、stop 命令和 trace 命令创建事件处理程序。(有关详细信息,请参见when 命令stop 命令trace 命令。)

stop 是常见术语 when 的简略表达方式。


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

事件规范由事件管理命令 stopwhentrace 用于指定相关事件。(请参见设置事件规范。)

大多数 trace 命令都可以使用 when 命令、ksh 功能和事件变量来手动创建。 在需要特定格式的跟踪输出时,这特别有用。

每个命令都返回一个称为处理程序 ID (hid) 的编号。可以使用预定义变量 $newhandlerid 访问此编号。

操作事件处理程序

可以使用下列命令操作事件处理程序。有关各命令的更多信息,请参见说明的相应一节。

使用事件计数器

每个事件处理程序都有一个行程计数器,计数器有计数限制。每当发生指定事件时,计数器的计数便会增加。只有当计数达到计数限制时,才会执行与处理程序关联的操作,此时计数器自动重置为 0。缺省限制为 1。每当重新运行进程时,所有事件计数器都会重置。

可以将 -count 修饰符与 stop 命令、when 命令或 trace 命令结合使用来设置计数限制(请参见-count n -count infinity)。另外也可以使用 handler 命令单独操作事件处理程序。


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

设置事件规范

stop 命令、stopi 命令、when 命令、wheni 命令、trace 命令以及 tracei 命令使用事件规范来指示事件类型和参数。格式由表示事件类型的关键字和可选参数构成。通常,对于这三个命令而言,事件规范的含义相同;例外情况在命令说明中进行了介绍(请参见stop 命令trace 命令when 命令)。

断点事件规范

断点是操作的发生位置,程序在该位置停止执行。下面是断点事件的事件规范。

in function

已进入函数,并且即将执行第一行。序进程后的第一个可执行代码用作实际断点位置。它可能是要初始化的局部变量所在的那一行。如果是 C++ 构造函数,在执行了所有基类构造函数后,将停止执行。如果使用 -instr 修饰符(请参见-instr),则它是即将执行的函数的第一个指令。function 规范可以接受形式参数签名,以支持重载的函数名或模板实例规范。例如:


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

注 –

不要将 in function-in function 修饰符混淆。


at [filename: ]line_number

指定行即将被执行。如果指定 filename,则即将执行指定文件中的指定行。文件名可以是源文件名或目标文件名。尽管不要求使用引号,但文件名中包含特殊字符时需要使用。如果指定行在模板代码中,则会在该模板的所有实例上放置断点。

at address_expression

给定地址处的指令即将被执行。此事件只能与 stopi 命令(请参见stopi 命令)或 -instr 事件修饰符(请参见-instr)结合使用。

infile filename

该事件在文件中定义的每个函数中放置断点。stop infile 命令循环访问与 funcs -f filename 命令相同的函数列表。

.h 文件中的方法定义、模板文件或 .h 文件中的纯 C 代码(如 regexp 命令使用的那种)可能会为文件提供函数定义,但这些定义会被排除。

如果指定的文件名是目标文件的名称(即,该文件名以 .o 结尾),则会在出现在该目标文件中的每个函数上放置断点。

stop infile list.h 命令不会在 list.h 文件中定义的所有方法实例中放置断点。请使用诸如 inclassinmethod 之类的事件来执行此操作。

fix 命令可以删除文件中的函数或向文件中添加函数。stop infile 命令可在文件中的所有旧版本函数中,以及未来可能添加的任何函数中放置断点。

不会在 Fortran 文件的嵌套函数或子例程中放置断点。

您可以使用 clear 命令禁用 infile 事件创建的集合中的单个断点。

infunction function

对于所有名为 function 的重载函数或其所有模板实例,等效于 in function

inmember function inmethod function

对于每个类,等效于 in function 或名为 function 的成员函数。

inclass classname [-recurse | -norecurse]

对于所有是 classname 的成员但不是 classname 的任何基类的成员函数,等效于 in function-norecurse 是缺省值。如果指定 -recurse,则包括基类。

inobject object-expression [-recurse | -norecurse]

调用了对由 object-expression 表示的地址处的特定对象调用的成员函数。stop inobject ox 大致等效于以下命令,但与 inclass 不同,此处,包括了动态类型的 ox 的基类。缺省值是 -recurse。如果指定 -norecurse,则不包括基类。


stop inclass dynamic_type(ox) -if this==ox

数据更改事件规范

以下是涉及访问或更改内存地址内容的事件的事件规范。

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

访问了由 address-expression 指定的内存。

mode 指定内存访问模式。可由以下一个或所有字母组成:

r

已读取指定地址处的内存。

w

已写入内存。

x

已执行内存。

mode 还可以包含以下任一项:

a

访问后停止进程(缺省值)。

b

访问前停止进程。

在这两种情况下,程序计数器都将指向违例指令。“之前”和“之后”都具有副作用。

address-expression 是求值结果为地址的任何表达式。如果提供符号表达式,则会自动推导出要监视的区域大小;可以通过指定 byte-size-expression 将其覆盖。也可以使用非符号、无类型地址表达式,在这种情况下,必须提供大小。例如:


stop access w 0x5678, sizeof(Complex)

access 命令有一个限制,即任何两个匹配区都不能重叠。


注 –

access 事件规范取代了 modify 事件规范


change variable

variable 的值已更改。change 事件大致等效于:


when step { if [ $last_value !=$[variable]] then
                 stop
            else
                 last_value=$[variable]
          }

此事件使用单步执行来执行。要提高速度,可使用 access 事件(请参见access mode address-expression [, byte-size-expression ])。

即使未检测到更改,第一次检查 variable 时也会触发一个事件。这第一个事件是访问 variable 的初始值。以后检测到 variable 值的更改时会触发其他事件。

cond condition-expression

condition-expression 表示的条件的求值结果为 true。可以为 condition-expression 指定任何表达式,但其求值结果必须为整型。cond 事件大致等效于:

stop step -if conditional_expression

系统事件规范

以下是系统事件的事件规范。

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

成功执行 dlopen()() 或 dlclose()() 调用后会发生这些事件。执行 dlopen()() 或 dlclose()() 调用可能会导致装入多个库。预定义变量 $dllist 中总是有这些库的列表。$dllist 中的第一个 shell 字为 "+" 或 "-",表示是要添加还是要删除库列表。

lib-path 是共享库的名称。如果指定该名称,则只在装入或卸载了给定库时才会发生事件。在这种情况下,$dlobj 包含库的名称。$dllist 仍然可用。

如果 lib-path/ 开头,则将执行完整字符串匹配。否则,将只比较路径的尾部。

如果未指定 lib-path,则只要出现 dl 活动,都会发生事件。在这种情况下,$dlobj 为空,但 $dllist 有效。

fault fault

当出现指定的错误时,就会发生 fault 事件。这些错误为体系结构相关式错误。以下这组 dbx 已知的错误在 proc(4) 手册页中进行了定义。

错误  

说明  

FLTILL

非法指令 

FLTPRIV

特权指令 

FLTBPT*

断点陷阱 

FLTTRACE*

跟踪陷阱(单步) 

FLTACCESS

内存访问(如对齐) 

FLTBOUNDS

内存边界(无效地址) 

FLTIOVF

整数溢出 

FLTIZDIV

整数除以零 

FLTPE

浮点异常 

FLTSTACK

无法恢复的栈错误 

FLTPAGE

可恢复的页错误 

FLTWATCH*

监视点陷阱 

FLTCPCOVF

CPU 性能计数器溢出 


注 –

dbx 使用 BPTTRACEBOUNDS 来实现断点和单步执行。处理它们时可能会干扰 dbx 的运行情况。



注 –

FLTBPTFLTTRACE 会被忽略,因为它们会干扰诸如断点和单步执行等 dbx 基本功能(请参见事件安全)。


上述错误摘自 /sys/fault.hfault 可以是上面所列错误中的任何一种(大小写、有无 FLT 前缀均可),也可以是实际的数字代码。


注 –

在 Linux 平台上不能使用 fault 事件。


lwp_exit

退出了 lwp 时,会发生 lwp_exit 事件。$lwp 包含事件处理程序执行期间退出的 LWP(lightweight process,轻量级进程)的 ID。


注 –

在 Linux 平台上不能使用 lwpexit 事件。


sig signal

信号首次传送给所调试的程序时,会发生 sig signal 事件。signal 可以是十进制数或信号名(大小写均可),前缀是可选的。它与 catch 命令和 ignore 命令毫无关系,尽管 catch 命令可按如下方式实现:


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

注 –

收到 sig 事件时,进程尚未检测到它。只有在使用指定的信号继续执行进程时,信号才会传送给它。


sig signal sub-code

首次将具有指定 sub-code 的指定信号传送到子进程时,会发生 sig signal sub-code 事件。与信号相同,可以按十进制数形式或大小写字母形式键入 sub-code,前缀是可选的。

sysin code | name

刚启动了指定的系统调用,且进程已进入内核模式。

dbx 支持的系统调用概念是由陷阱按 /usr/include/sys/syscall.h 中的枚举提供内核系统调用。

这与系统调用的 ABI 概念不同。一些 ABI 系统调用在用户模式下得到部分实现,并且使用非 ABI 内核陷阱。但是,对于大多数普通系统调用(主要异常是信号处理),syscall.h 和 ABI 之间没有区别。


注 –

在 Linux 平台上不能使用 sysin 事件。



注 –

/usr/include/sys/syscall.h 中的一组内核系统调用陷阱属于 Solaris OS 中随发行版本而异的一个专用接口。dbx 接受的陷阱名(代码)和陷阱编号列表包括 dbx 支持的任何 Solaris OS 版本支持的所有陷阱名(代码)和陷阱编号。dbx 支持的名称不太可能与任何 Solaris OS 特定发行版本支持的名称完全一致,而且 syscall.h 中的某些名称可能不可用。任何陷阱编号(代码)均可为 dbx 接受,并可正常使用,但是,如果它与已知的系统调用陷阱不对应,系统会发出警告。


sysout code | name

已完成指定的系统调用,进程即将返回到用户模式。


注 –

在 Linux 平台上不能使用 sysout 事件。


sysin | sysout

如果不使用参数,所有系统调用都会被跟踪。某些 dbx 功能(例如 modify 事件和运行时检查)会导致子进程为其自身目的执行系统调用,并且在被跟踪时显示出来。

执行进度事件规范

以下是与执行进度有关的事件的事件规范。

exit exitcode

退出了进程时,会发生 exit 事件。

next

next 事件与 step 事件类似,不同之处在于并不步入函数。

returns

returns 事件是当前访问的函数的返回点处的断点。使用访问的函数是为了可以在提供大量 step up 命令后使用 returns 事件规范。returns 事件始终为 -temp,并且只有当存在活动进程时才能创建该事件。

returns function

每当给定的函数返回到其调用点时,都会执行 returns function 事件。这不是临时事件。执行此操作时,并不提供返回值,但可以访问以下寄存器查找整型返回值:

基于 SPARC 的系统

$o0

基于 x86 的系统

$eax

基于 x64 的系统

$rax$rdx

该事件大致等效于:


when in func { stop returns; }

step

执行源代码的第一个指令时,会发生 step 事件。例如,可以使用以下语句获得简单跟踪:


when step { echo $lineno: $line; }; cont

启用了 step 事件后,即指示 dbx 在下次使用 cont 命令时自动单步执行。


注 –

step 命令终止时,不会发生 step(和 next)事件。step 命令是按照 step 事件实现的,实现方式大致如下: alias step="when step -temp { whereami; stop; }; cont"


其他事件规范

以下是其他类型事件的事件规范。

attach

dbx 已成功连接到进程。

detach

dbx 已成功与所调试的程序分离。

lastrites

所调试的进程即将过期,原因如下:

触发此事件时,通常(但并非总是)会有进程的最终状态,从而提供了检查进程状态的最后机会。在此事件后恢复执行会终止进程。


注 –

在 Linux 平台上不能使用 lastrites 事件。


proc_gone

dbx 不再与调试的进程关联时,会发生 proc_gone 事件。预定义变量 $reason 可以是 signalexitkilldetach

prog_new

由于执行 follow exec 而装入了新程序时,会发生 prog_new 事件。


注 –

此事件的处理程序始终永久性存在。


stop

进程已停止。每当进程停止以便用户收到提示(尤其是为了响应 stop 处理程序)时,都会发生 stop 事件。例如,以下命令是等效的:


display x
when stop {print x;}

sync

刚使用 exec() 执行了所调试的进程。在 a.out 中指定的所有内存均有效且存在,但预装入的共享库尚未装入。例如,尽管 printf 可供 dbx 使用,但尚未映射到内存中。

对此事件执行 stop 不起作用,但可以将 sync 事件与 when 命令一起使用。


注 –

在 Linux 平台上不能使用 sync 事件。


syncrtld

在执行 sync(或 attach,如果所调试的进程尚未处理共享库)后,会发生 syncrtld 事件。它在动态链接程序启动代码已经执行且所有预装入共享库的符号表都已装入之后、.init 段中的任何代码运行之前执行。

针对此事件执行 stop 不起作用,但可以将 syncrtld 事件与 when 命令一起使用。

thr_create [thread_id ]

创建了线程或具有指定 thread_id 的线程后,会发生 thr_create 事件。例如,在以下 stop 命令中,线程 ID t@1 是指执行创建线程,而线程 ID t@5 是指被创建线程。


stop thr_create t@5 -thread t@1

thr_exit

线程退出后,会发生 thr_exit 事件。要捕获特定线程的退出,请使用 stop 命令的 -thread 选项,如下所示:


stop thr_exit -thread t@5

throw

每当应用程序抛出任何不是未处理的异常或意外的异常时,都会发生 throw 事件。


注 –

在 Linux 平台上不能使用 throw 事件。


throw type

如果为 throw 事件指定了异常 type,则只有该类型的异常会导致发生 throw 事件。

throw -unhandled

-unhandled 是一种特殊的异常类型,表示会抛出但没有相应处理程序的异常。

throw -unexpected

-unexpected 是一种特殊的异常类型,表示该异常不符合抛出它的函数的异常规范。

timer seconds

所调试的程序运行了 seconds 时,会发生 timer 事件。 用于此事件的计时器与 collector 命令共享。精度为毫秒,因此,seconds 可以为浮点值(例如 0.001)。

事件规范修饰符

事件规范修饰符设置处理程序的其他属性,最常见的一种是事件过滤器。修饰符必须位于事件规范的关键字部分之后。修饰符以短划线 (-) 开头。以下是有效的事件规范修饰符。

-if condition

发生事件规范指定的事件时,便会对条件进行求值。仅当条件的求值结果为非零时,处理程序才会出现副作用。

如果 -if 修饰符用于具有关联的单一源位置(如 inat)的事件,则在与该位置对应的作用域对 condition 进行求值。否则,请使用所需作用域来限定它。

-resumeone

-resumeone 修饰符可以与 -if 修饰符一起用于多线程程序的事件规范中,这样,条件中包含函数调用时,只恢复一个线程。有关更多信息,请参见将过滤器与条件事件配合使用

-in function

该事件只会发生在到达给定 function 的第一个指令与该函数返回之间。函数的递归会被忽略。

-disable

-disable 修饰符用于创建处于禁用状态的处理程序。

-count n -count infinity

-count n-count infinity 修饰符用于使处理程序从 0 开始计数(请参见使用事件计数器)。每次发生事件时,计数便会增加,直至达到 n。达到 n 后,处理程序便会启动,且计数器重置为零。

程序运行或重新运行时,所有启用的处理程序的计数都会被重置。更确切地讲,就是在发生 sync 事件时重置计数。

在使用 debug -r 命令(请参见debug 命令)或 attach -r 命令(请参见attach 命令)开始调试新程序时会重置计数。

-temp

创建临时处理程序。发生事件后,会立即自动将其删除。缺省情况下,处理程序不是临时性的。如果处理程序是计数处理程序,则只有在计数达到 0(零)时,才会自动将其删除。

可使用 delete -temp 命令删除所有临时处理程序。

-instr

使处理程序在指令级操作。此事件取代了大多数命令的传统后缀 "i"。它通常修改事件处理程序的下列两个方面:

-thread thread_id

只有导致发生事件的线程与 thread_id 相符时,才会执行该操作。对于您考虑的特定线程,在程序的不同次执行中可能分配不同的 thread_id

-lwp lwp_id

只有在导致事件的线程与 lwp_id 相符时,才会执行该操作。只有在导致事件的线程与 lwp_id 相符时,才会执行该操作。对于您考虑的特定线程,在程序的不同次执行中可能分配不同的 lwp_id

-hidden

在常规 status 命令中隐藏处理程序。可使用 status -h 查看隐藏的处理程序。

-perm

正常情况下,装入新程序时,所有处理程序都会被抛弃。使用 -perm 修饰符可在多个调试会话中保留处理程序。不带参数的 delete 命令不会删除永久性处理程序。可使用 delete -p 删除永久性处理程序。

分析和二义性

事件规范和修饰符的语法如下:

表达式可能会有内嵌空格,这便会导致不明确情况发生。例如,假设有以下两个命令:


when a -temp
when a-temp

在第一个示例中,尽管应用程序可能有一个名为 temp 的变量,但 dbx 解析器仍会优先将 -temp 作为修饰符来解析事件规范。在第二个示例中,a-temp 作为整体传递给语言特定的表达式解析器。必须存在名为 atemp 的变量,否则就会发生错误。可使用括号强制解析。

使用预定义变量

有一些只读的 ksh 预定义变量。以下变量始终有效:

变量  

定义  

$ins

反汇编当前指令。 

$lineno

以十进制数表示的当前行号。 

$vlineno

以十进制数表示的当前“访问”行号。 

$line

当前行的内容。 

$func

当前函数名。 

$vfunc

当前“访问”函数的名称。 

$class

$func 所属类的名称。

$vclass

$vfunc 所属类的名称。

$file

当前文件名。 

$vfile

被访问的当前文件的名称。 

$loadobj

当前可装入对象的名称。 

$vloadobj

被访问的当前可装入对象的名称。 

$scope

当前 PC 在反引用符号中的作用域。 

$vscope

被访问 PC 在反引用符号中的作用域。 

$funcaddr

以十六进制数表示的 $func 地址。

$caller

调用 $func 的函数的名称。

$dllist

在发生 dlopendlclose 事件后,包含刚装入或卸载的装入对象的列表。dllist 的第一个字符根据发生的是 dlopen 还是 dlclose 为 "+" 或 "-"。

$newhandlerid

最近创建的处理程序的 ID。在任何删除处理程序的命令后,此变量有一个未定义的值。创建处理程序后立即使用该变量。dbx 不能针对创建多个处理程序的命令捕获所有处理程序 ID。

$firedhandlers

导致最近中断的处理程序 ID 列表。在 status 命令的输出中,该列表中的处理程序都标记有 "*"。

$proc

正被调试的当前进程的“进程 ID”。 

$lwp

当前 LWP 的 Lwp ID。 

$thread

当前线程的“线程 ID”。 

$newlwp

新建的 LWP 的 lwp ID。 

$newthread

新建线程的线程 ID。 

$prog

正被调试程序的完整路径名。 

$oprog

$prog 恢复为 "-" 时的上一个 $prog 值,用于在执行 exec() 后返回到以前调试的内容。$prog 扩展为完整路径名时,$oprog 包含命令行中指定的程序路径或指定给 debug 命令的程序路径。如果调用 exec() 多次,则无法返回到原始程序。

$exec32

如果 dbx 二进制数为 32 位,则为 True。

$exitcode

最后运行程序的退出状态。如果进程尚未退出,则该值为空字符串。 

$booting

如果在“引导”过程中发生事件,则会设置为 true。每当调试新程序时,它会先引导以便可以确定共享库的列表和位置。然后,进程将被中止。这一序列被称为引导。

引导过程中,所有事件仍然可用。例如,使用此变量来区分在调试运行期间发生的 syncsyncrtld 事件以及在正常运行期间发生的这些事件。

例如,可以这样实现 whereami


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

when 命令有效的变量

以下变量仅在 when 命令的主体中有效。

$handlerid

在执行主体过程中,$handlerid 是主体所属 when 命令的 ID。下列命令是等价的:


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

when 命令和特定事件有效的变量

某些变量仅在 when 命令主体中以及对于下表中所示的特定事件有效。

表 B–1 对 sig 事件有效的变量

变量  

说明  

$sig

触发事件的信号数 

$sigstr

$sig 的名称

$sigcode

$sig 的子代码(如果适用)

$sigcodestr

$sigcode 的名称

$sigsender

信号发出方的进程 ID(如果适用) 

表 B–2 对 exit 事件有效的变量

变量  

说明  

$exitcode

传递给 _exit(2)exit(3) 的参数的值或 main 的返回值

表 B–3 对 dlopendlclose 事件有效的变量

变量 

说明 

$dlobj

装入对象 dlopened 或 dlclosed 的路径名 

表 B–4 对 sysinsysout 事件有效的变量

变量 

说明 

$syscode

系统调用号 

$sysname

系统调用名 

表 B–5 对 proc_gone 事件有效的变量

变量 

说明 

$reason

signal、exit、kill 或 detach 之一 

表 B–6 对 thr_create 事件有效的变量

变量 

说明 

$newthread

新建线程的 ID(例如 t@5

$newlwp

新建 LWP 的 ID(例如 l@4

表 B–7 对 watch 事件有效的变量

变量 

说明 

$watchaddr

正在写入、读取或执行的地址 

$watchmode

以下项之一:r 代表读取,w 代表写入,x 代表执行;后跟以下项之一:a 代表之后,b 代表之前 

事件处理程序示例

以下是设置事件处理程序的一些示例。

为存储到数组成员设置断点

要在 array[99] 设置数据更改断点,请键入:


(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;

执行简单跟踪

要实现简单跟踪,请键入:


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

在函数内时启用处理程序 (in function)

要在函数内时启用处理程序,请键入:


<dbx> trace step -in foo

它等效于:


    # 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"; };
    }

确定已执行的行数

要了解在小程序中已执行了多少行,请键入:


(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

程序永远不会停止,程序只会终止。执行的行数为 133。此进程速度非常慢。它对多次调用的函数中的断点用处最大。

确定源代码行执行的指令数

要计算一行代码执行了多少个指令,请键入:


(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

如果步过的行进行函数调用,则该函数中的行也计入在内。可以使用 next 事件而非 step 计算指令数(不包括被调用函数)。

事件发生后启用断点

只在另一事件发生后启用断点。例如,如果程序的执行在函数 hash 中开始不正常,但只是发生在第 1300 次符号查找后,可键入:


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

注 –

$newhandlerid 是指刚执行的 stop in 命令。


重放重置应用程序文件

如果应用程序处理需要在 replay 期间重置的文件,可以编写一个处理程序,在每次运行程序时执行该操作:


(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

检查程序状态

要快速查看程序运行时的位置,请键入:


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

然后键入 ^C 在不停止程序的情况下查看程序的栈跟踪。

这基本上是收集器人工示例模式的任务(还有更多)。可使用 SIGQUIT (^\)^C 已用尽的情况下中断程序。

捕获浮点异常

要只捕获特定的浮点异常(例如 IEEE 下溢),请键入:


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