内容

名称

perldebug - Perl 调试

描述

首先,您是否尝试过使用 use strict;use warnings;?

如果您是 Perl 调试器的新手,您可能更喜欢阅读 perldebtut,它是一个关于调试器的教程介绍。

如果您想了解调试器是如何实现的,您可能更愿意阅读 perldebguts

有关深入的技术使用细节,请参阅 perl5db.pl,即调试器本身的文档。

Perl 调试器

如果您使用 -d 开关调用 Perl,您的脚本将在 Perl 源代码调试器下运行。这就像一个交互式 Perl 环境,它会提示您输入调试器命令,让您检查源代码、设置断点、获取堆栈回溯、更改变量的值等等。这非常方便,以至于您经常会单独启动调试器,只是为了交互式地测试 Perl 结构,看看它们是如何工作的。例如

$ perl -d -e 42

在 Perl 中,调试器不是像在典型的编译环境中那样是一个单独的程序。相反,-d 标志告诉编译器将源代码信息插入到它即将传递给解释器的解析树中。这意味着您的代码必须首先正确编译才能让调试器对其进行操作。然后,当解释器启动时,它会预加载一个包含调试器的特殊 Perl 库文件。

程序将在第一个运行时可执行语句之前停止(但请参阅下面关于编译时语句的内容),并要求您输入调试器命令。与普遍预期相反,无论何时调试器停止并向您显示一行代码,它始终显示它即将执行的行,而不是它刚刚执行的行。

任何调试器无法识别的命令都会直接执行(eval),作为当前包中的 Perl 代码。(调试器使用 DB 包来保存自己的状态信息。)

请注意,所述 eval 受隐式范围约束。因此,任何新引入的词法变量或任何修改的捕获缓冲区内容在 eval 之后都会丢失。调试器是一个学习 Perl 的好环境,但是如果您使用应该在同一范围内的材料进行交互式实验,请将其塞入一行中。

对于在调试器提示符下输入的任何文本,在进一步处理之前,将首先去除前导和尾随空格。如果调试器命令与您自己程序中的某些函数重合,只需在函数前面加上一些看起来不像调试器命令的东西,例如前导 ;+,或者用括号或大括号将其括起来。

调用调试器

有几种方法可以调用调试器

perl -d program_name

在由program_name标识的给定程序上。

perl -d -e 0

使用-e交互式地提供任意expression

perl -d:ptkdb program_name

通过Devel::ptkdb GUI调试给定程序。

perl -dt threaded_program_name

使用线程调试给定程序(实验性)。

如果 Perl 使用-d开关调用,则变量$^P将保存一个真值。如果您需要知道您的代码是否在调试器下运行,这很有用

if ( $^P ) {
    # running under the debugger
}

有关该变量的更多信息,请参阅"$^P" in perlvar

调试器命令

交互式调试器理解以下命令

h

打印一个简要的帮助信息

h [command]

打印给定调试器命令的帮助信息。

h h

h h的特殊参数会生成整个帮助页面,这相当长。

如果h h命令(或任何命令)的输出滚动到屏幕之外,请在命令前面加上一个管道符号,以便它通过您的分页器运行,例如

DB> |h h

您可以通过o pager=...命令更改使用的分页器。

p expr

与当前包中的print {$DB::OUT} expr相同。特别地,由于这只是 Perl 自己的print函数,这意味着嵌套的数据结构和对象不会被转储,这与x命令不同。

DB::OUT文件句柄被打开到/dev/tty,无论 STDOUT 重定向到哪里。

x [maxdepth] expr

在列表上下文中评估其表达式,并以美观的格式输出结果。嵌套的数据结构以递归方式打印出来,这与 Perl 中的真实 print 函数不同。在转储哈希时,您可能更喜欢使用 'x %h' 而不是 'x %h'。如果您想自己执行此操作,请参阅 Dumpvalue

输出格式受 "可配置选项" 下描述的多个选项控制。

如果包含 maxdepth,它必须是一个数字 N;该值仅转储 N 级深度,就好像 dumpDepth 选项已临时设置为 N 一样。

