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

b

Breakpoint on the current line.

b LINE

Breakpoint at LINE in the current file.

b LINE COND

Conditional; break when COND is true.

b FILE:LINE

Cross-file; FILE matches a %INC entry.

b FILE:LINE COND

Conditional cross-file.

b SUB

Break at the first line of SUB (SUB must be compiled).

b SUB COND

Conditional sub breakpoint.

b $coderef

Break at the sub referenced by $coderef (no COND supported).

b compile SUB

Break after SUB finishes compiling, before its body runs.

b postpone SUB

Break the first time SUB is called, even if not yet loaded.

b load FILE

Break when FILE is required / do’d.

B LINE

Delete breakpoint at LINE.

B *

Delete all breakpoints.

disable [FILE:]LINE

Disable without removing.

enable  [FILE:]LINE

Re-enable.

L

List breakpoints, actions, and watches.

L b

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 BEGIN { } block

Insert $DB::single = 1; inside the block.

Stop before a sub’s body runs (after it compiles)

b compile SUB

Stop on first call of a sub not yet loaded

b postpone SUB

Stop when a file is required or do’d

b load /full/path/from/%INC

Stop at a specific line

b LINE

Stop at a line only when a condition holds

b LINE COND

$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:

  1. Breakpoint condition is tested.

  2. Trace output is printed (if tracing on).

  3. Action runs.

  4. Prompt appears (if breakpoint hit or stepping).

  5. 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

< CMD

Perl code before each prompt (= after the line just executed).

<< CMD

Append to the pre-prompt list.

< ?

List pre-prompt code.

< *

Delete all pre-prompt code.

> CMD / >> CMD

Perl code after each prompt (= before next line).

{ DBCMD

Debugger command (not Perl) pre-prompt.

{{ DBCMD

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.