Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Branch: master
Fetching contributors…

Cannot retrieve contributors at this time

351 lines (302 sloc) 10.238 kB
// Copyright (C) 2011-2012, Parrot Foundation.
// Basic disassembler to demonstrate the PACT.Packfile classes
// Load disassembler
$include 'PACT/Packfile/Decompile.winxed';
$load 'PACT/Packfile/Decompile.pbc';
// Constants needed for later
$include_const 'call_bits.pasm';
$include_const 'hash_key_type.pasm';
// Useful opcode for displaying novel PMC types
inline get_repr(var v) return string {
string ret;
${ get_repr ret, v };
return ret;
}
function main[main](var argv) {
// Process arguments
string progname = argv[0];
if (elements(argv) != 2) {
cry('Usage: ', progname, ' <PBC file>');
exit(1);
}
string filename = argv[1];
// Get a PACT.Packfile
var packfile;
try {
:PACT.Packfile.Decompile decomp(filename);
packfile = decomp.pact;
} catch (e) {
cry( progname, ': Error during disassembly ', filename );
cry( e.message );
for ( string bt in e.backtrace_strings() )
cry(bt);
exit(1);
}
// Version number
say(".pact pbc 0\n");
// Generic variables for later
int i;
string s;
var v;
var vi;
// Float Constants
say('.constants num');
v = packfile.floats;
for (i = 0; i < elements(v); ++i)
say(i, ' ', v[i]);
say(".end\n");
// String Constants
var sc_map = {}; // Map from string values to constant index
say('.constants string');
v = packfile.strings;
for (i = 0; i < elements(v); ++i) {
s = v[i];
print(string(i));
if(s == null) {
say(' # null');
} else {
say(' ', encoding_name(s), ' "', escape(s), '"');
sc_map[s] = i;
}
}
say(".end\n");
var sub_map = {}; // Map from Packfile.Subroutine to label name
// It needs to be keyed on PMC identity, not hash or string
sub_map.set_key_type(Hash_key_type_PMC_ptr);
// PMC Constants
say('.constants pmc');
v = packfile.pmcs;
for (i = 0; i < elements(v); ++i) {
vi = v[i];
print(i, ' ');
switch(typeof(vi)) {
case 'PACT;Packfile;Subroutine': // print: label, name, options
// Generate and store a label
sub_map[vi] = s = '_sub' + string(i);
print('Sub ', s, ', sc', sc_map[vi.name]);
// TODO: main, tags, subid, etc
// Handle a multi signature
if (vi.multi_sig != null) {
print(', multi (');
int comma = 0;
for (var arg in vi.multi_sig) {
if (comma)
print(', ');
else
comma = 1;
switch(typeof(arg)) {
case 'Integer':
switch(int(arg)) {
case -1: print('i'); break;
case -2: print('f'); break;
case -3: print('s'); break;
case -4: print('p'); break;
default: print(arg); break; // XXX: What is this?
}
break;
case 'String':
print('sc', sc_map[arg]);
break;
default:
die('Unexpected type in multi_sig');
}
}
print(')');
}
say();
break;
case 'PACT;Packfile;Constant;Key': // print key contents
print('Key [ ');
int comma = 0;
for (var arg in vi.value) {
if (comma)
print(', ');
else
comma = 1;
// Key contents are similar to opcode arguments
show_argument(sc_map, arg);
}
say(' ]');
break;
default: // type, repr
print(typeof(vi), ' ');
// Try to show something
try {
say(get_repr(vi)); // repr first
} catch() {
try {
say(string(vi)); // string conversion
} catch() {
say('(Unprintable)'); // Give up
}
}
}
}
say(".end\n");
// Oplibs
for (s in packfile.oplibs)
if (s != 'core_ops')
say('.oplib ', s);
// Subs
show_namespace(sub_map, sc_map, packfile.root);
}
// Display the path for a namespace
function name_namespace(var path) {
// Print the path to the new namespace
print('.namespace sc');
print(path[0]);
for(int i = 1; i < elements(path); ++i) {
print(', sc');
print(path[i]);
}
say("\n"); // Yes, two newlines
}
// Show the contents of a namespace
// Arguments:
// sub_map = Hash: PACT.Packfile.Subroutine -> String label
// sc_map = Hash: String -> Constant index
// ns = PACT.Packfile.Namespace: thing to print
// path = Path from root to current namespace (default nothing)
// RPA: Integers for string constants
function show_namespace(var sub_map, var sc_map, var ns, var path = []) {
for (string s in ns.contents) {
var v = ns.contents[s];
switch(typeof(v)) {
case 'PACT;Packfile;Subroutine':
say('.sub ', sub_map[v]); // Show the label
show_sub(sc_map, v); // Then show the sub itself
say('.end');
say();
break;
case 'PACT;Packfile;Namespace':
push(path, sc_map[s]); // Update and the path
name_namespace(path);
show_namespace(sub_map, sc_map, v, path);
pop_var(path); // Restore and print the path
name_namespace(path);
break;
case 'PACT;Packfile;Multi':
// Just iterate over the canidates
for(var sub in v.canidates) {
say('.sub ', sub_map[sub]);
show_sub(sc_map, sub);
say('.end');
say();
}
break;
default:
die('Object of unexpected type (' + string(typeof(v))
+ ') found in namespace');
}
}
}
// Print out the contents of a subroutine
// sc_map = Hash: string to constant index
// sub = PACT.Packfile.Subroutine to print
function show_sub(var sc_map, var sub) {
string label;
for(var op in sub.ops) {
switch(typeof(op)) {
case 'PACT;Packfile;Debug':
say('.debug sc', sc_map[op.filename]);
break;
case 'PACT;Packfile;Annotation':
print('.annotate sc', sc_map[op.name], ', ');
var c = op.value;
// Annotation values can be integers or strings
switch(typeof(c)) {
case 'PACT;Packfile;Constant;Reference':
if(c.type != PARROT_ARG_STRING)
die("Unexpected annotation constant reference type " +
c.type);
say('sc', c.value);
break;
case 'PACT;Packfile;Constant':
switch(c.type) {
case PARROT_ARG_INTVAL:
say(c.value);
break;
case PARROT_ARG_STRING:
say('sc', sc_map[c.value]);
break;
default:
die("Unexpected annotation constant type " + c.type);
}
break;
default:
die("Unexpected annotation value type " + string(typeof(c)));
}
break;
case 'PACT;Packfile;Label':
// If we already found a label, print it
if (label != null)
say(label, ':');
// Store short labels to print before opcode
if (length(op.name) < 7) { // 7 == 8 tabstop - ':'
label = op.name;
} else {
// Print long ones immediately
label = null;
say(op.name, ':');
}
break;
case 'PACT;Packfile;Op':
// If we have a short label, print it
if (label != null)
print(label, ':');
label = null;
print("\t", op.name);
var args = op.args;
for(int i = 0; i < elements(args); ++i) {
print( i == 0 ? ' ' : ', ' );
show_argument(sc_map, args[i]);
}
say();
break;
default:
die("Unknown sub contents type " + string(typeof(op)));
}
}
}
// Display the argument for an opcode or key
// sc_map = Hash: string to constant index
// arg = argument to print
// should be a constant or register
function show_argument(var sc_map, var arg) {
switch(typeof(arg)) {
case 'PACT;Packfile;Constant;Reference':
switch(arg.type) {
case PARROT_ARG_INTVAL: die('Integer reference?');
case PARROT_ARG_STRING: print('sc'); break;
case PARROT_ARG_PMC: print('pc'); break;
case PARROT_ARG_FLOATVAL: print('fc'); break;
default: die('Unknown constref type ' + string(arg.type));
}
print(arg.value);
break;
case 'PACT;Packfile;Constant':
switch(arg.type) {
case PARROT_ARG_INTVAL:
print(arg.value);
break;
case PARROT_ARG_STRING:
print('sc', string(sc_map[arg.value]));
break;
default:
die('Unexpected constant type ' + string(arg.type));
}
break;
case 'PACT;Packfile;Register':
switch(arg.type) {
case PARROT_ARG_INTVAL: print('i'); break;
case PARROT_ARG_STRING: print('s'); break;
case PARROT_ARG_PMC: print('p'); break;
case PARROT_ARG_FLOATVAL: print('f'); break;
default: die('Unknown register type ' + string(arg.type));
}
print(arg.number);
break;
default:
die('Unknown argument type ' + string(typeof(arg)));
}
}
Jump to Line
Something went wrong with that request. Please try again.