static void dumpRef( const uint_8 *input, uint length ) { const uint_8 *p; uint_8 op_code; uint_32 tmp; int_32 itmp; uint_32 unit_length; const uint_8 *unit_base; p = input; while( p - input < length ) { unit_length = getU32( (uint_32 *)p ); p += sizeof( uint_32 ); unit_base = p; printf( "total_length: %08lx\n", getU32( (uint_32 *)p ) ); while( p - unit_base < unit_length ) { op_code = *p++; if( op_code < REF_CODE_BASE ) { printf( "%s", getReferenceOp( op_code ) ); switch( op_code ) { case REF_BEGIN_SCOPE: printf( " %08lx\n", getU32( (uint_32 *)p ) ); p += sizeof( uint_32 ); break; case REF_END_SCOPE: case REF_COPY: printf( "\n" ); break; case REF_SET_FILE: case REF_SET_LINE: case REF_SET_COLUMN: p = DecodeULEB128( p, &tmp ); printf( " %lu\n", tmp ); break; case REF_ADD_LINE: case REF_ADD_COLUMN: p = DecodeLEB128( p, &itmp ); printf( " %ld\n", itmp ); break; } } else { op_code -= REF_CODE_BASE; printf( "REF line += %d, column += %d, %08lx\n", op_code / REF_COLUMN_RANGE, op_code % REF_COLUMN_RANGE, getU32( (uint_32 *)p ) ); p += sizeof( uint_32 ); } } } }
void Dump_lines( const uint_8 *input, uint length ) /*************************************************/ { const uint_8 *p; const uint_8 *stmt_start; uint opcode_base; uint *opcode_lengths; uint u; uint file_index; const uint_8 *name; uint_32 mod_time; uint_32 file_length; uint_32 directory; uint_8 op_code; uint_32 op_len; uint_32 tmp; uint line_range; int line_base; int_32 itmp; int default_is_stmt; state_info state; uint min_instr; uint_32 unit_length; const uint_8 *unit_base; p = input; while( p - input < length ) { unit_length = get_u32( (uint_32 *)p ); p += sizeof( uint_32 ); unit_base = p; Wdputs( "total_length: " ); Puthex( unit_length, 8 ); Wdputslc( "\nversion: " ); Puthex( get_u16( (uint_16 *)p ), 4 ); p += sizeof( uint_16 ); Wdputslc( "\nprologue_length: " ); Puthex( get_u32( (uint_32 *)p ), 8 ); stmt_start = p; stmt_start += get_u32( (uint_32 *)p ); p += sizeof( uint_32 ); stmt_start += sizeof( uint_32 ); min_instr = *p; Wdputslc( "\nminimum_instruction_length: " ); Puthex( min_instr, 2 ); p += 1; default_is_stmt = *p; Wdputslc( "\ndefault_is_stmt: " ); Puthex( default_is_stmt, 2 ); p += 1; line_base = *(int_8 *)p; Wdputslc( "\nline_base: " ); Puthex( line_base, 2 ); p += 1; line_range = *(uint_8 *)p; Wdputslc( "\nline_range: " ); Puthex( line_range, 2 ); p += 1; opcode_base = *p; Wdputslc( "\nopcode_base: " ); Puthex( opcode_base, 2 ); Wdputslc( "\n" ); p += 1; opcode_lengths = malloc( sizeof( uint ) * opcode_base ); Wdputslc( "standard_opcode_lengths:\n" ); for( u = 0; u < opcode_base - 1; ++u ) { opcode_lengths[ u ] = *p; ++p; Putdecl( u, 4 ); Wdputs( ": " ); Putdec( opcode_lengths[ u ] ); Wdputslc( "\n" ); } Wdputs( "-- current_offset = " ); Puthex( p - input, 8 ); Wdputslc( "\n" ); if( p - input >= length ) return; Wdputslc( "include directories\n" ); file_index = 0; while( *p != 0 ) { ++file_index; name = p; p += strlen( (char *)p ) + 1; Wdputs( "path " ); Putdec( file_index ); Wdputs( ": '" ); Wdputs( (char *)name ); Wdputslc( "'\n" ); if( p - input >= length ) return; } p++; Wdputslc( "file names\n" ); file_index = 0; while( *p != 0 ) { ++file_index; name = p; p += strlen( (char *)p ) + 1; p = DecodeULEB128( p, &directory ); p = DecodeULEB128( p, &mod_time ); p = DecodeULEB128( p, &file_length ); Wdputs( "file " ); Putdec( file_index ); Wdputs( ": '" ); Wdputs( (char *)name ); Wdputs( "' directory " ); Putdec( directory ); Wdputs( " mod_time " ); Puthex( mod_time, 8 ); Wdputs( " length " ); Puthex( file_length, 8 ); Wdputslc( "\n" ); if( p - input >= length ) return; } p++; init_state( &state, default_is_stmt ); Wdputs( "-- current_offset = " ); Puthex( p - input, 8 ); if( p != stmt_start ) { Wdputs( ":***Prologue length off***" ); } Wdputslc( "\n" ); while( p - unit_base < unit_length ) { op_code = *p; ++p; if( op_code == 0 ) { /* extended op_code */ p = DecodeULEB128( p, &op_len ); Wdputs( "len: " ); Putdecl( op_len, 3 ); Wdputc( ' ' ); op_code = *p; ++p; --op_len; switch( op_code ) { case DW_LNE_end_sequence: Wdputslc( "END_SEQUENCE\n" ); state.end_sequence = 1; dump_state( &state ); init_state( &state, default_is_stmt ); p+= op_len; break; case DW_LNE_set_address: Wdputs( "SET_ADDRESS " ); if( op_len == 4 ) { tmp = get_u32( (uint_32 *)p ); } else if( op_len == 2 ) { tmp = get_u16( (uint_16 *)p ); } else { tmp = 0xffffffff; } state.address = tmp; Puthex( tmp, op_len*2 ); Wdputslc( "\n" ); p += op_len; break; case DW_LNE_set_segment: Wdputs( "SET_SEGMENT " ); if( op_len == 4 ) { tmp = get_u32( (uint_32 *)p ); } else if( op_len == 2 ) { tmp = get_u16( (uint_16 *)p ); } else { tmp = 0xffffffff; } state.segment = tmp; Puthex( tmp, op_len*2 ); Wdputslc( "\n" ); p += op_len; break; case DW_LNE_define_file: ++file_index; name = p; p += strlen( (char *)p ) + 1; p = DecodeULEB128( p, &directory ); p = DecodeULEB128( p, &mod_time ); p = DecodeULEB128( p, &file_length ); Wdputs( "DEFINE_FILE " ); Putdec( file_index ); Wdputs( ": '" ); Wdputs( (char *)name ); Wdputs( "' directory " ); Putdec( directory ); Wdputs( " mod_time " ); Puthex( mod_time, 8 ); Wdputs( " length " ); Puthex( file_length, 8 ); break; default: Wdputs( "** unknown extended opcode: " ); Puthex( op_code, 2 ); Wdputslc( "\n" ); p += op_len; break; } } else if( op_code < opcode_base ) { get_standard_op( op_code ); switch( op_code ) { case DW_LNS_copy: dump_state( &state ); state.basic_block = 0; break; case DW_LNS_advance_pc: p = DecodeLEB128( p, &itmp ); Putdec( itmp ); state.address += itmp * min_instr; break; case DW_LNS_advance_line: p = DecodeLEB128( p, &itmp ); Putdec( itmp ); state.line += itmp; break; case DW_LNS_set_file: p = DecodeLEB128( p, &itmp ); Putdec( itmp ); state.file = itmp; break; case DW_LNS_set_column: p = DecodeLEB128( p, &itmp ); Putdec( itmp ); state.column = itmp; break; case DW_LNS_negate_stmt: state.is_stmt = !state.is_stmt; break; case DW_LNS_set_basic_block: state.basic_block = 1; break; case DW_LNS_const_add_pc: state.address += ( ( 255 - opcode_base ) / line_range ) * min_instr; break; case DW_LNS_fixed_advance_pc: tmp = get_u16( (uint_16 *)p ); p += sizeof( uint_16 ); Puthex( tmp, 4 ); state.address += tmp; break; default: for( u = 0; u < opcode_lengths[ op_code - 1 ]; ++u ) { p = DecodeLEB128( p, &itmp ); Puthex( itmp, 8 ); } } } else { Wdputs( "SPECIAL " ); Puthex( op_code, 2 ); op_code -= opcode_base; Wdputs( ": addr incr: " ); Putdec( op_code / line_range ); Wdputs( " line incr: " ); Putdec( line_base + op_code % line_range ); state.line += line_base + op_code % line_range; state.address += ( op_code / line_range ) * min_instr; dump_state( &state ); state.basic_block = 0; } Wdputslc( "\n" ); } free( opcode_lengths ); Wdputs( "-- current_offset = " ); Puthex( p - input, 8 ); Wdputslc( "\n" ); } }
static void dumpLines( const uint_8 *input, uint length ) { const uint_8 *p; uint opcode_base; uint *opcode_lengths; uint u; uint file_index; const uint_8 *name; uint_32 dir_index; uint_32 mod_time; uint_32 file_length; uint_32 directory; uint_8 op_code; uint_8 op_len; uint_32 tmp; uint_16 tmp_seg; uint line_range; int line_base; int_32 itmp; int default_is_stmt; state_info state; uint min_instr; uint_32 unit_length; const uint_8 *unit_base; p = input; while( p - input < length ) { unit_length = getU32( (uint_32 *)p ); p += sizeof( uint_32 ); unit_base = p; printf( "total_length: 0x%08lx (%u)\n", unit_length, unit_length ); printf( "=== unit dump start ===\n" ); dumpHex( unit_base - sizeof( uint_32 ), unit_length + sizeof (uint_32 ), 1 ); printf( "=== unit dump end ===\n" ); printf( "version: 0x%04x\n", getU16( (uint_16 *)p ) ); p += sizeof( uint_16 ); printf( "prologue_length: 0x%08lx (%u)\n", getU32( (uint_32 *)p ), getU32( (uint_32 *)p ) ); p += sizeof( uint_32 ); min_instr = *p; printf( "minimum_instruction_length: 0x%02x (%u)\n", min_instr, min_instr ); p += 1; default_is_stmt = *p; printf( "default_is_stmt: 0x%02x (%u)\n", default_is_stmt, default_is_stmt ); p += 1; line_base = *(int_8 *)p; printf( "line_base: 0x%02x (%d)\n", (unsigned char)line_base, line_base ); p += 1; line_range = *(uint_8 *)p; printf( "line_range: 0x%02x (%u)\n", line_range, line_range ); p += 1; opcode_base = *p; printf( "opcode_base: 0x%02x (%u)\n", opcode_base, opcode_base ); p += 1; opcode_lengths = alloca( sizeof( uint ) * opcode_base ); printf( "standard_opcode_lengths:\n" ); for( u = 0; u < opcode_base - 1; ++u ) { opcode_lengths[u] = *p; ++p; printf( "%4u: %u\n", u + 1, opcode_lengths[u] ); } printf( "-- current_offset = %08x\n", p - input ); if( p - input >= length ) return; printf( "-- start include paths --\n"); file_index = 0; while( *p != 0 ) { ++file_index; name = p; p += strlen( (const char *)p ) + 1; printf( "path %u: '%s'\n", file_index, name ); if( p - input >= length ) { return; } } printf( "-- end include paths --\n"); p++; printf( "-- start files --\n"); file_index = 0; while( *p != 0 ) { ++file_index; name = p; p += strlen( (const char *)p ) + 1; p = DecodeULEB128( p, &dir_index ); p = DecodeULEB128( p, &mod_time ); p = DecodeULEB128( p, &file_length ); printf( "file %u: '%s' dir_index %08lx mod_time %08lx length %08lx\n", file_index, name, dir_index, mod_time, file_length ); if( p - input >= length ) { return; } } printf( "-- end files --\n"); p++; initState( &state, default_is_stmt ); while( p - unit_base < unit_length ) { op_code = *p; ++p; if( op_code == 0 ) { printf( "EXTENDED 0x%02x: ", op_code ); /* extended op_code */ op_len = *p; ++p; printf( "len: %03d ", op_len ); op_code = *p; ++p; switch( op_code ) { case DW_LNE_end_sequence: printf( "END_SEQUENCE\n" ); state.end_sequence = 1; dumpState( &state ); initState( &state, default_is_stmt ); break; case DW_LNE_set_address: if( op_len == 3 ) { tmp = getU16( (uint_16 *)p ); p += sizeof( uint_16 ); } else { tmp = getU32( (uint_32 *)p ); p += sizeof( uint_32 ); } #if 0 /* Why did they choose 6 byte here? */ tmp_seg = getU16( (uint_16 *)p ); p += sizeof( uint_16 ); printf( "SET_ADDRESS %04x:%08lx\n", tmp_seg, tmp ); #else tmp_seg = 0; /* stop warning */ printf( "SET_ADDRESS %08lx\n", tmp ); #endif break; case DW_LNE_WATCOM_set_segment_OLD: case DW_LNE_WATCOM_set_segment: tmp_seg = getU16( (uint_16 *)p ); p += sizeof( uint_16 ); printf( "SET_ADDRESS_SEG %04x\n", tmp_seg ); break; case DW_LNE_define_file: ++file_index; name = p; p += strlen( (const char *)p ) + 1; p = DecodeULEB128( p, &directory ); p = DecodeULEB128( p, &mod_time ); p = DecodeULEB128( p, &file_length ); printf( "DEFINE_FILE %u: '%s' directory %ld mod_time %08lx length %08lx\n", file_index, name, directory, mod_time, file_length ); break; default: printf( "** unknown extended opcode: %02x - %u bytes\n", op_code, op_len ); printf( "** losing %u bytes\n", unit_length - ( p - unit_base )); dumpHex( p-3, (unit_length - ( p - unit_base )) + 3, 1 ); p = unit_base + unit_length; goto hacky; // return; } } else if( op_code < opcode_base ) { printf( "%s", getStandardOp( op_code ) ); switch( op_code ) { case DW_LNS_copy: printf( "\n" ); dumpState( &state ); state.basic_block = 0; break; case DW_LNS_advance_pc: p = DecodeLEB128( p, &itmp ); printf( " %ld\n", itmp ); state.address += itmp * min_instr; break; case DW_LNS_advance_line: p = DecodeLEB128( p, &itmp ); printf( " %ld\n", itmp ); state.line += itmp; break; case DW_LNS_set_file: p = DecodeLEB128( p, &itmp ); printf( " %ld\n", itmp ); state.file = itmp; break; case DW_LNS_set_column: p = DecodeLEB128( p, &itmp ); printf( " %ld\n", itmp ); state.column = itmp; break; case DW_LNS_negate_stmt: printf( "\n" ); state.is_stmt = !state.is_stmt; break; case DW_LNS_set_basic_block: printf( "\n" ); state.basic_block = 1; break; case DW_LNS_const_add_pc: printf( "\n" ); state.address += ( ( 255 - opcode_base ) / line_range ) * min_instr; break; case DW_LNS_fixed_advance_pc: tmp = getU16( (uint_16 *)p ); p += sizeof( uint_16 ); printf( " %04x\n", tmp ); state.address += tmp; break; default: for( u = 0; u < opcode_lengths[op_code - 1]; ++u ) { p = DecodeLEB128( p, &itmp ); printf( " %08lx", itmp ); } printf( "\n" ); } } else { printf( "SPECIAL 0x%02x:", op_code ); op_code -= opcode_base; printf( " addr incr: %d line incr: %d\n", op_code / line_range, line_base + op_code % line_range ); state.line += line_base + op_code % line_range; state.address += ( op_code / line_range ) * min_instr; dumpState( &state ); state.basic_block = 0; } } hacky: printf( "-- current_offset = %08x\n", p - input ); } }
static void dumpInfo( const uint_8 *input, uint length ) { const uint_8 *p; uint_32 abbrev_code; uint_32 abbrev_offset; uint_8 * abbrev; uint_32 tag; uint_32 attr; uint_32 form; uint_32 len; uint_32 tmp; int_32 stmp; uint_32 unit_length; int address_size; const uint_8 *unit_base; p = input; while( p - input < length ) { unit_length = getU32( (uint_32 *)p ); unit_base = p + sizeof( uint_32 ); address_size = *(p + 10); abbrev_offset = getU32( (uint_32 *)(p + 6) ); printf( "Length: %08lx\nVersion: %04x\nAbbrev: %08lx\nAddress Size %02x\n", unit_length, getU16( (uint_16 *)(p + 4) ), abbrev_offset, address_size ); p += 11; while( p - unit_base < unit_length ) { printf( "offset %08x: ", p - input ); p = DecodeULEB128( p, &abbrev_code ); printf( "Code: %08lx\n", abbrev_code ); if( abbrev_code == 0 ) continue; abbrev = findAbbrev( abbrev_code, abbrev_offset ); if( abbrev == NULL ) { printf( "can't find abbreviation %08lx\n", abbrev_code ); break; } if( p >= input + length ) break; abbrev = DecodeULEB128( abbrev, &tag ); printf( "\t%s\n", getTAG( tag ) ); abbrev++; for( ;; ) { abbrev = DecodeULEB128( abbrev, &attr ); abbrev = DecodeULEB128( abbrev, &form ); if( attr == 0 ) break; printf( "\t%-20s", getAT( attr ) ); decode_form: switch( form ) { case DW_FORM_addr: switch( address_size ) { case 4: tmp = getU32( (uint_32 *)p ); p += sizeof( uint_32 ); printf( "\t%08lx\n", tmp ); break; case 2: tmp = getU16( (uint_16 *)p ); p += sizeof( uint_16 ); printf( "\t%04lx\n", tmp ); break; default: printf( "Unknown address size\n" ); p += address_size; break; } break; case DW_FORM_block: p = DecodeULEB128( p, &len ); printf( "\n" ); dumpHex( p, len, 0 ); p += len; break; case DW_FORM_block1: len = *p++; printf( "\n" ); dumpHex( p, len, 0 ); p += len; break; case DW_FORM_block2: len = getU16( (uint_16 *)p ); p += sizeof( uint_16 ); printf( "\n" ); dumpHex( p, len, 0 ); p += len; break; case DW_FORM_block4: len = getU32( (uint_32 *)p ); p += sizeof( uint_32 ); printf( "\n" ); dumpHex( p, len, 0 ); p += len; break; case DW_FORM_data1: case DW_FORM_ref1: printf( "\t%02x\n", *p++ ); break; case DW_FORM_data2: case DW_FORM_ref2: printf( "\t%04x\n", getU16( (uint_16 *)p ) ); p += sizeof( uint_16 ); break; case DW_FORM_data4: case DW_FORM_ref4: printf( "\t%08lx\n", getU32( (uint_32 *)p ) ); p += sizeof( uint_32 ); break; case DW_FORM_flag: printf( "\t%s\n", *p++ ? "True" : "False" ); break; case DW_FORM_indirect: p = DecodeULEB128( p, &form ); printf( "\t(%s)", getFORM( form ) ); goto decode_form; case DW_FORM_sdata: p = DecodeLEB128( p, &stmp ); printf( "\t%08lx\n", stmp ); break; case DW_FORM_string: printf( "\t\"%s\"\n", p ); p += strlen( (const char *)p ) + 1; break; case DW_FORM_strp: /* 4 byte index into .debug_str */ printf_debug_str( getU32( (uint_32 *)p ) ); p += 4; break; case DW_FORM_udata: case DW_FORM_ref_udata: p = DecodeULEB128( p, &tmp ); printf( "\t%08lx\n", tmp ); break; case DW_FORM_ref_addr: //KLUDGE should really check addr_size printf( "\t%08lx\n", getU32( (uint_32 *)p ) ); p += sizeof(uint_32); break; default: printf( "unknown form!\n" ); return; } } } } }