Search
lxdream.org :: lxdream :: r1300:d18488c8668b
lxdream 0.9.1
released Jun 29
Download Now
changeset1300:d18488c8668b
parent1299:645ccec8dfb0
child1301:b76840ccf94b
authornkeynes
dateWed 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
src/loader.c
src/sh4/sh4.h
src/sh4/sh4dasm.h
src/sh4/sh4dasm.in
src/sh4/sh4trans.c
1.1 --- a/src/loader.c Sun May 24 19:46:06 2015 +1000
1.2 +++ b/src/loader.c Wed May 27 08:46:29 2015 +1000
1.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.8
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.18
1.19 if( read( fd, &head, sizeof(head) ) != sizeof(head) )
1.20 @@ -265,6 +268,43 @@
1.21 }
1.22 }
1.23
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 + else
1.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 +1000
2.2 +++ b/src/sh4/sh4.h Wed May 27 08:46:29 2015 +1000
2.3 @@ -161,7 +161,21 @@
2.4 */
2.5 gboolean sh4_get_profile_blocks();
2.6
2.7 +struct sh4_symbol {
2.8 + const char *name;
2.9 + sh4addr_t address;
2.10 + unsigned size;
2.11 +};
2.12
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 modified
2.17 + * to sort it by address and eliminate duplicates.
2.18 + * The callback supplied is invoked whenever the table is changed
2.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.22
2.23 #ifdef __cplusplus
2.24 }
3.1 --- a/src/sh4/sh4dasm.h Sun May 24 19:46:06 2015 +1000
3.2 +++ b/src/sh4/sh4dasm.h Wed May 27 08:46:29 2015 +1000
3.3 @@ -29,6 +29,7 @@
3.4
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.8
3.9 #ifdef __cplusplus
3.10 }
4.1 --- a/src/sh4/sh4dasm.in Sun May 24 19:46:06 2015 +1000
4.2 +++ b/src/sh4/sh4dasm.in Wed May 27 08:46:29 2015 +1000
4.3 @@ -21,6 +21,8 @@
4.4 #include "sh4/mmu.h"
4.5 #include "mem.h"
4.6
4.7 +#include <string.h>
4.8 +
4.9 #define UNIMP(ir) snprintf( buf, len, "??? " )
4.10
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.14
4.15
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 very
4.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 +1000
5.2 +++ b/src/sh4/sh4trans.c Wed May 27 08:46:29 2015 +1000
5.3 @@ -294,6 +294,16 @@
5.4 sh4_translate_disasm_block( stderr, code, sh4_pc, NULL );
5.5 }
5.6
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.17
5.18 static struct xlat_symbol xlat_symbol_table[] = {
5.19 { "sh4r+128", ((char *)&sh4r)+128 },
5.20 @@ -338,6 +348,20 @@
5.21
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 == 8
5.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 #endif
5.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.51
5.52 if( source_pc < source_end ) {
5.53 uint32_t source_pc2 = sh4_disasm_instruction( source_pc, buf, sizeof(buf), op );
.