The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl

use strict;
use warnings;
use feature qw( say switch );
no if $] >= 5.017011, warnings => 'experimental::smartmatch';

use Devel::MAT;
use List::Util qw( max );

sub show_sv
{
   my $sv = shift;

   say $sv->desc_addr . " with refcount " . $sv->refcnt;
   say "  blessed as " . $sv->blessed->stashname if $sv->blessed;

   my $type = ref $sv; $type =~ s/^Devel::MAT::SV:://;
   given( $type ) {
      when( "GLOB" ) {
         say '  stash=' . $sv->stash->desc_addr if $sv->stash;

         say '  SCALAR=' . $sv->scalar->desc_addr if $sv->scalar;
         say '  ARRAY='  . $sv->array->desc_addr  if $sv->array;
         say '  HASH='   . $sv->hash->desc_addr   if $sv->hash;
         say '  CODE='   . $sv->code->desc_addr   if $sv->code;
         say '  EGV='    . $sv->egv->desc_addr    if $sv->egv;
         say '  IO='     . $sv->io->desc_addr     if $sv->io;
         say '  FORM='   . $sv->form->desc_addr   if $sv->form;
      }
      when( "SCALAR" ) {
         say '  UV=' . $sv->uv if defined $sv->uv;
         say '  IV=' . $sv->iv if defined $sv->iv;
         say '  NV=' . $sv->nv if defined $sv->nv;
         if( defined( my $pv = $sv->pv ) ) {
            say '  PV=' . $pv if length $pv < 40 and $pv !~ m/[\0-\x1f\x80-\x9f]/;
            say '  PVLEN ' . $sv->pvlen;
         }
      }
      when( "REF" ) {
         say '  RV=' . $sv->rv->desc_addr if $sv->rv;
      }
      when( "ARRAY" ) {
         my @elems = $sv->elems;
         say "  [$_]=" . ( $elems[$_] ? $elems[$_]->desc_addr : "NULL" ) for 0 .. $#elems;
      }
      when([ "HASH", "STASH" ]) {
         if( $type eq "STASH" ) {
            say '  stashname=' . $sv->stashname;
         }
         foreach my $key ( sort $sv->keys ) {
            my $v = $sv->value($key);
            say $v ?  "  {$key}=" . $v->desc_addr : "  {$key} undef";
         }
      }
      when( "CODE" ) {
         say $sv->name    ? "  name=" . $sv->name : "  no name";
         say $sv->stash   ? "  stash=" . $sv->stash->desc_addr : "  no stash";
         say $sv->glob    ? "  glob="  . $sv->glob->desc_addr  : "  no glob";
         say                "  location=" . $sv->location;
         say $sv->scope   ? "  scope=" . $sv->scope->desc_addr : "  no scope";
         say $sv->padlist ? "  padlist=" . $sv->padlist->desc_addr : "  no padlist";
         say $sv->padnames ? "  padnames=" . $sv->padnames->desc_addr : "  no padnames";

         my @pads = $sv->pads;
         foreach my $depth ( 0 .. $#pads ) {
            next unless $pads[$depth];
            say "  pad[$depth]=" . $pads[$depth]->desc_addr;
         }

         if( my @globs = $sv->globrefs ) {
            say "Referenced globs:";
            say "  " . join( ", ", map { $_->desc_addr } @globs );
         }
      }
      when( "PADNAMES" ) {
         say $sv->padcv ? "  padcv=" . $sv->padcv->desc_addr : "  no padcv";

         my @elems = $sv->elems;
         # Every PADNAMES element is either NULL or a SCALAR(PV)
         # PADIX 0 is always @_
         foreach my $padix ( 1 .. $#elems ) {
            my $slot = $elems[$padix];
            if( $slot and $slot->type eq "SCALAR" ) {
               say "  [$padix] is " . $slot->pv;
            }
            else {
               say "  [$padix] unused";
            }
         }
      }
      when( "PAD" ) {
         my $padcv = $sv->padcv;
         say $padcv ? "  padcv=" . $padcv->desc_addr : "  no padcv";

         my @elems = $sv->elems;
         my @padnames = map { $padcv->padname( $_ ) } 0 .. $#elems;
         my $maxname = max map { defined $_ ? length $_ : 0 } @padnames;

         my %padtype;
         if( my $gvix = $padcv->{gvix} ) {
            $padtype{$_} = "GLOB" for @$gvix;
         }
         if( my $constix = $padcv->{constix} ) {
            $padtype{$_} = "CONST" for @$constix;
         }

         foreach my $padix ( 1 .. $#elems ) {
            my $padsv = $elems[$padix];
            if( $padnames[$padix] ) {
               printf "  [%3d/%*s]=%s\n", $padix, $maxname, $padnames[$padix],
                  $padsv ? $padsv->desc_addr : "NULL";
            }
            else {
               printf "  [%3d %*s]=%s\n", $padix, $maxname,
                  $padtype{$padix} // "",
                  $padsv ? $padsv->desc_addr : "NULL";
            }
         }
      }
   }
}

my $df = Devel::MAT->load( $ARGV[0] // die "Need dumpfile\n" )->dumpfile;

my $addr = $ARGV[1] // die "Need addr\n";
$addr = $df->defstash->addr if $addr eq "defstash";
$addr = hex $addr if $addr =~ m/^0x/;

my $sv = $df->sv_at( $addr );
$sv or die sprintf "No SV at %#x\n", $addr;

show_sv( $sv );