Breakpoints, actions, and watches#
This chapter covers stopping the debugger at a specific point — a line, a subroutine, a condition, a value change — and the prompt-hook machinery that lets you run code automatically at each stop.
Readers arriving here know how to launch perl -d and step one
line at a time. The next skill is to skip straight to the
interesting place and stop only when the problem is about to
manifest.
Breakpoints on lines and subs#
Command |
Effect |
|---|---|
|
Breakpoint on the current line. |
|
Breakpoint at LINE in the current file. |
|
Conditional; break when COND is true. |
|
Cross-file; FILE matches a |
|
Conditional cross-file. |
|
Break at the first line of SUB (SUB must be compiled). |
|
Conditional sub breakpoint. |
|
Break at the sub referenced by |
|
Break after SUB finishes compiling, before its body runs. |
|
Break the first time SUB is called, even if not yet loaded. |
|
Break when FILE is |
|
Delete breakpoint at LINE. |
|
Delete all breakpoints. |
|
Disable without removing. |
|
Re-enable. |
|
List breakpoints, actions, and watches. |
|
List breakpoints only. |
Conditions are raw expressions, not if (…):
DB<1> b 237 $count > 10
DB<2> b 42 /unauthorized/i
DB<3> b validate_payload ref($obj) eq 'HASH' && keys %$obj
Breakpoints settle only on lines that contain executable code. A blank line, a pure comment, or a continuation of an earlier statement refuses:
DB<1> b 3
Line 3 not breakable.
A line carries one breakpoint and one action at most; adding a second overwrites the first.
Timing matrix#
Where in the program lifecycle a breakpoint fires matters —
especially for code in BEGIN blocks or modules that are
required lazily.
Goal |
Command |
|---|---|
Stop at the first runtime statement |
Default — the debugger already stops there. |
Stop inside a |
Insert |
Stop before a sub’s body runs (after it compiles) |
|
Stop on first call of a sub not yet loaded |
|
Stop when a file is |
|
Stop at a specific line |
|
Stop at a line only when a condition holds |
|
$DB::single = 1; inside a BEGIN block is the trick for
compile-time debugging: writing b at the prompt only works
after the debugger is running, but BEGIN code runs before the
first prompt. Drop the assignment into the block, launch under
-d, and the debugger stops at the next breakable line inside
the block.
Accessing $DB::single when not under -d autovivifies DB::
harmlessly — the pattern is safe to commit.
Listing and managing breakpoints#
DB<1> L
app.pl:
42: $user = User->load($id);
break if (1)
91: dispatch($req);
break if ($req->method eq 'POST')
DB<2> disable 42
DB<3> enable 42
DB<4> B 42
DB<5> B *
disable / enable toggle a breakpoint without forgetting its
condition — useful when you want to skip a hot breakpoint
temporarily and re-arm it later.
Actions: run code automatically at a line#
An action runs Perl code before the specified line executes, without stopping. Use for passive observation:
DB<1> a 42 print "entering: user_id=$user_id\n"
DB<2> a 91 warn "POST body:\n" . Dumper($body) if $req->method eq 'POST'
DB<3> L a
app.pl:
42: ...
action: print "entering: user_id=$user_id\n"
DB<4> A 42 # delete action at line 42
DB<5> A * # delete all actions
Ordering at a breakable line:
Breakpoint condition is tested.
Trace output is printed (if tracing on).
Action runs.
Prompt appears (if breakpoint hit or stepping).
The line itself executes.
Actions and breakpoints coexist on the same line — one of each maximum.
Watches: break on value change#
A watch reports the old and new value when a tracked expression changes, and drops you at the prompt:
DB<1> w $global_count
DB<2> c
Watchpoint 0: $global_count changed:
old value: 42
new value: 43
main::tick(app.pl:118): ++$global_count;
DB<3> W $global_count # delete this watch
DB<4> W * # delete all watches
Watches are evaluated at every breakable line. Expressions must
reference globals or accessible aliases; lexical my variables
are not watchable directly. When a lexical matters, use
Tie::Watch in the code to install a watcher at tie time, or
assign via a package-scoped alias.
Watches add per-statement cost proportional to the number of watches and the expense of each expression. Keep them narrow and remove them when done.
Prompt hooks: run code at every stop#
< / > install Perl code to run automatically before / after
every prompt. { / {{ do the same for debugger commands:
Command |
Effect |
|---|---|
|
Perl code before each prompt (= after the line just executed). |
|
Append to the pre-prompt list. |
|
List pre-prompt code. |
|
Delete all pre-prompt code. |
|
Perl code after each prompt (= before next line). |
|
Debugger command (not Perl) pre-prompt. |
|
Append to the pre-prompt debugger-command list. |
Typical use: timestamp every step:
DB<1> < print "stop: ", scalar localtime, "\n"
DB<2> > print "start: ", scalar localtime, "\n"
Or always show the current line and a watched variable:
DB<1> { v
DB<2> { p $important
Multi-line: escape the newline with \:
DB<1> < for my $f (@important_files) { \
cont: print " $f: ", (-s $f) // 'n/a', "\n"; \
cont: }
Aliases#
Persistent command shortcuts via =:
DB<1> = len s/^len(.*)/p length($1)/
DB<2> = quit s/^quit(\s*)/exit/
DB<3> = # list all aliases
Aliases live in %DB::alias and apply at dispatch time. Define
once in .perldb for across-session persistence.
One-shot breakpoints#
c LINE sets a breakpoint at LINE, continues, and clears the
breakpoint when it hits:
DB<1> c 42
Simplest way to say “just run to line 42 and stop there”. No
manual b / B pairing.
Breaking on import / first-call lazily#
When a sub lives in a module that may not be loaded yet, b SUB
fails:
DB<1> b MyApp::Worker::dispatch
Subroutine not yet compiled.
b postpone waits for the sub to finish compiling:
DB<1> b postpone MyApp::Worker::dispatch
DB<2> c
For files loaded by require / do, b load breaks on first
load:
DB<1> b load /usr/share/perl5/MyApp/Worker.pm
The filename must match the full path in %INC, not just the
module name.
Find out more#
inspecting-state — what to look at once a breakpoint fires.
tracing — when you want to watch what happens without stopping.