1# Disassembler.pm 2# 3# Copyright (c) 1996 Malcolm Beattie 4# 5# You may distribute under the terms of either the GNU General Public 6# License or the Artistic License, as specified in the README file. 7package B::Disassembler::BytecodeStream; 8 9our $VERSION = '1.03'; 10 11use FileHandle; 12use Carp; 13use Config qw(%Config); 14use B qw(cstring cast_I32); 15@ISA = qw(FileHandle); 16sub readn { 17 my ($fh, $len) = @_; 18 my $data; 19 read($fh, $data, $len); 20 croak "reached EOF while reading $len bytes" unless length($data) == $len; 21 return $data; 22} 23 24sub GET_U8 { 25 my $fh = shift; 26 my $c = $fh->getc; 27 croak "reached EOF while reading U8" unless defined($c); 28 return ord($c); 29} 30 31sub GET_U16 { 32 my $fh = shift; 33 my $str = $fh->readn(2); 34 croak "reached EOF while reading U16" unless length($str) == 2; 35 return unpack("S", $str); 36} 37 38sub GET_NV { 39 my $fh = shift; 40 my ($str, $c); 41 while (defined($c = $fh->getc) && $c ne "\0") { 42 $str .= $c; 43 } 44 croak "reached EOF while reading double" unless defined($c); 45 return $str; 46} 47 48sub GET_U32 { 49 my $fh = shift; 50 my $str = $fh->readn(4); 51 croak "reached EOF while reading U32" unless length($str) == 4; 52 return unpack("L", $str); 53} 54 55sub GET_I32 { 56 my $fh = shift; 57 my $str = $fh->readn(4); 58 croak "reached EOF while reading I32" unless length($str) == 4; 59 return unpack("l", $str); 60} 61 62sub GET_objindex { 63 my $fh = shift; 64 my $str = $fh->readn(4); 65 croak "reached EOF while reading objindex" unless length($str) == 4; 66 return unpack("L", $str); 67} 68 69sub GET_opindex { 70 my $fh = shift; 71 my $str = $fh->readn(4); 72 croak "reached EOF while reading opindex" unless length($str) == 4; 73 return unpack("L", $str); 74} 75 76sub GET_svindex { 77 my $fh = shift; 78 my $str = $fh->readn(4); 79 croak "reached EOF while reading svindex" unless length($str) == 4; 80 return unpack("L", $str); 81} 82 83sub GET_pvindex { 84 my $fh = shift; 85 my $str = $fh->readn(4); 86 croak "reached EOF while reading pvindex" unless length($str) == 4; 87 return unpack("L", $str); 88} 89 90sub GET_strconst { 91 my $fh = shift; 92 my ($str, $c); 93 $str = ''; 94 while (defined($c = $fh->getc) && $c ne "\0") { 95 $str .= $c; 96 } 97 croak "reached EOF while reading strconst" unless defined($c); 98 return cstring($str); 99} 100 101sub GET_pvcontents {} 102 103sub GET_PV { 104 my $fh = shift; 105 my $str; 106 my $len = $fh->GET_U32; 107 if ($len) { 108 read($fh, $str, $len); 109 croak "reached EOF while reading PV" unless length($str) == $len; 110 return cstring($str); 111 } else { 112 return '""'; 113 } 114} 115 116sub GET_comment_t { 117 my $fh = shift; 118 my ($str, $c); 119 while (defined($c = $fh->getc) && $c ne "\n") { 120 $str .= $c; 121 } 122 croak "reached EOF while reading comment" unless defined($c); 123 return cstring($str); 124} 125 126sub GET_double { 127 my $fh = shift; 128 my ($str, $c); 129 while (defined($c = $fh->getc) && $c ne "\0") { 130 $str .= $c; 131 } 132 croak "reached EOF while reading double" unless defined($c); 133 return $str; 134} 135 136sub GET_none {} 137 138sub GET_op_tr_array { 139 my $fh = shift; 140 my $len = unpack "S", $fh->readn(2); 141 my @ary = unpack "S*", $fh->readn($len*2); 142 return join(",", $len, @ary); 143} 144 145sub GET_IV64 { 146 my $fh = shift; 147 my $str = $fh->readn(8); 148 croak "reached EOF while reading I32" unless length($str) == 8; 149 return sprintf "0x%09llx", unpack("q", $str); 150} 151 152sub GET_IV { 153 $Config{ivsize} == 4 ? &GET_I32 : &GET_IV64; 154} 155 156sub B::::GET_PADOFFSET { 157 $Config{ptrsize} == 8 ? &B::GET_IV64 : &B::GET_U32; 158} 159 160sub B::::GET_long { 161 $Config{longsize} == 8 ? &B::GET_IV64 : &B::GET_U32; 162} 163 164 165package B::Disassembler; 166use Exporter; 167@ISA = qw(Exporter); 168@EXPORT_OK = qw(disassemble_fh get_header); 169use Carp; 170use strict; 171 172use B::Asmdata qw(%insn_data @insn_name); 173 174our( $magic, $archname, $blversion, $ivsize, $ptrsize ); 175 176sub dis_header($){ 177 my( $fh ) = @_; 178 $magic = $fh->GET_U32(); 179 warn( "bad magic" ) if $magic != 0x43424c50; 180 $archname = $fh->GET_strconst(); 181 $blversion = $fh->GET_strconst(); 182 $ivsize = $fh->GET_U32(); 183 $ptrsize = $fh->GET_U32(); 184} 185 186sub get_header(){ 187 return( $magic, $archname, $blversion, $ivsize, $ptrsize); 188} 189 190sub disassemble_fh { 191 my ($fh, $out) = @_; 192 my ($c, $getmeth, $insn, $arg); 193 bless $fh, "B::Disassembler::BytecodeStream"; 194 dis_header( $fh ); 195 while (defined($c = $fh->getc)) { 196 $c = ord($c); 197 $insn = $insn_name[$c]; 198 if (!defined($insn) || $insn eq "unused") { 199 my $pos = $fh->tell - 1; 200 die "Illegal instruction code $c at stream offset $pos\n"; 201 } 202 $getmeth = $insn_data{$insn}->[2]; 203 $arg = $fh->$getmeth(); 204 if (defined($arg)) { 205 &$out($insn, $arg); 206 } else { 207 &$out($insn); 208 } 209 } 210} 211 2121; 213 214__END__ 215 216=head1 NAME 217 218B::Disassembler - Disassemble Perl bytecode 219 220=head1 SYNOPSIS 221 222 use Disassembler; 223 224=head1 DESCRIPTION 225 226See F<ext/B/B/Disassembler.pm>. 227 228=head1 AUTHOR 229 230Malcolm Beattie, C<mbeattie@sable.ox.ac.uk> 231 232=cut 233