|
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 b
Length: 8609 (0x21a1) Types: TextFile Names: »blocks.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit └─⟦3f75c1919⟧ »EurOpenD3/utils/decomp.tar.Z« └─⟦510c4d5ee⟧ └─⟦this⟧ »decomp/blocks.c«
/* * Module: blocks.c * * Author: J. Reuter * * The functions in this module analyze a contiguous block of code * comprising a function, construct a directed graph of basic blocks * from the code, and perform trivial simplification of the graph. */ #include "defs.h" #include "machine.h" #include "labeltab.h" #include "objfile.h" #include "vartab.h" #include "nodes.h" #include <setjmp.h> extern jmp_buf badbranch; static int op_argval[6]; /* * blocks builds an array (node_array) of the basic blocks * contained in the code section. Branches to unconditional * branches (these happen often because of the byte-offset of * conditional branches) are converted into branches to the * final destination during this pass. The node arcs are converted * from addresses to node_array indices. */ blocks( start_address, end_address ) register address start_address, end_address; { find_blocks( start_address, end_address ); /* find the basic blocks */ array_nodes(); /* make an array of the blocks */ rem_ubranch(); /* remove second level branches */ } /* * find_blocks makes a pass through the code and finds the basic * blocks by looking for branches and entry points recorded in the * label table by the previous pass. */ static find_blocks( start_address, end_address ) address start_address, end_address; { unsigned char ins; int is_if = 0; int prev_is_if; register address cur_address; register address prev_address; register address node_entry; register address branch_address; register struct node *node; address insaddr; unsigned char mode; register int argtype, amode, argno, argval; register int rn, type; short offset; struct llb *l; int is_branch; /* initialize pass */ /* get the first (in address order) branch target */ l = llb_first(); cur_address = start_address; node_entry = cur_address; /* loop across all the instructions in this function */ while ( cur_address < end_address ) { prev_address = cur_address; is_branch = FALSE; while ( l->l_address <= cur_address ) l = llb_next(); prev_is_if = is_if; ins = get_byte( cur_address ); is_if = ( ins == O_TSTF || ins == O_TSTD || ins == O_TSTB || ins == O_TSTW || ins == O_TSTL || ins == O_CMPF || ins == O_CMPD || ins == O_CMPB || ins == O_CMPW || ins == O_CMPL || ins == O_CMPV || ins == O_CMPZV ); cur_address += 1; /* process each instruction operand, filling op_argval */ for (argno = 0; argno < opcode[ins].numargs; argno++) { argtype = opcode[ins].argtype[argno]; if (is_branch_disp(argtype)) { mode = 0xAF + ( (typelen(argtype) & ~T_UNSIGNED) << 4); is_branch = TRUE; } else { mode = get_byte( cur_address ); cur_address += 1; } rn = regnm( mode ); type = typelen( argtype ); amode = addrmode(mode); switch (amode) { case LITSHORT: case LITUPTO31: case LITUPTO47: case LITUPTO63: argval = mode; break; case INDEX: argno--; break; case REG: case REGDEF: case AUTODEC: break; case AUTOINC: if ( rn != PC ) { ; } else { /* immediate values */ switch ( type & ~T_UNSIGNED ) { case TYPB: argval = getdisp(cur_address, 1, rn, amode); cur_address += 1; break; case TYPW: argval = getdisp(cur_address, 2, rn, amode); cur_address += 2; break; case TYPL: argval = getdisp(cur_address, 4, rn, amode); cur_address += 4; break; default: printf( "ERR: strange-autoinc %d\n", type ); break; } } break; case AUTOINCDEF: if ( rn == PC ) { /* immediate deferred */ argval = getdisp(cur_address, 4, rn, amode); cur_address += 4; } else { ; } break; case BYTEDISP: argval = getdisp(cur_address, 1, rn, amode); cur_address += 1; break; case BYTEDISPDEF: argval = getdisp(cur_address, 1, rn, amode); cur_address += 1; break; case WORDDISP: argval = getdisp(cur_address, 2, rn, amode); cur_address += 2; break; case WORDDISPDEF: argval = getdisp(cur_address, 2, rn, amode); cur_address += 2; break; case LONGDISP: argval = getdisp(cur_address, 4, rn, amode); cur_address += 4; break; case LONGDISPDEF: argval = getdisp(cur_address, 4, rn, amode); cur_address += 4; break; } if ( is_branch_disp(argtype) ) branch_address = argval; op_argval[argno] = argval; } if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) { /* case statements */ /* arc 0 is flow exit, arc 1 to argno+1 are case exits */ node = get_node( argval + 2 ); insaddr = cur_address; for ( argno = 0; argno <= argval; argno++ ) { offset = get_word( cur_address ); cur_address += 2; node->arcs[argno + 1] = offset + insaddr; } node->node_type = N_CASE; node->start_address = node_entry; node->end_address = cur_address; node->num_arcs = argval + 2; node->arcs[0] = cur_address; /* flow exit */ node_entry = cur_address; node->varpart[V_BASE] = op_argval[1]; node->varpart[V_LIMIT] = op_argval[2]; } else if ( is_branch && ( ins == O_BRB || ins == O_BRW ) ) { /* unconditional branch */ /* arc 0 is branch exit */ /* currently does not deal with JMP instructions */ /* * if this is an unconditional branch at an entry point * then start_address == end_address */ node = get_node( 1 ); node->node_type = N_FLOW; node->start_address = node_entry; node->end_address = prev_address; node->num_arcs = 1; node->arcs[0] = branch_address; node_entry = cur_address; } else if ( is_branch ) { /* conditional branch */ /* arc 0 is flow exit, arc 1 is branch exit */ if (opcode[ins].coptype == BBRANCH && prev_address != node_entry) { node = get_node( 1 ); node->node_type = N_FLOW; node->start_address = node_entry; node->end_address = prev_address; node->num_arcs = 1; node->arcs[0] = prev_address; node_entry = prev_address; } node = get_node( 2 ); if ( prev_is_if || opcode[ins].coptype == BBRANCH ) node->node_type = N_IF; else node->node_type = N_BRANCH; node->start_address = node_entry; node->end_address = cur_address; node->num_arcs = 2; node->arcs[THEN_ARC] = branch_address; node->arcs[ELSE_ARC] = cur_address; node->varpart[V_NEGATE] = FALSE; node_entry = cur_address; } else if ( ins == O_RET || ins == O_RSB || ins == O_HALT ) { /* ret or rsb instruction */ /* no exit arcs */ node = get_node( 0 ); node->node_type = N_END; node->start_address = node_entry; node->end_address = cur_address; node->num_arcs = 0; node_entry = cur_address; } else if ( cur_address == l->l_address || (is_if && prev_address != node_entry) ) { /* entry point with no branch */ /* arc 0 is flow exit */ node = get_node( 1 ); node->node_type = N_FLOW; node->start_address = node_entry; if ( is_if && prev_address != node_entry ) { node->end_address = prev_address; node_entry = prev_address; node->arcs[0] = prev_address; } else { node->end_address = cur_address; node_entry = cur_address; node->arcs[0] = cur_address; } node->num_arcs = 1; } } /* no more code in function */ if ( cur_address > node_entry ) { fprintf( stderr, "Dangling function end\n" ); longjmp( badbranch, 1 ); } } /* * Print the displacement of an instruction that uses displacement * addressing. */ static int getdisp(obj_address, nbytes, rn, mode) register address obj_address; register int nbytes; register int rn; register int mode; { register int argval; switch (nbytes) { case 1: argval = get_byte( obj_address ); break; case 2: argval = get_word( obj_address ); break; case 4: argval = get_long( obj_address ); break; } if (rn == PC && mode >= BYTEDISP) { argval += obj_address + nbytes; } return argval; } /* * rem_ubranch converts arcs leading to unconditional branches into * arcs leading to the final branch destination. */ static rem_ubranch() { register struct node *n, *m; register int i, j; for ( i = 0; i < node_count; i++ ) { n = node_array[i]; for ( j = 0; j < n->num_arcs; j++ ) { m = node_array[n->arcs[j]]; while ( m->start_address == m->end_address && m->node_type == N_FLOW ) { n->arcs[j] = m->arcs[0]; m = node_array[n->arcs[j]]; } } } }