V [pkg [vars]]

使用数据美化打印程序显示包中所有(或某些)变量(默认值为 main)(哈希显示其键和值,以便您可以看到是什么,控制字符被设置为可打印的,等等)。确保您不要在其中放置类型说明符(如 $),只需使用符号名称,例如

V DB filename line

使用 ~pattern!pattern 表示正则表达式的正向和反向匹配。

这类似于对每个适用的变量调用 x 命令。

X [vars]

V currentpackage [vars] 相同。

y [level [vars]]

显示当前作用域或更高 level 作用域中的所有(或某些)词法变量(助记符:mY 变量)。您可以使用 vars 来限制您看到的变量,其工作方式与 VX 命令完全相同。需要 PadWalker 模块版本 0.08 或更高版本;如果没有安装,将发出警告。输出以与 V 相同的样式进行美化打印,并且格式由相同的选项控制。

T

生成堆栈回溯。有关其输出的详细信息,请参见下文。

s [expr]

单步执行。执行到另一个语句的开头,进入子程序调用。如果提供的表达式包含函数调用,它也将被单步执行。

n [expr]

下一步。执行子程序调用,直到下一个语句的开头。如果提供的表达式包含函数调用,则这些函数将被执行,并在每个语句之前停止。

r

继续执行,直到从当前子程序返回。如果设置了 PrintRet 选项(默认),则转储返回值。

<CR>

重复上一个 ns 命令。

c [line|sub]

继续执行,可以选择在指定行或子程序处插入一次性断点。

l

列出下一窗口的行。

l min+incr

min 开始列出 incr+1 行。

l min-max

列出从 minmax 的行。l - 等同于 -

l line

列出一行。

l subname

列出子程序的第一窗口行。subname 可以是包含代码引用的变量。

-

列出上一窗口的行。

v [line]

查看当前行周围的几行代码。

.

将内部调试指针返回到最后执行的行,并打印该行。

f filename

切换到查看不同的文件或 eval 语句。如果 filename 不是在 %INC 的值中找到的完整路径名,则它被认为是正则表达式。

evaled 字符串(如果可访问)被认为是文件名:f (eval 7)f eval 7\b 访问第 7 个 evaled 字符串(按执行顺序)的主体。当前执行的 eval 和定义子程序的 evaled 字符串的主体将被保存,因此可以访问。

/pattern/

向前搜索模式(Perl 正则表达式);最后的 / 可选。默认情况下,搜索不区分大小写。

?pattern?

向后搜索模式;最后的 ? 可选。默认情况下,搜索不区分大小写。

L [abw]

列出(默认所有)操作、断点和监视表达式

S [[!]regex]

列出[不]匹配正则表达式的子程序名称。

t [n]

切换跟踪模式(另请参见 AutoTrace 选项)。可选参数是跟踪当前级别以下的最大级别数;比这更深的任何内容都将保持静默。

t [n] expr

跟踪执行 expr。可选的第一个参数是跟踪当前级别以下的最大级别数;比这更深的任何内容都将保持静默。有关示例,请参见 "perldebguts 中的帧列表输出示例"

b

在当前行设置断点

b [line] [condition]

在给定行之前设置断点。如果指定了条件,则每次到达语句时都会对其进行评估:只有在条件为真时才会设置断点。断点只能设置在以可执行语句开头的行上。条件不使用 if

b 237 $x > 30
b 237 ++$count237 < 11
b 33 /pattern/i

如果行号为 .,则在当前行设置断点

b . $n > 100
b [file]:[line] [condition]

在(可能不同的)文件中的给定行之前设置断点。如果指定了条件,则每次到达语句时都会对其进行评估:只有在条件为真时才会设置断点。断点只能设置在以可执行语句开头的行上。条件不使用 if

b lib/MyModule.pm:237 $x > 30
b /usr/lib/perl5/site_perl/CGI.pm:100 ++$count100 < 11
b subname [condition]

