Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 087e6c4d7d
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 351 lines (302 sloc) 10.238 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
// 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)));
    }
}
Something went wrong with that request. Please try again.