ysth asked me on IRC to comment on your question. I've done a whole
pile of stuff "disassembling" compiled perl and stuff (just see my
CPAN page [http://search.cpan.org/~jjore]).
Perl compiles your source to a tree of OP*
structs which
occasionally have C pointers to SV*
which are perl values. Your core
dump now has a bunch of those OP*
and SV*
stashed.
The best possible world would be to have a perl module like
B::Deparse do the information-understanding work for you. It
works by using a light interface to perl memory in the B::OP
and
B::SV
classes (documented in B, perlguts, and
perlhack). This is unrealistic for you because a B::*
object is
just a pointer into memory with accessors to decode the struct for our
use. Consider:
require Data::Dumper;
require Scalar::Util;
require B;
my $value = 'this is a string';
my $sv = B::svref_2object( \ $value );
my $address = Scalar::Util::refaddr( \ $value );
local $Data::Dumper::Sortkeys = 1;
local $Data::Dumper::Purity = 1;
print Data::Dumper::Dumper(
{
address => $address,
value => \ $value,
sv => $sv,
sv_attr => {
CUR => $sv->CUR,
LEN => $sv->LEN,
PV => $sv->PV,
PVBM => $sv->PVBM,
PVX => $sv->PVX,
as_string => $sv->as_string,
FLAGS => $sv->FLAGS,
MAGICAL => $sv->MAGICAL,
POK => $sv->POK,
REFCNT => $sv->REFCNT,
ROK => $sv->ROK,
SvTYPE => $sv->SvTYPE,
object_2svref => $sv->object_2svref,
},
}
);
which when run showed that the B::PV
object (it is ISA B::SV
) is
truely merely an interface to the memory representation of the
compiled string this is a string
.
$VAR1 = {
'address' => 438506984,
'sv' => bless( do{\(my $o = 438506984)}, 'B::PV' ),
'sv_attr' => {
'CUR' => 16,
'FLAGS' => 279557,
'LEN' => 24,
'MAGICAL' => 0,
'POK' => 1024,
'PV' => 'this is a string',
'PVBM' => 'this is a string',
'PVX' => 'this is a string',
'REFCNT' => 2,
'ROK' => 0,
'SvTYPE' => 5,
'as_string' => 'this is a string',
'object_2svref' => \'this is a string'
},
'value' => do{my $o}
};
$VAR1->{'value'} = $VAR1->{'sv_attr'}{'object_2svref'};
This however implies that any B::*
using code must actually operate
on live memory. Tye McQueen thought he remembered a C debugger which
could fully revive a working process given a core dump. My gdb
can't. gdb
can allow you to dump the contents of your OP*
and
SV*
structs. You would most likely just read the dumped structs to
interpret your program's structure. You could, if you wished, use
gdb
to dump the structs, then synthetically create B::*
objects
which behaved in interface as if they were ordinary and use
B::Deparse
on that. At root, our deparser and other debug dumping
tools are mostly object oriented so you could just "fool" them by
creating a pile of fake B::*
classes and objects.
You may find reading the B::Deparse class's coderef2text
method
instructive. It accepts a function reference, casts it to a B::CV
object, and uses that for input to the deparse_sub
method:
require B;
require B::Deparse;
sub your_function { ... }
my $cv = B::svref_2object( \ &your_function );
my $deparser = B::Deparse->new;
print $deparser->deparse_sub( $cv );
For gentler introductions to OP*
and related ideas, see the updated
PerlGuts Illustrated and Optree guts.