Documentation

dumpopo

  1. Usage
  2. Overview
  3. Decode support
  4. Decompilation

Usage

Syntax: dumpopo.lua <filename>|--stdin [options] [<procName> [<startAddr>]]

Prints information about the specified OPO (compiled OPL) file.

If just a filename is specified, prints information about the file and all the
procedures it contains. With --all or a <procName>, prints an assembly listing
of all procedures or the specified procedure, respectively. The <startAddr>
argument can be used to skip over some amount of the procedure code, which can
be useful when debugging code using obfuscation techniques.

Options:

    --all, -a
        Prints assembly listing of all procedures, if neither <procName> or
        --decompile is specified.

    --decompile, -d
        Convert the compiled code back to OPL source code and print to stdout.
        Decompiles all procedures unless <procName> is specified.

    --annotate, -t
        In addition to setting the annotate and show-elided options (see below),
        also prefixes each line with the address of the start of the first
        statement on that line.

    --name <proc>:<name>=<newname>
        Manually specify a name for a local in the given proc. Can be used
        multiple times for multiple variables. For example to rename local_00AC%
        to event% in the MAIN proc, specify --name MAIN:local_00AC=event. Has
        no effect unless --decompile is specified.

    --aif <path>, -i <path>
        Adds an APP...ENDA block to the decompile output based on the given AIF
        file.

    --stdin
        Read from stdin rather than a file. <filename> must not be specified.

    --option <opt>, -o <opt>
        Pass an option to the decompiler to customise its output.
        Options include:
            annotate
                Adds comments about inferred block structure.
            show-elided
                Add comments for control statements that are normally not
                shown, such as implicit returns, and GOTOs that are part of
                block structures.
            no-elide
                Like show-elided, but leave the statements in place rather than
                commenting them.
            no-merge-prints
                Do not recombine print commands into compound print statements.
            no-breaks
                Do not convert GOTOs into BREAKs and CONTINUEs where applicable.
            no-elses
                Do not convert non-dropping-through IF...ENDIF into
                IF...ELSE...ENDIF. Implies no-elseifs.
            no-elseifs
                Do not combine ELSE + IF... into ELSEIF.
            no-whiles
                Do not convert applicable IF...ENDIF into WHILE...ENDWH. Due to
                the way ELSE blocks are calculated requiring the WHILE transform
                to have taken place, this option implies no-elses and
                no-elseifs.

Overview

Parses compiled-OPL programs, optionally decoding or decompiling the QCode.

For example, when run with no additional arguments, the structure of the file and the procedures it contains are listed. For example, when run on the very basic example program simple.opo:

$ ./bin/dumpopo.lua examples/Tests/simple.opo
UID2: 0x10000073
UID3: 0x10000168
translatorVersion: 0x200A minRunVersion: 0x200A
Source name: D:\Program
procTableIdx: 0x0000006B
1: TEST @ 0x0000001F code=0x00000036 size=0x00000018 line=0
    Subproc "WAT" offset=0x0012 nargs=0
    maxStack: 8
    iDataSize: 23 (0x00000017)
    iTotalTableSize: 5 (0x00000005)
2: WAT @ 0x0000004E code=0x00000060 size=0x0000000B line=6
    maxStack: 0
    iDataSize: 18 (0x00000012)
    iTotalTableSize: 0 (0x00000000)

Decode support

If a procedure name or --all is given, the procedure QCode is decoded:

$ ./bin/dumpopo.lua examples/Tests/simple.opo --all
UID2: 0x10000073
UID3: 0x10000168
translatorVersion: 0x200A minRunVersion: 0x200A
Source name: D:\Program
procTableIdx: 0x0000006B
1: TEST @ 0x0000001F code=0x00000036 size=0x00000018 line=0
    Subproc "WAT" offset=0x0012 nargs=0
    maxStack: 8
    iDataSize: 23 (0x00000017)
    iTotalTableSize: 5 (0x00000005)
00000036: 2B [ConstantString] "Hello world!"
00000044: 8B [PrintString]
00000045: 92 [PrintCarriageReturn]
00000046: 53 [RunProcedure] 0x0012 (name="WAT" nargs=0)
00000049: 82 [DropFloat]
0000004A: 57 [CallFunction] 0x0A (Get)
0000004C: 80 [DropInt]
0000004D: 76 [ZeroReturnFloat]
2: WAT @ 0x0000004E code=0x00000060 size=0x0000000B line=6
    maxStack: 0
    iDataSize: 18 (0x00000012)
    iTotalTableSize: 0 (0x00000000)
00000060: 2B [ConstantString] "Waaaat"
00000068: 8B [PrintString]
00000069: 92 [PrintCarriageReturn]
0000006A: 76 [ZeroReturnFloat]

Decompilation

If --decompile is given, an attempt is made to convert the QCode back to OPL source code. While the OPL compiler is not hugely complex, not all information is preserved so the source code is unlikely to be identical to the original - in particular, names of local variables are thrown away by the compiler so the decompiler will generate new names for them based on their location in the procedure. In the case of simple.opo which has no variables or complex flow control, the output is very close to the original:

$ ./bin/dumpopo.lua examples/Tests/simple.opo --decompile
PROC TEST:
    PRINT "Hello world!"
    WAT:
    GET
ENDP

PROC WAT:
    PRINT "Waaaat"
ENDP