# Inspecting state This chapter covers the debugger's data-inspection vocabulary: `x`, `V`, `X`, `y`, `m`, `M`, `i`, and the options that control how deeply aggregate values are dumped. After this chapter you can ask any running program "what does this variable, this package, this object actually look like right now?" Readers arrive here knowing `p EXPR` prints a scalar. The rest of the inspection commands earn their keep the moment the answer "what is this?" requires more than a single value. ## `x`: dump structures `x EXPR` pretty-prints in list context, recursing into references: ``` DB<1> x \%config 0 HASH(0x5651f9a82358) 'debug' => 1 'dsn' => 'dbi:SQLite::memory:' 'timeout' => 30 'users' => ARRAY(0x5651f9b28a10) 0 'alice' 1 'bob' 2 'carol' ``` Always pass a **reference** for aggregates. `x %h` dumps the flat key/value list, which hides the structure. `x \%h` does what you want. ``` DB<2> x \@list 0 ARRAY(0x5651f9b28a10) 0 'alice' 1 'bob' 2 'carol' DB<3> x $obj 0 MY::Class=HASH(0x5651fa01c2b0) 'id' => 42 'prefs' => HASH(0x5651fa01c330) 'theme' => 'dark' ``` For deep or cyclic structures, cap the recursion: ``` DB<4> x 2 \%tree # recurse 2 levels deep DB<5> x 1 $obj # one level ``` If the first token of the expression is numeric, parenthesise: ``` DB<6> x (3 + $offset) # without parens, 3 is mis-parsed as depth ``` ## `V` and `X`: package variables `V [PKG [VARS]]` dumps the globals of a package: ``` DB<1> V main $counter = 42 @ARGV = ( 0 '--verbose' 1 'input.txt' ) %ENV = ( 'PATH' => '/usr/bin:/bin' ... ) ``` With a second argument, filter variables: ``` DB<2> V MyApp $config $last_user # only these DB<3> V MyApp ~^config # regex: names matching /^config/ DB<4> V MyApp !^_ # regex: names NOT matching /^_/ ``` `X` is `V` for the current package: ``` DB<5> X # dump current package's globals DB<6> X $foo @bar # filtered ``` `V` / `X` do **not** see lexicals (`my` variables). For those, use `y`. ## `y`: lexicals in enclosing scope `y LEVEL [VARS]` reads lexical `my` variables via `PadWalker`: ``` DB<1> y 0 # lexicals of the current sub my $req = HTTP::Request=HASH(0x...) my $user_id = 42 my @errors = () DB<2> y 1 # one frame up (the caller's lexicals) my $request_count = 118 my $dispatcher = MyApp::Dispatcher=HASH(0x...) DB<3> y 0 $req $user_id # only those ``` `y` requires `PadWalker` version 0.08 or later. It works only inside a sub (the outer script body has no pad to walk). ## `m`: methods of an object or class `m EXPR` lists methods callable on an object or class: ``` DB<1> m $user via UNIVERSAL: isa can DOES VERSION DESTROY via MyApp::Model: save load delete update via MyApp::Role::Auditable: audit_log record_event DB<2> m 'MyApp::Worker' via UNIVERSAL: ... via MyApp::Worker: dispatch retry cancel ``` Groups methods by the package that provides them — useful for spotting which role or superclass a method comes from. ## `M` and `i`: modules and inheritance `M` lists loaded modules with versions: ``` DB<1> M 'DBI' (version 1.643) 'JSON::PP' (version 4.16) 'MyApp::Model' (version undef) ... ``` `i CLASS` or `i $obj` prints the inheritance tree: ``` DB<2> i $user MyApp::User 0.12 MyApp::Model 0.42 Moo::Object ? ``` Useful for "where is this method actually coming from?" when method resolution crosses several roles. ## `S`: subroutine names `S [[!]PAT]` lists sub names matching (or not matching) a pattern: ``` DB<1> S ^MyApp::Worker:: MyApp::Worker::cancel MyApp::Worker::dispatch MyApp::Worker::retry DB<2> S !^(main|DB|UNIVERSAL):: # everything except these ``` `S` alone lists everything — long. ## `p` vs `x`: which to use when | Want | Use | |------|-----| | A single scalar's value, plain | `p $x` | | A joined / formatted expression | `p join ',', sort keys %h` | | A hash or array | `x \%h`, `x \@a` | | An object's fields | `x $obj` | | Only the top level | `x 1 $deep_tree` | | Package variables of `Pkg` | `V Pkg` | | Lexicals of current sub | `y 0` | | Method list of `$obj` | `m $obj` | | `@ISA` chain of `$obj` | `i $obj` | Special case: `p` is a flat print. For a reference, `p $ref` prints `HASH(0x…)`. Use `x $ref` for the contents. ## Depth and compactness options Dump output is shaped by options set via the `o` command. The relevant settings for inspection: | Option | Effect | |----------------|--------| | `dumpDepth` | Recursion depth (negative = unlimited). Default 4. | | `arrayDepth` | First N array elements only; empty = all. | | `hashDepth` | Same, for hashes. | | `compactDump` | Short arrays on one line. | | `veryCompact` | Tighter yet. | | `globPrint` | Dump glob contents. | | `DumpReused` | Fully expand repeated references (beware cycles). | | `quote` | `"` or `'` or `auto` (default). | | `undefPrint` | How `undef` renders. | | `bareStringify`| Print overload-stringified form. | Set an option in a session: ``` DB<1> o dumpDepth=6 DB<2> o compactDump=1 DB<3> o arrayDepth=20 DB<4> o compactDump? # query current value ``` Set options at startup via `PERLDB_OPTS` or in `.perldb`: ``` PERLDB_OPTS="dumpDepth=6 compactDump=1" perl -d script.pl ``` ## Inspecting SV internals `Devel::Peek` exposes the scalar's internal storage — type flags, refcount, PV/NV/IV layout, magic chain — when the question is "what kind of scalar is this really?": ``` DB<1> use Devel::Peek; Dump($sv) ``` Primarily for investigating tied variables, overloaded objects, or performance anomalies where the answer depends on whether a scalar is currently stored as an integer, a string, or both. Note: `Devel::Peek` in pperl is a compat layer — it reports a pperl-specific `Sv` layout rather than perl5's SV layout. Fields like `REFCNT`, `FLAGS`, `PV`, `IV`, `NV` have equivalents; the exact output differs. See the [pperl-architecture guide](../pperl-architecture/index) for layout details. ## Evaluating at the prompt Anything unrecognised as a command is evaluated as Perl. Use it to drill deeper than a single command: ``` DB<1> p keys %{ $obj->{prefs} } theme,locale,tz DB<2> x [ grep { !defined $_->{parent} } @nodes ] DB<3> x { map { $_->id => $_->name } @users } ``` For one-off assertions without stopping: ``` DB<1> die "unexpected" if ref $obj ne 'MyApp::User' ``` ## Program I/O vs debugger I/O The debugger's own input and output go through `$DB::IN` and `$DB::OUT`, which are opened to `/dev/tty` directly. The program can redirect STDIN / STDOUT / STDERR freely; the debugger prompt still shows up. Conversely, `p EXPR` output does not contaminate a program's captured stdout. ## Find out more - [breakpoints](breakpoints) — stop where you can inspect; this chapter is about what to look at once stopped. - [tracing](tracing) — watch values change over time without stopping at every step.