home *** CD-ROM | disk | FTP | other *** search
- # Disassembler.pm
- #
- # Copyright (c) 1996 Malcolm Beattie
- #
- # You may distribute under the terms of either the GNU General Public
- # License or the Artistic License, as specified in the README file.
- package B::Disassembler::BytecodeStream;
-
- our $VERSION = '1.01';
-
- use FileHandle;
- use Carp;
- use Config qw(%Config);
- use B qw(cstring cast_I32);
- @ISA = qw(FileHandle);
- sub readn {
- my ($fh, $len) = @_;
- my $data;
- read($fh, $data, $len);
- croak "reached EOF while reading $len bytes" unless length($data) == $len;
- return $data;
- }
-
- sub GET_U8 {
- my $fh = shift;
- my $c = $fh->getc;
- croak "reached EOF while reading U8" unless defined($c);
- return ord($c);
- }
-
- sub GET_U16 {
- my $fh = shift;
- my $str = $fh->readn(2);
- croak "reached EOF while reading U16" unless length($str) == 2;
- return unpack("S", $str);
- }
-
- sub GET_NV {
- my $fh = shift;
- my ($str, $c);
- while (defined($c = $fh->getc) && $c ne "\0") {
- $str .= $c;
- }
- croak "reached EOF while reading double" unless defined($c);
- return $str;
- }
-
- sub GET_U32 {
- my $fh = shift;
- my $str = $fh->readn(4);
- croak "reached EOF while reading U32" unless length($str) == 4;
- return unpack("L", $str);
- }
-
- sub GET_I32 {
- my $fh = shift;
- my $str = $fh->readn(4);
- croak "reached EOF while reading I32" unless length($str) == 4;
- return unpack("l", $str);
- }
-
- sub GET_objindex {
- my $fh = shift;
- my $str = $fh->readn(4);
- croak "reached EOF while reading objindex" unless length($str) == 4;
- return unpack("L", $str);
- }
-
- sub GET_opindex {
- my $fh = shift;
- my $str = $fh->readn(4);
- croak "reached EOF while reading opindex" unless length($str) == 4;
- return unpack("L", $str);
- }
-
- sub GET_svindex {
- my $fh = shift;
- my $str = $fh->readn(4);
- croak "reached EOF while reading svindex" unless length($str) == 4;
- return unpack("L", $str);
- }
-
- sub GET_pvindex {
- my $fh = shift;
- my $str = $fh->readn(4);
- croak "reached EOF while reading pvindex" unless length($str) == 4;
- return unpack("L", $str);
- }
-
- sub GET_strconst {
- my $fh = shift;
- my ($str, $c);
- $str = '';
- while (defined($c = $fh->getc) && $c ne "\0") {
- $str .= $c;
- }
- croak "reached EOF while reading strconst" unless defined($c);
- return cstring($str);
- }
-
- sub GET_pvcontents {}
-
- sub GET_PV {
- my $fh = shift;
- my $str;
- my $len = $fh->GET_U32;
- if ($len) {
- read($fh, $str, $len);
- croak "reached EOF while reading PV" unless length($str) == $len;
- return cstring($str);
- } else {
- return '""';
- }
- }
-
- sub GET_comment_t {
- my $fh = shift;
- my ($str, $c);
- while (defined($c = $fh->getc) && $c ne "\n") {
- $str .= $c;
- }
- croak "reached EOF while reading comment" unless defined($c);
- return cstring($str);
- }
-
- sub GET_double {
- my $fh = shift;
- my ($str, $c);
- while (defined($c = $fh->getc) && $c ne "\0") {
- $str .= $c;
- }
- croak "reached EOF while reading double" unless defined($c);
- return $str;
- }
-
- sub GET_none {}
-
- sub GET_op_tr_array {
- my $fh = shift;
- my @ary = unpack("S256", $fh->readn(256 * 2));
- return join(",", @ary);
- }
-
- sub GET_IV64 {
- my $fh = shift;
- my ($hi, $lo) = unpack("LL", $fh->readn(8));
- return sprintf("0x%x%08x", $hi, $lo); # cheat
- }
-
- sub GET_IV {
- $Config{ivsize} == 4 ? &GET_I32 : &GET_IV64;
- }
-
- package B::Disassembler;
- use Exporter;
- @ISA = qw(Exporter);
- @EXPORT_OK = qw(disassemble_fh get_header);
- use Carp;
- use strict;
-
- use B::Asmdata qw(%insn_data @insn_name);
-
- our( $magic, $archname, $blversion, $ivsize, $ptrsize, $byteorder );
-
- sub dis_header($){
- my( $fh ) = @_;
- $magic = $fh->GET_U32();
- warn( "bad magic" ) if $magic != 0x43424c50;
- $archname = $fh->GET_strconst();
- $blversion = $fh->GET_strconst();
- $ivsize = $fh->GET_U32();
- $ptrsize = $fh->GET_U32();
- $byteorder = $fh->GET_strconst();
- }
-
- sub get_header(){
- return( $magic, $archname, $blversion, $ivsize, $ptrsize, $byteorder );
- }
-
- sub disassemble_fh {
- my ($fh, $out) = @_;
- my ($c, $getmeth, $insn, $arg);
- bless $fh, "B::Disassembler::BytecodeStream";
- dis_header( $fh );
- while (defined($c = $fh->getc)) {
- $c = ord($c);
- $insn = $insn_name[$c];
- if (!defined($insn) || $insn eq "unused") {
- my $pos = $fh->tell - 1;
- die "Illegal instruction code $c at stream offset $pos\n";
- }
- $getmeth = $insn_data{$insn}->[2];
- $arg = $fh->$getmeth();
- if (defined($arg)) {
- &$out($insn, $arg);
- } else {
- &$out($insn);
- }
- }
- }
-
- 1;
-
- __END__
-
- =head1 NAME
-
- B::Disassembler - Disassemble Perl bytecode
-
- =head1 SYNOPSIS
-
- use Disassembler;
-
- =head1 DESCRIPTION
-
- See F<ext/B/B/Disassembler.pm>.
-
- =head1 AUTHOR
-
- Malcolm Beattie, C<mbeattie@sable.ox.ac.uk>
-
- =cut
-