在命名子例程的第一行之前设置断点。subname 可以是一个包含代码引用的变量(在这种情况下,不支持condition)。

b postpone subname [condition]

在子例程编译后的第一行设置断点。

b load filename

filename 的第一行执行之前设置断点,filename 应该是 %INC 值中找到的完整路径名。

b compile subname

在指定子程序编译后执行的第一个语句之前设置断点。

B line

从指定的删除断点。

B *

删除所有已安装的断点。

disable [file]:[line]

禁用断点,使其不会停止程序执行。断点默认情况下处于启用状态,可以使用enable命令重新启用。

disable [line]

禁用断点,使其不会停止程序执行。断点默认情况下处于启用状态,可以使用enable命令重新启用。

这是针对当前文件中的断点进行的。

enable [file]:[line]

启用断点,使其会停止程序执行。

enable [line]

启用断点,使其会停止程序执行。

这是针对当前文件中的断点进行的。

a [line] command

设置在执行该行之前要执行的操作。如果省略line,则在即将执行的行上设置操作。调试器执行的步骤顺序为

1. check for a breakpoint at this line
2. print the line if necessary (tracing)
3. do any actions associated with that line
4. prompt user if at a breakpoint or in single-step
5. evaluate line

例如,这将在每次经过第 53 行时打印出 $foo

a 53 print "DB FOUND $foo\n"
A line

从指定的行删除操作。

A *

删除所有已安装的操作。

w expr

添加全局监视表达式。每当监视的全局变量发生变化时,调试器将停止并显示旧值和新值。

W expr

删除监视表达式

W *

删除所有监视表达式。

o

显示所有选项。

o booloption ...

将每个列出的布尔选项设置为值1

o anyoption? ...

打印一个或多个选项的值。

o option=value ...

设置一个或多个选项的值。如果值包含内部空格,则应将其用引号括起来。例如,您可以设置 o pager="less -MQeicsNfr" 以使用这些特定选项调用 **less**。您可以使用单引号或双引号,但如果您这样做,您必须转义任何嵌入的相同类型的引号,以及转义任何紧接在该引号之前的转义符,但这些转义符并非用于转义引号本身。换句话说,您遵循单引号规则,无论引号是什么;例如:o option='this isn\'t bad'o option="She said, \"Isn't it?\""

出于历史原因,=value 是可选的,但在安全的情况下默认为 1,即主要针对布尔选项。始终最好使用 = 指定特定值。option 可以缩写,但为了清晰起见,可能不应该缩写。可以同时设置多个选项。有关这些选项的列表,请参阅 "可配置选项"

< ?

列出所有提示前 Perl 命令操作。

< [ command ]

设置在每个调试器提示符之前执行的操作(Perl 命令)。可以通过反斜杠转义换行符来输入多行命令。

< *

删除所有提示前 Perl 命令操作。

<< command

添加在每个调试器提示符之前执行的操作(Perl 命令)。可以通过反斜杠转义换行符来输入多行命令。

> ?

列出所有提示后 Perl 命令操作。

> command

设置在您刚刚发出返回执行脚本的命令后,在提示符出现后执行的操作(Perl 命令)。可以通过反斜杠转义换行符来输入多行命令(我们敢打赌您现在已经猜到了)。

> *

删除所有提示后 Perl 命令操作。

>> command

添加在您刚刚发出返回执行脚本的命令后,在提示符出现后执行的操作(Perl 命令)。可以通过反斜杠转义换行符来输入多行命令。

