gida is a tracing disassembler written in C++.
GIDA can only code for the MOS Technology 6800 CPU for which it
- finds code that is probably executed
- recognises subroutines
Try gida with the ROM, ripped from an ancient coke machine:
# gida -6800 rom.bin <rom.conf >rom.asm
Enjoy!
Support for the MOS Technology 6502 CPU is under contruction.
gida uses the GNU autotools to get built and installed. Accordingly, you need to have autoconf and automake installed.
autoreconf -i
automake --add-missing
./configure
make
Binaries are traced to set up a list of 'vchunk's. Each vchunk contains a code or data address, an optional user-defined name for its label, and a pointer to a dumper (derived from 'vdump'). A vsegment holds all chunks of a binary and guarantees that they're sorted in ascending order by their starting addresses and that consequent chunks leave no gaps.
If the binary was traced, the dump() function of each vchunk in the vsegment is called. Usually it invokes the dumper, the vchunk points to. There two dumpers for code and data which are invoked when vchunk::dump() is called. vchunk::dump is overloaded by 'vsubroutine' and 'vgap' to print extra comments.
The vchunk class provides machine independent function to test and trace chunks.
You must add a new virtual CPU to support a new processor. A vcpu generates a 'vop's of particular instructions or inserts new 'vchunk's a traced instruction accesses. Additionally it must be able to insert new vchunks to a segment if an instruction accesses it. Finally, a cpu must be able to generate intermediate instruction object (vop's).
The vprint interface is used by vdump objects to output diassemblies. vprint provides functions to print code, data, labels, constants, comments and red tape in a particular format vdump doesn't need to know of.
If you want to implement new CPU supprt, see the vop.h and vcpu.h files for starters.
!!!!!!!!!! FOLLOWING IS JUST PLANNED STUFF !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Backtracing code is needed to recognize register arguments and jump tables. The virtual cpu needs to create a intermediate description of the operation it performs. A description is made from virtual operation objects that are linked to trees that can be traversed and executed.
Let's take a look at the following real life example that needs recovery of a jump table's address:
chunkstart:
ASLA ; Multiply by two for word alignment.
LDX #D_9081 ; Load base of jump table.
JSR add_xa ; Add index to base.
LDX D_0000,X ; Get address of jump.
JMP D_0000,X ; Jump.
; ### SUBROUTINE #############################################
;
; Add A to X and store result in X.
add_xa: ; XREFS: 8b99 8d7f 8dbf 8ddd 8ded 8e44 8e86 8e96 8eb3 8f24 8f4b 8f81 902f 9046 9063 93bc 97fe 9978 999a 99d7 99f9 a529 c937 d0e1 e0be e116
CLRB
STX D_0248
ADDA D_0249
ADCB D_0248
STAA D_0249
STAB D_0248
LDX D_0248
RTS
; ### DATA ###########################################
D_9081: ; XREFS: 9043
FCB $90, $8d, $91
FCC "8"
...
From the perspective of the disassembler the first problem occurs at the first LDX instruction which loads X with a value taken from a memory location at an unknown address. It now needs to backtrace all former instructions until a code label is reached or all source values to calculate X is known. For simplicity let's assume that all vops are already built and we have the following operations:
vassign (®_a, vconstant (0));
chunkstart:
vop_shiftl (®_a, vconstant (1));
vop_assign (®_x, vconstant (0x9081));
vassign (®_s, ®_pc);
vop_sub (®_s, ®_s, vconstant (2));
vop_assign (®_pc, vconstant (add_ax));
add_ax:
vop_assign (®_b, vconstant (0), VR_BYTE);
vop_assign (vref (0x0248, VR_WORD), ®_x);
a = vop_add (®_a, &carry_flag, vref (0x0249, VR_BYTE), ®_a);
vop_addc (®_b, 0, vref (0x0248, VR_BYTE), ®_b, $carry_flag);
vop_assign (vref (0x0249, VR_WORD), ®_a);
vop_assign (vref (0x0248, VR_WORD), ®_b);
vop_assign (®_x, vref (0x0248, VR_WORD));
vop_add (®_s, ®_s, vconstant (2));
vassign (®_pc, ®_s);
vop_assign (®_pc, vref (vconstant (0), ®_x), VR_WORD);
vop_assign (®_pc, vref (vconstant (0), ®_x), VR_WORD);
The operations were constructed the way shown above by the virtual cpu. Register objects were constructed before while new objects for constants and memory locations were created. There is no relationship between a memory location and the last instruction that assigned a value to it. To get that information, the set of vops is traversed and the accessed references are linked to each other using a scoreboard algorithm.