revision 1300:d18488c8668b
summary |
tree |
shortlog |
changelog |
graph |
changeset |
raw | bz2 | zip | gz changeset | 1300:d18488c8668b |
parent | 1299:645ccec8dfb0 |
child | 1301:b76840ccf94b |
author | nkeynes |
date | Wed May 27 08:46:29 2015 +1000 (8 years ago) |
Add support for extracting the ELF symbol table and printing symbol names
alongside the SH4 disassembly
alongside the SH4 disassembly
src/loader.c | view | annotate | diff | log | ||
src/sh4/sh4.h | view | annotate | diff | log | ||
src/sh4/sh4dasm.h | view | annotate | diff | log | ||
src/sh4/sh4dasm.in | view | annotate | diff | log | ||
src/sh4/sh4trans.c | view | annotate | diff | log |
1.1 --- a/src/loader.c Sun May 24 19:46:06 2015 +10001.2 +++ b/src/loader.c Wed May 27 08:46:29 2015 +10001.3 @@ -34,6 +34,7 @@1.4 #include "drivers/cdrom/cdrom.h"1.5 #include "drivers/cdrom/isofs.h"1.6 #include "gdrom/gdrom.h"1.7 +#include "sh4/sh4.h"1.9 const char bootstrap_magic[32] = "SEGA SEGAKATANA SEGA ENTERPRISES";1.10 const char iso_magic[6] = "\001CD001";1.11 @@ -242,6 +243,8 @@1.12 {1.13 Elf32_Ehdr head;1.14 Elf32_Phdr phdr;1.15 + Elf32_Shdr shdr;1.16 + Elf32_Sym sym;1.17 int i;1.19 if( read( fd, &head, sizeof(head) ) != sizeof(head) )1.20 @@ -265,6 +268,43 @@1.21 }1.22 }1.24 + /* Find symbol table */1.25 + uint32_t symtabOffset = 0, symtabSize = 0, symtabEntSize = 0;1.26 + uint32_t strtabOffset = 0, strtabSize = 0;1.27 + for( int i = 0; i < head.e_shnum; i++ ) {1.28 + lseek( fd, head.e_shoff + i * head.e_shentsize, SEEK_SET );1.29 + read( fd, &shdr, sizeof( shdr ) );1.30 + if( shdr.sh_type == SHT_SYMTAB ) {1.31 + symtabOffset = shdr.sh_offset;1.32 + symtabSize = shdr.sh_size;1.33 + symtabEntSize = shdr.sh_entsize;1.34 + } else if( shdr.sh_type == SHT_STRTAB ) {1.35 + strtabOffset = shdr.sh_offset;1.36 + strtabSize = shdr.sh_size;1.37 + }1.38 + }1.39 + /* Extract symbols */1.40 + if( symtabOffset != 0 && strtabOffset != 0 ) {1.41 + unsigned numSymtabEntries = symtabSize / symtabEntSize;1.42 + char *data = g_malloc( numSymtabEntries * sizeof( struct sh4_symbol ) + strtabSize );1.43 + struct sh4_symbol *symtab = ( struct sh4_symbol * )data;1.44 + char *strings = data + ( numSymtabEntries * sizeof( struct sh4_symbol ) );1.45 + lseek( fd, strtabOffset, SEEK_SET );1.46 + read( fd, strings, strtabSize );1.47 + strings[strtabSize-1] = '\0'; /* Should already be 0, but just in case */1.48 + for( int i = 0; i < numSymtabEntries; i++ ) {1.49 + lseek( fd, symtabOffset + ( i * symtabEntSize ), SEEK_SET );1.50 + read( fd, &sym, sizeof( sym ) );1.51 + if( sym.st_name < strtabSize )1.52 + symtab[i].name = &strings[sym.st_name];1.53 + else1.54 + symtab[i].name = NULL;1.55 + symtab[i].address = sym.st_value;1.56 + symtab[i].size = sym.st_size;1.57 + }1.58 + sh4_set_symbol_table( symtab, numSymtabEntries, ( sh4_symtab_destroy_cb )free );1.59 + }1.60 +1.61 file_load_postload( filename, head.e_entry );1.62 return TRUE;1.63 }
2.1 --- a/src/sh4/sh4.h Sun May 24 19:46:06 2015 +10002.2 +++ b/src/sh4/sh4.h Wed May 27 08:46:29 2015 +10002.3 @@ -161,7 +161,21 @@2.4 */2.5 gboolean sh4_get_profile_blocks();2.7 +struct sh4_symbol {2.8 + const char *name;2.9 + sh4addr_t address;2.10 + unsigned size;2.11 +};2.13 +typedef void (*sh4_symtab_destroy_cb)(struct sh4_symbol *table, unsigned size);2.14 +2.15 +/**2.16 + * Set the active symbol table used for disassembly. The table will be modified2.17 + * to sort it by address and eliminate duplicates.2.18 + * The callback supplied is invoked whenever the table is changed2.19 + * or removed.2.20 + */2.21 +void sh4_set_symbol_table( struct sh4_symbol *table, unsigned symtab_size, sh4_symtab_destroy_cb callback );2.23 #ifdef __cplusplus2.24 }
3.1 --- a/src/sh4/sh4dasm.h Sun May 24 19:46:06 2015 +10003.2 +++ b/src/sh4/sh4dasm.h Wed May 27 08:46:29 2015 +10003.3 @@ -29,6 +29,7 @@3.5 uint32_t sh4_disasm_instruction( uint32_t pc, char *buf, int len, char * );3.6 void sh4_disasm_region( FILE *f, int from, int to );3.7 +const char *sh4_disasm_get_symbol( sh4addr_t addr );3.9 #ifdef __cplusplus3.10 }
4.1 --- a/src/sh4/sh4dasm.in Sun May 24 19:46:06 2015 +10004.2 +++ b/src/sh4/sh4dasm.in Wed May 27 08:46:29 2015 +10004.3 @@ -21,6 +21,8 @@4.4 #include "sh4/mmu.h"4.5 #include "mem.h"4.7 +#include <string.h>4.8 +4.9 #define UNIMP(ir) snprintf( buf, len, "??? " )4.11 uint32_t sh4_disasm_instruction( sh4vma_t pc, char *buf, int len, char *opcode )4.12 @@ -275,6 +277,74 @@4.13 }4.16 +static struct sh4_symbol *sh4_symbol_table = NULL;4.17 +static unsigned sh4_symbol_table_size = 0;4.18 +static sh4_symtab_destroy_cb sh4_symbol_table_cb = NULL;4.19 +4.20 +4.21 +static void swap_symbol( struct sh4_symbol *a, struct sh4_symbol *b ) {4.22 + struct sh4_symbol tmp;4.23 + if( a == b )4.24 + return;4.25 + memcpy( &tmp, a, sizeof( struct sh4_symbol ) );4.26 + memcpy( a, b, sizeof( struct sh4_symbol ) );4.27 + memcpy( b, &tmp, sizeof( struct sh4_symbol ) );4.28 +}4.29 +4.30 +static unsigned sort_symtab( struct sh4_symbol *table, unsigned numSymtabEntries ) {4.31 + /* Implement via simple selection sort for now; usually we don't have very4.32 + * large symbol tables.4.33 + */4.34 + for( unsigned i = 0; i < numSymtabEntries; i++ ) {4.35 + struct sh4_symbol *next_entry = &table[i];4.36 + for( unsigned j = i + 1; j < numSymtabEntries; ) {4.37 + if( table[j].address < next_entry->address ) {4.38 + next_entry = &table[j];4.39 + j++;4.40 + } else if( table[j].address == next_entry->address ) {4.41 + /* Duplicate - kill it */4.42 + swap_symbol( &table[j], &table[--numSymtabEntries] );4.43 + } else {4.44 + j++;4.45 + }4.46 + }4.47 + swap_symbol( &table[i], next_entry );4.48 + }4.49 + return numSymtabEntries;4.50 +}4.51 +4.52 +const char *sh4_disasm_get_symbol( sh4addr_t addr )4.53 +{4.54 + int l = 0, h = sh4_symbol_table_size;4.55 + while( l != h ) {4.56 + int i = l + (h-l)/2;4.57 + int iaddr = sh4_symbol_table[i].address;4.58 + if( iaddr == addr ) {4.59 + return sh4_symbol_table[i].name;4.60 + } else if( iaddr > addr ) {4.61 + h = i;4.62 + } else { /* iaddr < addr */4.63 + l = i+1;4.64 + }4.65 + }4.66 + return NULL;4.67 +}4.68 +4.69 +void sh4_set_symbol_table( struct sh4_symbol *table, unsigned size, sh4_symtab_destroy_cb callback )4.70 +{4.71 + if( sh4_symbol_table_cb != NULL ) {4.72 + sh4_symbol_table_cb(sh4_symbol_table, sh4_symbol_table_size);4.73 + }4.74 + sh4_symbol_table = table;4.75 + sh4_symbol_table_cb = callback;4.76 + if( table == NULL ) {4.77 + sh4_symbol_table_size = 0;4.78 + } else {4.79 + sh4_symbol_table_size = sort_symtab(table, size);4.80 + }4.81 +}4.82 +4.83 +4.84 void sh4_disasm_region( FILE *f, int from, int to )4.85 {4.86 int pc;4.87 @@ -285,6 +355,10 @@4.88 buf[0] = '\0';4.89 sh4_disasm_instruction( pc,4.90 buf, sizeof(buf), opcode );4.91 + const char *sym = sh4_disasm_get_symbol( pc );4.92 + if( sym != 0 ) {4.93 + fprintf( f, "%s:\n", sym );4.94 + }4.95 fprintf( f, " %08x: %s %s\n", pc, opcode, buf );4.96 }4.97 }
5.1 --- a/src/sh4/sh4trans.c Sun May 24 19:46:06 2015 +10005.2 +++ b/src/sh4/sh4trans.c Wed May 27 08:46:29 2015 +10005.3 @@ -294,6 +294,16 @@5.4 sh4_translate_disasm_block( stderr, code, sh4_pc, NULL );5.5 }5.7 +void sh4_translate_dump_block_phys( uint32_t sh4_pma )5.8 +{5.9 + void *code = xlat_get_code( sh4_pma );5.10 + if( code == NULL ) {5.11 + fprintf( stderr, "** No translated block for address %08x **\n", sh4_pma );5.12 + return;5.13 + }5.14 + sh4_translate_disasm_block( stderr, code, sh4_pma, NULL );5.15 +5.16 +}5.18 static struct xlat_symbol xlat_symbol_table[] = {5.19 { "sh4r+128", ((char *)&sh4r)+128 },5.20 @@ -338,6 +348,20 @@5.22 for( target_pc = target_start; target_pc < target_end; ) {5.23 uintptr_t pc2 = xlat_disasm_instruction( target_pc, buf, sizeof(buf), op );5.24 +5.25 + if( source_recov_table < source_recov_end &&5.26 + target_pc >= (target_start + source_recov_table->xlat_offset) ) {5.27 + source_recov_table++;5.28 + if( source_end < (source_start + (source_recov_table->sh4_icount)*2) )5.29 + source_end = source_start + (source_recov_table->sh4_icount)*2;5.30 + }5.31 +5.32 + if( source_pc < source_end ) {5.33 + const char *sym = sh4_disasm_get_symbol(source_pc);5.34 + if( sym != 0 ) {5.35 + fprintf( out, "%s:\n", sym );5.36 + }5.37 + }5.38 #if SIZEOF_VOID_P == 85.39 fprintf( out, "%c%016lx: %-30s %-40s", (target_pc == (uintptr_t)native_pc ? '*' : ' '),5.40 target_pc, op, buf );5.41 @@ -345,12 +369,6 @@5.42 fprintf( out, "%c%08lx: %-30s %-40s", (target_pc == (uintptr_t)native_pc ? '*' : ' '),5.43 target_pc, op, buf );5.44 #endif5.45 - if( source_recov_table < source_recov_end &&5.46 - target_pc >= (target_start + source_recov_table->xlat_offset) ) {5.47 - source_recov_table++;5.48 - if( source_end < (source_start + (source_recov_table->sh4_icount)*2) )5.49 - source_end = source_start + (source_recov_table->sh4_icount)*2;5.50 - }5.52 if( source_pc < source_end ) {5.53 uint32_t source_pc2 = sh4_disasm_instruction( source_pc, buf, sizeof(buf), op );
.