{ ?

列出所有提示前调试器命令。

{ [ command ]

在每个调试器提示符之前设置一个操作(调试器命令)。可以以通常的方式输入多行命令。

由于此命令在某种意义上是新的,因此如果您似乎意外输入了一个块,则会发出警告。如果您确实要这样做,请像使用 ;{ ... } 甚至 do { ... } 一样编写它。

{ *

删除所有提示符前的调试器命令。

{{ command

添加一个操作(调试器命令),以便在每个调试器提示符之前发生。如果您可以猜出如何输入多行命令,则可以输入:请参见上文。

! number

重做上一个命令(默认为上一个命令)。

! -number

重做第 number 个上一个命令。

! pattern

重做以 pattern 开头的最后一个命令。另请参见 o recallCommand

!! cmd

在子进程中运行 cmd(从 DB::IN 读取,写入 DB::OUT)另请参见 o shellBang。请注意,将使用用户的当前 shell(实际上是他们的 $ENV{SHELL} 变量),这可能会干扰对退出状态或信号和核心转储信息的正确解释。

source file

file 读取并执行调试器命令。file 本身可能包含 source 命令。

H -number

显示最后 n 个命令。仅列出长度超过一个字符的命令。如果省略 number,则列出所有命令。

q 或 ^D

退出。(“quit”对此不起作用,除非您创建了别名)这是退出调试器的唯一支持方法,尽管键入 exit 两次可能有效。

如果您希望能够从脚本末尾逐步执行,请将 inhibit_exit 选项设置为 0。如果您希望逐步执行全局销毁,您可能还需要将 $finished 设置为 0。

R

通过 exec() 新会话重新启动调试器。我们会尝试在整个过程中维护您的历史记录,但内部设置和命令行选项可能会丢失。

以下设置当前被保留:历史记录、断点、操作、调试器选项,以及 Perl 命令行选项 -w-I-e

|dbcmd

运行调试器命令,将 DB::OUT 管道到当前分页器。

||dbcmd

|dbcmd 相同,但 DB::OUT 也被临时 select

= [alias value]

定义一个命令别名,例如

= quit q

或列出当前别名。

command

将命令作为 Perl 语句执行。将添加一个尾随分号。如果 Perl 语句会被误认为 Perl 调试器,则也使用一个前导分号。

m expr

列出可以对已评估表达式的结果调用的方法。表达式可以评估为对已祝福对象的引用,或对包名的引用。

M

显示所有已加载的模块及其版本。

man [manpage]

尽管名称如此,但它会调用系统上的默认文档查看器来查看给定的页面,或者如果省略了 manpage,则查看查看器本身。如果该查看器是 man,则当前 Config 信息将用于使用正确的 MANPATH 或 -M manpath 选项调用 man。将重新尝试对形式为 XXX 的失败查找,这些查找与形式为 perlXXX 的已知手册页匹配。这使您可以在调试器中键入 man debugman op

在传统上没有可用 man 命令的系统上,调试器会调用 perldoc。有时这种确定是错误的,因为供应商固执己见,或者更幸运的是,因为有进取心的用户。如果您属于这两个类别中的任何一个,只需手动将 $DB::doccmd 变量设置为在您的系统上查看 Perl 文档的任何查看器。这可以在 rc 文件中设置,也可以通过直接赋值设置。我们仍在等待一个类似于以下内容的工作示例

$DB::doccmd = 'netscape -remote http://something.here/';

可配置选项

调试器有许多可以使用 o 命令设置的选项,无论是交互式地还是从环境或 rc 文件中设置。该文件在 Unix 下名为 ./.perldb~/.perldb,其中 /dev/ttyperldb.ini,否则为。

recallCommand, ShellBang

用于召回命令或启动 shell 的字符。默认情况下,两者都设置为 !,这很不幸。

pager

用于分页管道命令(以 | 字符开头的命令)输出的程序。默认情况下,将使用 $ENV{PAGER}。由于调试器使用当前终端的粗体和下划线特性,如果所选分页器不按原样传递转义序列,则某些调试器命令的输出在通过分页器发送时将不可读。

tkRunning

在提示(使用 ReadLine)时运行 Tk。

signalLevel, warnLevel, dieLevel

详细程度级别。默认情况下,调试器会保留您的异常和警告,因为更改它们可能会破坏正确运行的程序。当收到未捕获的 INT、BUS 或 SEGV 信号时,它将尝试打印一条消息。(但请参阅下面 "BUGS" 中关于信号的说明。)

要禁用此默认安全模式,请将这些值设置为大于 0 的值。在级别 1 时,您会在收到任何类型的警告(这通常很烦人)或异常(这通常很有价值)时获得回溯。不幸的是,调试器无法区分致命异常和非致命异常。如果 dieLevel 甚至为 1,那么您的非致命异常也会被跟踪,如果它们来自 eval'ed 字符串或来自您尝试加载的模块中的任何类型的 eval,它们也会被无情地更改。如果 dieLevel 为 2,调试器就不在乎它们来自哪里:它会接管您的异常处理程序并打印出跟踪,然后用它自己的修饰来修改所有异常。这可能对某些跟踪目的有用,但往往会彻底破坏任何认真对待异常处理的程序。

AutoTrace

跟踪模式(类似于 t 命令,但可以放入 PERLDB_OPTS 中)。

LineInfo

用于打印行号信息的 文件 或 管道。如果它是一个管道(例如,|visual_perl_db),则使用简短消息。这是用于与客户端编辑器或可视化调试器(例如特殊的 viemacs 钩子,或 ddd 图形调试器)交互的机制。

inhibit_exit

如果为 0,则允许从脚本末尾“步出”。

PrintRet

如果设置(默认),则在 r 命令后打印返回值。

ornaments

影响命令行的屏幕外观(参见 Term::ReadLine)。目前无法禁用这些装饰,这可能会导致某些显示器或某些分页器上的某些输出难以辨认。这被认为是一个错误。

frame

影响在进入和退出子程序时打印消息。如果 frame & 2 为假,则仅在进入时打印消息。(如果与其他消息交织在一起,则在退出时打印可能会有用。)

如果 frame & 4,则打印函数的参数,以及上下文和调用者信息。如果 frame & 8,则在打印的参数上启用重载的 stringifytied FETCH。如果 frame & 16,则打印子程序的返回值。

参数列表被截断的长度由下一个选项控制

maxTraceLen

frame 选项的位 4 设置时,截断参数列表的长度。

windowSize

更改代码列表窗口的大小(默认值为 10 行)。

以下选项影响 VXx 命令的行为

arrayDepth, hashDepth

仅打印前 N 个元素('' 表示所有元素)。

dumpDepth

在转储结构时将递归深度限制为 N 级。负值被解释为无穷大。默认值:无穷大。

compactDump, veryCompact

更改数组和哈希输出的样式。如果 compactDump,则短数组可以打印在一行上。

globPrint

是否打印全局变量的内容。

DumpDBFiles

转储包含调试文件的数组。

DumpPackages

转储包的符号表。

DumpReused

转储“重用”地址的内容。

quote, HighBit, undefPrint

更改字符串转储的样式。quote 的默认值为 auto;可以通过将其分别设置为 "' 来启用双引号或单引号格式。默认情况下,高位设置为 1 的字符将按原样打印。

UsageOnly

基本的每个包内存使用情况转储。计算包中变量中找到的字符串的总大小。这并不包括模块文件范围内的词法变量,也不包括在闭包中丢失的词法变量。

HistFile

调试器启动时读取历史记录(假设可以使用 Term::ReadLine 后端)的文件路径,并在关闭时保存历史记录(以便在会话之间持久化)。概念上类似于 Bash 的 .bash_history 文件。

HistSize

历史记录中保存的行数(假设上面有 HistFile)。

在读取 rc 文件后,调试器会读取 $ENV{PERLDB_OPTS} 环境变量,并将其解析为“O …”行的其余部分,就像您可能在调试器提示符处输入的那样。您可以在其中放置初始化选项 TTYnoTTYReadLineNonStop

如果您的 rc 文件包含

parse_options("NonStop=1 LineInfo=db.out AutoTrace");

那么您的脚本将在没有人为干预的情况下运行,将跟踪信息放入文件 db.out 中。(如果您中断它,您最好将 LineInfo 重置为 /dev/tty,如果您希望看到任何内容。)

TTY

用于调试 I/O 的 TTY。

noTTY

如果设置,调试器将进入 NonStop 模式,并且不会连接到 TTY。如果中断(或如果控制通过显式设置 $DB::signal 或 $DB::single 从 Perl 脚本转到调试器),它将连接到启动时在 TTY 选项中指定的 TTY,或使用您选择的 Term::Rendezvous 模块在运行时找到的 tty。

此模块应实现一个名为 new 的方法,该方法返回一个具有两个方法的对象:INOUT。这些应分别返回用于调试输入和输出的文件句柄。new 方法应检查包含启动时 $ENV{PERLDB_NOTTY} 值的参数,否则检查 "$ENV{HOME}/.perldbtty$$"。此文件不会检查其所有权,因此理论上存在安全隐患。

ReadLine

如果为假,则调试器中的 readline 支持将被禁用,以便调试本身使用 ReadLine 的应用程序。

NonStop

如果设置,调试器将进入非交互模式,直到被中断,或通过设置 $DB::signal 或 $DB::single 以编程方式中断。

以下是如何使用 $ENV{PERLDB_OPTS} 变量的示例

$ PERLDB_OPTS="NonStop frame=2" perl -d myprogram

这将运行脚本 myprogram,无需人工干预,并打印出带有入口点和出口点的调用树。请注意,NonStop=1 frame=2 等效于 N f=2,并且最初,选项可以通过第一个字母(模 Dump* 选项)唯一地缩写。但是,建议您始终完整地拼写它们,以提高可读性和未来的兼容性。

其他示例包括

$ PERLDB_OPTS="NonStop LineInfo=listing frame=2" perl -d myprogram

这将非交互式地运行脚本,在进入子例程时打印信息,并将每行执行的代码打印到名为 listing 的文件中。(如果您中断它,最好将 LineInfo 重置为“交互式”!)

其他示例包括(使用标准 shell 语法来显示环境变量设置)

$ ( PERLDB_OPTS="NonStop frame=1 AutoTrace LineInfo=tperl.out"
    perl -d myprogram )

这可能对调试使用 Term::ReadLine 本身的程序很有用。不要忘记将您的 shell 从与 /dev/ttyXX 相对应的窗口中的 TTY 分离,例如,通过发出以下命令

$ sleep 1000000

有关详细信息,请参阅 "perldebguts 中的调试器内部"

调试器输入/输出

提示

调试器提示类似于

DB<8>

甚至

DB<<17>>

其中该数字是命令编号,您可以使用内置的类似 csh 的历史机制来访问它。例如,!17 将重复命令编号 17。尖括号的深度表示调试器的嵌套深度。您可能会获得不止一组括号,例如,如果您已经在断点处,然后打印了本身具有断点的函数调用的结果,或者您通过 s/n/t expression 命令进入表达式。

多行命令

如果您想输入多行命令,例如包含多个语句的子例程定义或格式,请使用反斜杠转义通常会结束调试器命令的换行符。以下是一个示例

DB<1> for (1..4) {         \
cont:     print "ok\n";   \
cont: }
ok
ok
ok
ok

请注意,这种转义换行符的操作特定于输入到调试器的交互式命令。

堆栈回溯

以下是如何通过 T 命令显示堆栈回溯的示例

$ = main::infested called from file 'Ambulation.pm' line 10
@ = Ambulation::legs(1, 2, 3, 4) called from file 'camel_flea'
                                                         line 7
$ = main::pests('bactrian', 4) called from file 'camel_flea'
                                                         line 4

上面的左侧字符指示函数被调用的上下文,其中 $@ 分别表示标量或列表上下文,而 . 表示空上下文(实际上是一种标量上下文)。上面的显示表明您在运行堆栈转储时位于函数 main::infested 中,并且它是在标量上下文中从文件 Ambulation.pm 的第 10 行调用的,但没有任何参数,这意味着它是作为 &infested 调用的。下一个堆栈帧显示函数 Ambulation::legs 是在列表上下文中从 camel_flea 文件调用,并带有四个参数。最后一个堆栈帧显示 main::pests 是在标量上下文中调用的,也来自 camel_flea,但来自第 4 行。

如果您在活动的 use 语句中执行 T 命令,则回溯将包含 require 帧和 eval 帧。

行列表格式

这展示了 l 命令可以产生的输出类型。

  DB<<13>> l
101:        @i{@i} = ();
102:b       @isa{@i,$pack} = ()
103             if(exists $i{$prevpack} || exists $isa{$pack});
104     }
105
106     next
107==>      if(exists $isa{$pack});
108
109:a   if ($extra-- > 0) {
110:        %isa = ($pack,1);

可中断行用 : 标记。带有断点的行用 b 标记,带有操作的行用 a 标记。即将执行的行用 ==> 标记。

请注意,调试器列表中的代码可能与您的原始源代码看起来不同。行指令和外部源过滤器可以在 Perl 看到代码之前更改代码,导致代码从其原始位置移动或采用完全不同的形式。

帧列表

frame 选项设置时,调试器将以不同的样式打印已进入(以及可选地已退出)的子例程。有关这些的极其冗长的示例,请参见 perldebguts

调试编译时语句

如果您有编译时可执行语句(例如 BEGIN、UNITCHECK 和 CHECK 块或 use 语句中的代码),这些语句将 *不会* 被调试器停止,尽管 require 和 INIT 块会,并且编译时语句可以使用 PERLDB_OPTS 中设置的 AutoTrace 选项进行跟踪)。但是,从您自己的 Perl 代码中,您可以使用以下语句将控制权转移回调试器,如果调试器未运行,则该语句是无害的。

$DB::single = 1;

如果您将 $DB::single 设置为 2,则等同于只键入了 n 命令,而值为 1 则表示 s 命令。$DB::trace 变量应设置为 1 以模拟键入 t 命令。

调试编译时代码的另一种方法是启动调试器,在某个模块的 *加载* 上设置断点

  DB<7> b load f:/perllib/lib/Carp.pm
Will stop on load of 'f:/perllib/lib/Carp.pm'.

然后使用 R 命令重新启动调试器(如果可能)。可以使用 b compile subname 来实现相同目的。

调试器自定义

调试器可能包含足够的配置钩子,因此您永远不必自己修改它。您可以使用其 o 命令从调试器内部更改调试器的行为,通过 PERLDB_OPTS 环境变量从命令行更改,以及从自定义文件更改。

您可以通过设置一个名为 .perldb 的文件来进行一些自定义,该文件包含初始化代码。例如,您可以创建以下别名(最后一个是人们期望存在的别名)

$DB::alias{'len'}  = 's/^len(.*)/p length($1)/';
$DB::alias{'stop'} = 's/^stop (at|in)/b/';
$DB::alias{'ps'}   = 's/^ps\b/p scalar /';
$DB::alias{'quit'} = 's/^quit(\s*)/exit/';

您可以使用类似于以下的调用从 .perldb 中更改选项;

parse_options("NonStop=1 LineInfo=db.out AutoTrace=1 frame=2");

代码在 DB 包中执行。请注意,.perldb 在处理 PERLDB_OPTS 之前进行处理。如果 .perldb 定义了子例程 afterinit,则在调试器初始化结束之后会调用该函数。.perldb 可能包含在当前目录中,也可能包含在主目录中。由于此文件由 Perl 源代码导入,并且可能包含任意命令,出于安全原因,它必须由超级用户或当前用户拥有,并且只能由其所有者写入。

您可以通过将任意命令添加到 @DB::typeahead 来模拟调试器的 TTY 输入。例如,您的 .perldb 文件可能包含

sub afterinit { push @DB::typeahead, "b 4", "b 6"; }

这将在调试器初始化之后立即尝试在第 4 行和第 6 行设置断点。请注意,@DB::typeahead 不是受支持的接口,并且可能会在将来的版本中发生更改。

如果您想修改调试器,请将 perl5db.pl 从 Perl 库复制到另一个名称,并根据您的需要进行修改。然后,您需要设置 PERL5DB 环境变量,例如

BEGIN { require "myperl5db.pl" }

作为最后的手段,您还可以使用 PERL5DB 通过直接设置内部变量或调用调试器函数来自定义调试器。

请注意,本文档(或 perldebguts)中未记录的任何变量和函数被认为仅供内部使用,因此可能会在未经通知的情况下发生更改。

调试器中的 Readline 支持/历史记录

在默认情况下,提供的唯一命令行历史记录是一个简单的历史记录,它检查以感叹号开头的命令。但是,如果您从 CPAN 安装了 Term::ReadKeyTerm::ReadLine 模块(例如 Term::ReadLine::GnuTerm::ReadLine::Perl 等),您将拥有与 GNU readline(3) 提供的类似的完整编辑功能。在 CPAN 上的 modules/by-module/Term 目录中查找这些模块。但是,它们不支持正常的 vi 命令行编辑。

还提供了一个基本的命令行补全功能,包括当前作用域中的词法变量(如果安装了 PadWalker 模块)。

如果没有 Readline 支持,您可能会在使用箭头键和/或退格键时看到符号 "^[[A"、"^[[C"、"^[[B"、"^[[D""、"^H" 等。

编辑器支持调试

如果您在系统上安装了 GNU 版本的 emacs,它可以与 Perl 调试器交互,提供类似于其与 C 调试器交互的集成软件开发环境。

最近版本的 Emacs 带有一个启动文件,用于使 emacs 充当理解 Perl 语法(部分)的语法定向编辑器。请参阅 perlfaq3

vi 用户也应该查看 vimgvim(带鼠标和窗口的版本),以获得 Perl 关键字的颜色。

请注意,只有 perl 才能真正解析 Perl,因此所有此类 CASE 工具都或多或少地达不到目标,尤其是在您没有像 C 程序员那样编写 Perl 代码的情况下。

Perl 分析器

如果您希望为 Perl 提供一个替代调试器来运行,请使用冒号和包参数调用您的脚本,并将其传递给 -d 标志。Perl 的替代调试器包括 Perl 分析器,Devel::NYTProf,它作为 CPAN 分发版单独提供。要分析文件 mycode.pl 中的 Perl 程序,只需键入

$ perl -d:NYTProf mycode.pl

当脚本终止时,分析器将创建一个包含分析信息的数据库,您可以使用分析器的工具将其转换为报告。有关详细信息,请参阅 <perlperf>。

调试正则表达式

use re 'debug' 使您能够看到 Perl 正则表达式引擎工作方式的详细信息。为了理解这种通常大量的输出,您不仅需要了解正则表达式匹配的一般工作原理,还需要了解 Perl 的正则表达式是如何在内部编译成自动机的。这些问题在 "perldebguts 中的调试正则表达式" 中进行了详细探讨。

调试内存使用情况

Perl 内置了报告自身内存使用情况的支持,但这是一个相当高级的概念,需要对内存分配机制有一定的了解。有关详细信息,请参阅 "perldebguts 中的调试 Perl 内存使用情况"

另请参阅

您已经启用了 use strictuse warnings,对吧?

perldebtutperldebgutsperl5db.plreDBDevel::NYTProfDumpvalueperlrun

在调试使用 #! 并因此通常在 $PATH 中找到的脚本时,-S 选项会导致 perl 在 $PATH 中搜索它,因此您不必键入路径或 which $scriptname

$ perl -Sd foo.pl

错误

您无法获取堆栈帧信息,也无法以任何方式调试未由 Perl 编译的函数,例如来自 C 或 C++ 扩展的函数。

如果您在子例程中更改了 @_ 参数(例如使用 shiftpop),则堆栈回溯将不会显示原始值。

调试器目前无法与 -W 命令行开关一起使用,因为它本身并不没有警告。

如果您处于缓慢的系统调用中(例如 waitaccept 或从键盘或套接字 read),并且没有设置自己的 $SIG{INT} 处理程序,那么您将无法使用 CTRL-C 返回调试器,因为调试器自己的 $SIG{INT} 处理程序不理解它需要引发异常以从慢速系统调用中 longjmp(3) 出去。