Oracle® Solaris Studio 12.4:使用 dbx 调试程序

退出打印视图

更新时间: 2015 年 1 月
 
 

事件管理

事件管理是指 dbx 在所调试的程序中发生事件时执行操作的能力。

事件处理程序

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

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

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

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

when event-specification {action; ... }

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

创建事件处理程序

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

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

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

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

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

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

操作事件处理程序

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

表 B-1  操作事件处理程序
命令
说明
有关更多信息
status
列出处理程序
请参见status 命令
delete
删除所有处理程序,其中包括临时处理程序
请参见delete 命令
clear
根据断点位置删除处理程序
请参见clear 命令
handler –enable
启用处理程序
handler –disable
禁用处理程序
cancel
取消信号并启用该流程以继续
请参见cancel 命令

使用事件计数器

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

您可以随 stop 命令、when 命令或 trace 命令使用 –count 修饰符来设置计数限制。另外也可以使用 handler 命令单独操作事件处理程序。

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

事件安全

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

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

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

  • 程序启动时rtld 运行阶段(请参见动态链接程序

  • 进程开始和结束阶段

  • 跟随 fork() 函数和 exec() 函数(请参见跟随 fork 函数跟随 exec 函数

  • dbx 需要在用户进程中初始化头文件 (proc_heap_init()) 的调用期间

  • dbx 需要确保堆栈上映射页的可用性 (ensure_stack_memory()) 的调用期间

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

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

  • 禁止对 syncsyncrtldprog_new 事件使用 stop 命令

  • rtld 握手期间和上面提到的其他阶段中,忽略 stop 命令

例如:

...SolBook linebreakstopped in munmap at 0xff3d503c 0xff3d503c: munmap+0x0004: ta %icc,0x00000008SolBook linebreak dbx76: warning: 'stop' ignored -- while doing rtld handshake

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

设置事件规范

stop 命令、stopi 命令、when 命令、wheni 命令、trace 命令和 tracei 命令使用事件规范表示事件类型和参数。此格式由一个表示事件类型和可选参数的关键字组成。 对于所有三种命令,事件规范的含义通常相同。在附录 D 的命令说明中介绍了各种异常。

断点事件规范

断点是操作的发生位置,程序在该位置停止执行。本节介绍了断点事件的事件规范。

in 事件规范

in 事件规范的语法如下:

infunction

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

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

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

at 事件规范

at 事件规范的语法如下:

at[filename:]line-number

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

您还可以使用指定特定地址:

ataddress-expression

给定地址处的指令即将被执行。此事件仅可与 stopi 命令或 –instr 事件修饰符结合使用

infile 事件规范

infile 事件规范的语法如下:

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 事件规范

infunction 事件规范的语法如下:

infunctionfunction

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

inmember 事件规范

inmember 事件规范的语法如下:

inmember function

此规范是 inmethod 事件规范的别名。

inmethod 事件规范

inmember 事件规范的语法如下:

inmethod function

此规范等效于 in function 或每个类命名为 function 的成员方法。

inclass 事件规范

inclass 事件规范的语法如下:

inmember classname [-recurse | -norecurse]

对于所有属于 classname 成员、但并非任何 classname 基础的成员函数,此规范等效于 in function–norecurse 为缺省值。如果指定 –recurse,则包括基类。

inobject 事件规范

inobject 事件规范的语法如下:

inobject object-expression [-recurse | -norecurse]

已调用针对 object-expression 表示的地址中的特定对象所调用的成员函数。stop inobject ox 大致等效于以下内容,但与 inclass 不同,它包括 ox 的动态类型基础。–recurse 为缺省值。 如果指定 –norecurse,则不包括基类。

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

数据更改事件规范

本节介绍了涉及访问或更改内存地址内容的事件的事件规范。

access 事件规范

access 事件规范的语法如下:

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 事件规范

change 事件规范的语法如下:

change variable

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

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

此事件使用单步执行来执行。要提高速度,可使用 access 事件。

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

cond 事件规范

cond 事件规范的语法如下:

cond condition-expression

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

stop step -if conditional-expression

系统事件规范

本节介绍了系统事件的事件规范。

dlopendlclose 事件规范

dlopen()dlopen() 事件规范的语法如下:

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 fault

遇到指定的故障时,会发生 fault 事件。 这些错误为体系结构相关式错误。dbx 的已知故障集在以下列表中列出,且在 proc(4) 手册页中已定义。

FLTILL

非法指令

FLTPRIV

特权指令

FLTBPT*

断点陷阱

FLTTRACE*

跟踪陷阱(单步)

FLTACCESS

内存访问(如对齐)

FLTACCESS

内存访问(如对齐)

FLTBOUNDS

内存边界(无效地址)

FLTIOVF

整数溢出

FLTIZDIV

整数除以零

FLTPE

浮点异常

FLTSTACK

无法恢复的堆栈错误

FLTPAGE

可恢复的缺页

FLTWATCH*

监视点陷阱

FLTCPCOVF

CPU 性能计数器溢出


注 -  FLTBPTFLTTRACEFLTWATCH 未处理,因为它们已由 dbx 用来实现断点、单步步入和监视点。

这些故障摘自 /sys/fault.hfault 可以是以上列出的任意错误(不区分大小写,无论含或不含 FLT- 前缀),也可以是实际的数字代码。


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

lwp_exit 事件规范

lwp_exit 事件规范的语法如下:

lwp_exit

退出 lwp 时,会发生 lwp_exit 事件。对于事件处理程序的持续时间,$lwp 包含退出的 LWP(轻量级进程)的 ID。


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

sig 事件规范

sig 事件规范的语法如下:

sigsignal

信号第一次传递给调试的程序时,会发生 sig signal 事件。signal 既可以是十进制数,也可以是大写或小写的信号名称。 前缀是可选的。尽管 catch 命令可按如下所示实现,但此事件完全独立于 catch 命令和 ignore 命令:

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

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

或者,您可以使用子代码指定信号。sig 事件规范的此选项的语法如下:

sigsignal sub-code

首次将具有指定 sub-code 的指定信号传送到子进程时,会发生 sig signal sub-code 事件。对于信号,您可以十进制数、大写或小写字母的形式提供 sub-code。前缀是可选的。

sysin 事件规范

sysin 事件规范的语法如下:

sysincode|name

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

dbx 支持的系统调用概念,是指由进入内核(/usr/include/sys/syscall.h 中所枚举)中的陷阱所提供的概念。

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


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

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

sysout 事件规范

sysout 事件规范的语法如下:

sysoutcode|name

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


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

sysin | sysout 事件规范

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

执行进度事件规范

本节介绍了有关于执行进度的事件的事件规范。

exit 事件规范

exit 事件规范的语法如下:

exitexitcode

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

next 事件规范

next 事件类似于 step 事件,除了函数尚未步入以外。

returns 事件规范

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

returns 事件规范的语法如下:

returnsfunction

每当给定的函数返回到其调用点时,都会执行 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"

throw 事件规范

throw 事件的语法如下:

throw [type | –unhandled | –unexpected]

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

如果异常类型使用 throw 事件指定,则只有该类型的异常才会导致 throw 事件的发生。

如果指定了 –unhandled 选项,则对于没有处理程序的情况,系统将抛出特殊异常类型,表明出现异常。

指定了 –unexpected 选项,该选项是一种特殊的异常类型,表示异常不符合抛出它的函数的异常规范。

跟踪线程事件规范

下面这一节介绍跟踪线程的事件规范。

omp_barrier 事件规范

当跟踪线程进入或退出屏障时,会涉及 omp_barrier 事件规范。您可以指定 type(它可以是 explicitimplicit)和 state(它可以是 enterexitall_entered)。缺省值为 explicit all_entered

omp_taskwait 事件规范

当跟踪线程进入或退出任务等待时,会涉及 omp_taskwait 事件规范。您可以指定 state(它可以是 enterexit)。缺省值为 exit

omp_ordered 事件规范

当跟踪线程进入或退出有序区域时,会涉及 omp_ordered 事件规范。您可以指定 state(它可以是 beginenterexit)。缺省值为 enter

omp_critical 事件规范

当跟踪线程进入重要区域时,会涉及 omp_critical 事件规范。

omp_atomic 事件规范

当跟踪线程进入或退出原子区域时,会涉及 omp_atomic 事件规范。您可以指定 state(它可以是 beginexit)。缺省值为 begin

omp_flush 事件规范

当跟踪线程进入显式刷新区域时,会涉及 omp_flush 事件规范。

omp_task 事件规范

当跟踪线程进入或退出任务区域时,会涉及 omp_task 事件规范。您可以指定 state(它可以是 createstartfinish)。缺省值为 start

omp_master 事件规范

当跟踪线程进入主要区域时,会涉及 omp_master 事件规范。

omp_single 事件规范

当跟踪线程进入单个区域时,会涉及 omp_single 事件规范。

其他事件规范

本节介绍了其他类型事件的事件规范。

attach 事件规范

attach 事件是 dbx 成功连接到进程。

detach 事件规范

detach 事件是 dbx 成功与所调试的程序分离。

lastrites 事件规范

    lastrites 事件是所调试的进程即将过期,原因可能如下:

  • _exit(2) 系统调用已通过显式调用发生,或在 main() 返回时发生。

  • 即将传送终止信号。

  • 进程正由 kill 命令中止。

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


注 -  在 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() 执行时,会发生 sync 事件。在 a.out 中指定的所有内存均有效且存在,但预装入的共享库尚未装入。例如,尽管 printf 可供 dbx 使用,但尚未映射到内存中。

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


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

syncrtld 事件规范

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

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

thr_create [thread-ID] 事件规范

创建线程或具有指定线程 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

timer 事件规范

timer 事件的语法如下:

timerseconds

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

事件规范修饰符

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

-if 修饰符

-if 修饰符的语法为:

-ifcondition

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

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

根据与 print 命令相同的约定对条件执行宏扩展。

-resumeone 修饰符

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

-in 修饰符

-in 修饰符的语法为:

-infunction

仅当事件在达到给定函数的第一个指令之后、函数返回之前的这段时间发生时,才会触发事件。函数的递归会被忽略。

-disable 修饰符

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

-count n-count infinity 修饰符

-count 修饰符的语法为:

-countn

-count infinity

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

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

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

-temp 修饰符

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

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

-instr 修饰符

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

  • 任何消息均输出汇编级信息,而非源代码级信息。

  • 事件的粒度变为指令级。例如,step –instr 意味着指令级单步执行。

-thread 修饰符

-thread 修饰符的语法为:

-threadthread-ID

-thread 修饰符意味着只有在导致事件的线程与另一个线程 ID 相符时,才会执行该操作。对于您考虑的特定线程,在程序的不同次执行中可能分配不同的线程 ID。

-lwp 修饰符

-lwp 修饰符的语法为:

-lwplwp-ID

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

-hidden 修饰符

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

-perm 修饰符

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

解析和二义性

事件规范和修饰符的语法由关键字驱动,且以 ksh 约定为基础。所有内容均拆分为用空格分隔的单词。

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

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 的第一个字是 + (加号)或 - (减号),具体取决于是否已发生 dlopendlclose
$newhandlerid
最近创建的处理程序的 ID。在任何删除处理程序的命令后,此变量有一个未定义的值。创建处理程序后立即使用该变量。dbx 不能针对创建多个处理程序的命令捕获所有处理程序 ID。
$firedhandlers
导致最近中断的处理程序 ID 列表。在 status 命令的输出中,该列表中的处理程序都标记有 *(星号)。
$proc
正被调试的当前进程的“进程 ID”。
$lwp
当前 LWP 的 ID。
$thread
当前线程的“线程 ID”。
$newlwp
新建 LWP 的 ID。
$newthread
新建线程的 ID。
$prog
正被调试程序的全路径名。
$oprog
$prog 的上一个值,当程序的全路径名恢复为 - (短划线)时,使用此值返回您在 exec() 之后调试的内容。$prog 扩展为全路径名时,$oprog 包含命令行中指定的程序路径或指定给 debug 命令的程序路径。如果调用 exec() 多次,则无法返回到原始程序。
$exec32
如果 dbx 二进制数为 32 位,则为 True。
$exitcode
最后运行程序的退出状态。如果进程尚未退出,则该值为空字符串。
$booting
如果在引导过程中发生事件,则会设置为 true。每当调试新程序时,它会先引导以便可以确定共享库的列表和位置。然后,进程将被中止。这一序列被称为“引导”。
引导过程中,所有事件仍然可用。例如,使用此变量来区分在调试运行期间发生的 syncsyncrtld 事件以及在正常运行期间发生的这些事件。
$machtype
如果已装入程序,则返回计算机类型:sparcv8sparcv8+sparcv9intel。否则,返回 unknown
$datamodel
如果已装入程序,则返回数据模型:ilp32lp64。否则,返回 unknown。要查找刚才装入的程序模型,请使用 .dbxrc 文件中的以下内容:
when prog_new -perm {
     echo machine: $machtype $datamodel;
} 

以下示例说明可以实现 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-2  sig 事件有效的变量
变量
说明
$sig
触发事件的信号数
$sigstr
$sig 的名称
$sigcode
$sig 的子代码(如果适用)
$sigcodestr
$sigcode 的名称
$sigsender
信号发出方的进程 ID(如果适用)
表 B-3  exit 事件有效的变量
变量
说明
$exitcode
传递给 _exit(2)exit(3) 的参数的值或 main 的返回值
表 B-4  dlopendlclose 事件有效的变量
变量
说明
$dlobj
装入对象 dlopened 或 dlclosed 的路径名
表 B-5  sysinsysout 事件有效的变量
变量
说明
$syscode
系统调用号
$sysname
系统调用名
表 B-6  proc_gone 事件有效的变量
变量
说明
$reason
signalexitkilldetach 之一
表 B-7  thr_create 事件有效的变量
变量
说明
$newthread
新建线程的 ID(例如 t@5
$newlwp
新建 LWP 的 ID(例如 l@4
表 B-8  access 事件有效的变量
变量
说明
$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; }

在函数内时启用处理程序

以下示例显示如何在函数内时启用处理程序:

<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               # disable default handler
(dbx) help signals | grep FPE  # can’t remember the subcode name
...
(dbx) stop sig fpe FPE_FLTUND
...

有关启用 ieee 处理程序的更多信息,请参见捕获 FPE 信号(仅限 Oracle Solaris)