|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T d
Length: 11180 (0x2bac) Types: TextFile Names: »disasm.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit └─⟦3f75c1919⟧ »EurOpenD3/utils/decomp.tar.Z« └─⟦510c4d5ee⟧ └─⟦this⟧ »decomp/disasm.c«
/* * Module: disasm.c * * Author: J. Reuter * * This module "disassembles" a function into pseudo-C code * for data manipulation and pseudo-assembler code for all * conditional test and branch instructions. It makes no * attempt to structure the code. * * This disassembler is used as a fallback when the fancy * structuring code breaks. This does not happen very often * with PCC output. Occasionally the Unix peephole optimizer will * combine the last bits of code for several functions, causing * the structuring code to break. */ #include "defs.h" #include "machine.h" #include "labeltab.h" #include "objfile.h" #include "vartab.h" extern char *typesuf[]; static struct operand { int op_argval; int op_indexed; int op_index_rn; int op_index_type; char opstring[40]; } operand[6]; disasm( addr, end_addr ) address addr, end_addr; { struct opcode *op; VaxOpcode ins; address insaddr; unsigned char mode; int argtype, amode, argno, argval; int rn, type; short offset; struct nlist *s; char *str; struct llb *l; struct relocation_info *r; /* initialize pass */ l = llb_first(); relo_first(); r = relo_next(); /* the main loop */ while ( addr < end_addr ) { argval = 0; while ( l->l_address < addr ) l = llb_next(); if ( l != NULL && addr == l->l_address ) { if ( l->caselab ) printf( "C%04d:", addr ); else printf( "G%04d:", addr ); } ins = get_byte( addr ); addr += 1; op = &opcode[ins]; for (argno = 0; argno < op->numargs; argno++) operand[argno].op_indexed = FALSE; for (argno = 0; argno < op->numargs; argno++) { str = operand[argno].opstring; argtype = op->argtype[argno]; if (is_branch_disp(argtype)) { mode = 0xAF + ( (typelen(argtype) & ~T_UNSIGNED) << 4); } else { mode = get_byte( addr ); addr += 1; } while ( r != NULL && addr > r->r_address ) r = relo_next(); rn = regnm( mode ); type = typelen( argtype ); amode = addrmode(mode); if ( r != NULL && addr == r->r_address ) { if ( amode == LONGDISP || amode == LONGDISPDEF ) { argval = getdisp(addr, 4, rn, amode); addr += 4; } else if ( amode == AUTOINC ) { if ( rn != PC ) { printf( "ERR: strange relo autoinc reg\n" ); } else { /* immediate values */ switch ( type & ~T_UNSIGNED ) { case TYPL: argval = getdisp(addr, 4, rn, amode); addr += 4; break; default: printf( "ERR: strange relo autoinc %d\n", type ); break; } } } else { printf( "ERR: bad relo mode %d\n", amode ); } if ( r->r_extern ) { s = &symtab[r->r_symbolnum]; if ( s->n_type == (N_EXT+N_UNDF) ) { if ( amode == LONGDISP || amode == LONGDISPDEF ) { char *def; if ( amode == LONGDISPDEF ) { def = "*"; type |= T_POINTER; } else { def = ""; } if ( rn == PC ) sprintf( str, "%s%s", def, ext_sym( r->r_symbolnum, type, argval ) ); else sprintf( str, "%s%s(r%02d)", def, ext_sym( r->r_symbolnum, type, argval ), rn ); } else if ( amode == AUTOINC ) { sprintf( str, "%s", ext_sym( r->r_symbolnum, type, argval ) ); } else { printf( "ERR: ext relo mode %d\n", amode ); } } else { printf( "ERR: ext relo type %d\n", s->n_type ); } } else { /* not r->r_extern */ if ( amode == LONGDISP || amode == LONGDISPDEF ) { char *def; if ( amode == LONGDISPDEF ) { def = "*"; type |= T_POINTER; } else { def = ""; } if ( rn == PC ) { switch ( r->r_symbolnum ) { case 4: /* static function */ sprintf( str, "%s%s", def, int_sym( argval, type, C_TEXT ) ); break; case 5: /* global function */ sprintf( str, "%s%s", def, int_sym( argval, type, C_TEXT ) ); break; case 6: /* static data, const, string */ sprintf( str, "%s%s", def, int_sym( argval, type, C_DATA ) ); break; case 7: /* global data, const, string */ sprintf( str, "%s%s", def, int_sym( argval, type, C_DATA ) ); break; case 8: /* bss */ sprintf( str, "%s%s", def, int_sym( argval, type, C_BSS ) ); break; default: printf( "ERR: bad relo symbolnum %d\n", r->r_symbolnum ); break; } } else { /* other registers? */ sprintf( str, "%s%d(r%02d)", def, argval, rn ); printf( "\targ %d int longdisp sym#%d pcrel %d len %d reg %d\n", argno, r->r_symbolnum, r->r_pcrel, r->r_length, rn ); } } else if ( amode == AUTOINC ) { switch ( r->r_symbolnum ) { case 6: /* static data */ sprintf( str, "%s", int_sym( argval, type, C_DATA ) ); break; case 8: /* static bss */ sprintf( str, "%s", int_sym( argval, type, C_BSS ) ); break; default: printf( "ERR: auto relo symnum %d\n", r->r_symbolnum ); break; } } else { printf( "ERR: int relo mode %d\n", amode ); } } } else { /* no relo info */ switch (amode) { case LITSHORT: case LITUPTO31: case LITUPTO47: case LITUPTO63: if ( type == TYPF || type == TYPD ) sprintf( str, "%s", fltimm[mode] ); else sprintf( str, "%d", mode ); argval = mode; break; case INDEX: operand[argno].op_indexed = TRUE; operand[argno].op_index_rn = rn; operand[argno].op_index_type = T_LONG; argno--; break; case REG: sprintf( str, "%s", reg_sym( rn, type ) ); break; case REGDEF: sprintf( str, "*%s", reg_sym( rn, type | T_POINTER ) ); break; case AUTODEC: if ( rn == SP ) sprintf( str, "@arg@" ); else sprintf( str, "*(--%s)", reg_sym( rn, type | T_POINTER) ); break; case AUTOINC: if ( rn != PC ) { sprintf( str, "*%s++", reg_sym( rn, type | T_POINTER ) ); } else { /* immediate values */ switch ( type & ~T_UNSIGNED ) { case TYPB: argval = getdisp(addr, 1, rn, amode); addr += 1; break; case TYPW: argval = getdisp(addr, 2, rn, amode); addr += 2; break; case TYPL: argval = getdisp(addr, 4, rn, amode); addr += 4; break; default: printf( "ERR: strange-autoinc %d\n", type ); break; } sprintf( str, "%d", argval ); } break; case AUTOINCDEF: if ( rn == PC ) { /* immediate deferred */ argval = getdisp(addr, 4, rn, amode); addr += 4; sprintf( str, "*%d", argval ); } else { sprintf( str, "**(%s++)", reg_sym( rn, type | T_POINTER ) ); } break; case BYTEDISP: argval = getdisp(addr, 1, rn, amode); regdisp( rn, argval, type, FALSE, str ); addr += 1; break; case BYTEDISPDEF: ; argval = getdisp(addr, 1, rn, amode); regdisp( rn, argval, type, TRUE, str ); addr += 1; break; case WORDDISP: argval = getdisp(addr, 2, rn, amode); regdisp( rn, argval, type, FALSE, str ); addr += 2; break; case WORDDISPDEF: ; argval = getdisp(addr, 2, rn, amode); regdisp( rn, argval, type, TRUE, str ); addr += 2; break; case LONGDISP: argval = getdisp(addr, 4, rn, amode); regdisp( rn, argval, type, FALSE, str ); addr += 4; break; case LONGDISPDEF: ; argval = getdisp(addr, 4, rn, amode); regdisp( rn, argval, type, TRUE, str ); addr += 4; break; } } operand[argno].op_argval = argval; } /* print the decompiled instruction */ #define doindex( i ) if ( operand[i].op_indexed ) printf( "[%s]", \ reg_sym( operand[i].op_index_rn, operand[i].op_index_type ) ) switch( op->coptype ) { case MACRO: /* print macro code */ case COMP: case TEST: case BBRANCH: case CBRANCH: printf( "\t%s\t", op->cop1 ); for ( argno = 0; argno < op->numargs; argno++ ) { if ( argno != 0 ) printf( "," ); printf( "%s", operand[argno].opstring ); doindex(argno); } if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) { insaddr = addr; for (argno = 0; argno <= argval; argno++) { offset = get_word( addr ); addr += 2; printf( "\n\t\tC%04d", offset+insaddr ); } } printf( "\n" ); break; case A1OPA0: printf( "\t%s", operand[1].opstring ); doindex(1); printf( "%s", op->cop1 ); printf( "%s", operand[0].opstring ); doindex(0); printf( ";\n" ); break; case A2EQ1OP0: printf( "\t%s", operand[2].opstring ); doindex(2); printf( " = %s", operand[1].opstring ); doindex(1); printf( "%s", op->cop1 ); printf( "%s", operand[0].opstring ); doindex(0); printf( ";\n" ); break; case A0OP: printf( "\t%s", operand[0].opstring ); doindex(0); printf( "%s;\n", op->cop1 ); break; case OPONLY: printf( "\t%s;\n", op->cop1 ); break; case CALLS: printf( "\t@val@ = %s", operand[1].opstring ); doindex(1); printf( "( @%s args@ );\n", operand[0].opstring ); break; case PUSH: printf( "\t@arg@ = %s", operand[0].opstring ); doindex(0); printf( ";\n" ); break; case PUSHA: printf( "\t@arg@ = &%s", operand[0].opstring ); doindex(0); printf( ";\n" ); break; case EXTZV: printf( "\t%s", operand[3].opstring ); doindex(3); printf( " = " ); if ( operand[0].op_argval != 0 ) { printf( "( %s", operand[2].opstring ); doindex(2); printf( " >> %d )", operand[0].op_argval ); } else { printf( "%s", operand[2].opstring ); doindex(2); } if ( operand[1].op_argval != 32 ) printf( " & 0x%x;\n", 0x7fffffff >> ( 31 - operand[1].op_argval ) ); else printf( ";\n" ); } } } /* * Print the displacement of an instruction that uses displacement * addressing. */ static int getdisp(addr, nbytes, rn, mode) address addr; int nbytes; int rn; int mode; { int argval; switch (nbytes) { case 1: argval = get_byte( addr ); break; case 2: argval = get_word( addr ); break; case 4: argval = get_long( addr ); break; } if (rn == PC && mode >= BYTEDISP) { argval += addr + nbytes; } return argval; } static regdisp( rn, offset, type, defr, str ) int rn, offset, type, defr; char *str; { char *ds; if ( defr ) ds = "*"; else ds = ""; switch ( rn ) { /* arguments */ case AP: if ( offset < 0 ) printf( "ERR: bad argument offset %d\n", offset ); else sprintf( str, "%s%s", ds, arg_sym( offset, type ) ); break; /* locals */ case FP: if ( offset > 0 ) printf( "bad local offset %d\n", offset ); else sprintf( str, "%s%s", ds, loc_sym( -offset, type ) ); break; case PC: if ( defr ) printf( "ERR: PC deferred\n" ); sprintf( str, "G%04d", offset ); break; /* everything else */ default: sprintf( str, "%s%s->O%03d%s", ds, reg_sym( rn, type | T_POINTER ), offset, typesuf[ type ] ); break; } }