CPU73050: add the data extractor program
This commit is contained in:
parent
e13de7352e
commit
3748c88c96
|
@ -1,3 +1,6 @@
|
|||
# Original DLL and related ELF
|
||||
CPU73050.dll
|
||||
CPU73050.elf
|
||||
|
||||
# Compiled program
|
||||
list-registers
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
list-registers: list-registers.c
|
||||
gcc $< -o $@ -Wall -Wextra -O2
|
||||
|
||||
CPU73050.elf: CPU73050.dll
|
||||
objcopy CPU73050.dll -O elf32-i386 CPU73050.elf
|
|
@ -0,0 +1,330 @@
|
|||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
//---
|
||||
// Structure of CPU73050.dll
|
||||
//---
|
||||
|
||||
/* First is an address to the list of register tables
|
||||
struct reg (*TABLE_LIST_ADDRESS)[][]
|
||||
(second-level arrays are not stored contiguously) */
|
||||
uint32_t const TABLE_LIST_ADDRESS = 0x100903e0;
|
||||
/* Just following is the list of peripheral modules
|
||||
struct module MODULE_LIST[]
|
||||
Unlike register tables this is not a pointer, it's the whole table */
|
||||
uint32_t const MODULE_LIST = 0x100903e4;
|
||||
|
||||
/* Each module has the following structure (yet to be discovered entirely) */
|
||||
struct module
|
||||
{
|
||||
uint32_t pointer_to_name;
|
||||
uint32_t pointer_to_description;
|
||||
uint32_t unknown[28];
|
||||
};
|
||||
/* Each peripheral register has this structure */
|
||||
struct reg
|
||||
{
|
||||
uint32_t pointer_to_name;
|
||||
uint32_t pointer_to_description;
|
||||
uint32_t unknown_1;
|
||||
uint32_t address;
|
||||
uint32_t unknown_2[2];
|
||||
uint32_t data_size;
|
||||
uint32_t access_size;
|
||||
uint32_t unknown_3[2];
|
||||
|
||||
uint32_t f1_other;
|
||||
uint32_t f1_u8;
|
||||
uint32_t f1_u16;
|
||||
uint32_t f1_u32;
|
||||
|
||||
uint32_t f2_other;
|
||||
uint32_t f2_u8;
|
||||
uint32_t f2_u16;
|
||||
uint32_t f2_u32;
|
||||
|
||||
uint32_t unknown_6[13];
|
||||
};
|
||||
|
||||
//---
|
||||
// ELF utilities
|
||||
//---
|
||||
|
||||
void check_header(Elf32_Ehdr *h)
|
||||
{
|
||||
/* Signature */
|
||||
assert(h->e_ident[EI_MAG0] == ELFMAG0);
|
||||
assert(h->e_ident[EI_MAG1] == ELFMAG1);
|
||||
assert(h->e_ident[EI_MAG2] == ELFMAG2);
|
||||
assert(h->e_ident[EI_MAG3] == ELFMAG3);
|
||||
/* Class */
|
||||
assert(h->e_ident[EI_CLASS] == ELFCLASS32);
|
||||
/* Little endian */
|
||||
assert(h->e_ident[EI_DATA] == ELFDATA2LSB);
|
||||
/* Must have a section table */
|
||||
assert(h->e_shoff != 0);
|
||||
}
|
||||
|
||||
Elf32_Shdr *get_section(Elf32_Ehdr *h, int id)
|
||||
{
|
||||
return (void *)h + h->e_shoff + id * h->e_shentsize;
|
||||
}
|
||||
|
||||
/* Get data from virtual address by searching all sections */
|
||||
void *get_virtual(Elf32_Ehdr *elf, uint32_t address)
|
||||
{
|
||||
for(int id = 0; id < elf->e_shnum; id++)
|
||||
{
|
||||
/* Skip sections of uninteresting types */
|
||||
Elf32_Shdr *section = get_section(elf, id);
|
||||
int type = section->sh_type;
|
||||
if(type == SHT_NULL || type == SHT_STRTAB) continue;
|
||||
|
||||
/* Check if in bounds of virtual address */
|
||||
int32_t offset = address - section->sh_addr;
|
||||
if(offset < 0 || offset >= (int32_t)section->sh_size) continue;
|
||||
|
||||
return (void *)elf + section->sh_offset + offset;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void print_sections(Elf32_Ehdr *elf)
|
||||
{
|
||||
Elf32_Shdr *strtable_section = get_section(elf, elf->e_shstrndx);
|
||||
char const *strtable = (void *)elf + strtable_section->sh_offset;
|
||||
|
||||
printf("Sections:\n");
|
||||
printf(" Name Size Virtual\n");
|
||||
|
||||
for(int id = 0; id < elf->e_shnum; id++)
|
||||
{
|
||||
Elf32_Shdr *section = get_section(elf, id);
|
||||
int type = section->sh_type;
|
||||
if(type == SHT_NULL || type == SHT_STRTAB) continue;
|
||||
|
||||
char const *name = strtable + section->sh_name;
|
||||
printf(" %2d %-8s %08x %08x\n", id, name, section->sh_size,
|
||||
section->sh_addr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//---
|
||||
// Data analysis heuristics
|
||||
//---
|
||||
|
||||
int valid_looking_string(uint8_t const *str)
|
||||
{
|
||||
int i = 0;
|
||||
while(i < 256 && str[i] >= 32 && str[i] <= 0x7f) i++;
|
||||
return (i > 0) && (i < 256) && !str[i];
|
||||
}
|
||||
|
||||
int valid_looking_module(Elf32_Ehdr *elf, struct module *m)
|
||||
{
|
||||
/* Check that there are valid printable ASCII name and description */
|
||||
if((m->pointer_to_name & 0xfff00000) != 0x10000000) return 0;
|
||||
if((m->pointer_to_description & 0xfff00000) != 0x10000000) return 0;
|
||||
|
||||
uint8_t const *name = get_virtual(elf, m->pointer_to_name);
|
||||
if(!valid_looking_string(name)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int valid_looking_reg(Elf32_Ehdr *elf, struct reg *r)
|
||||
{
|
||||
/* Check that there is a valid name */
|
||||
if((r->pointer_to_name & 0xfff00000) != 0x10000000) return 0;
|
||||
if((r->pointer_to_description & 0xfff00000) != 0x10000000) return 0;
|
||||
|
||||
/* Check that the name is printable ASCII */
|
||||
uint8_t const *name = get_virtual(elf, r->pointer_to_name);
|
||||
if(!valid_looking_string(name)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//---
|
||||
// Analysis of CPU73050.elf to find SH7305 register lists
|
||||
//---
|
||||
|
||||
void print_module(Elf32_Ehdr *elf, struct module *m)
|
||||
{
|
||||
if(m == NULL)
|
||||
{
|
||||
printf(" (Virtual) Name: Description:\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char const *name = get_virtual(elf, m->pointer_to_name);
|
||||
char const *desc = get_virtual(elf, m->pointer_to_description);
|
||||
printf(" %-10s %s\n", name, desc);
|
||||
}
|
||||
|
||||
void print_reg_f(char str[8][9], ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
|
||||
for(int i = 0; i < 8; i++)
|
||||
{
|
||||
uint32_t ptr = va_arg(args, uint32_t);
|
||||
if(ptr == 0) sprintf(str[i], "%-8s", "");
|
||||
else sprintf(str[i], "%08x", ptr);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void print_reg(Elf32_Ehdr *elf, struct reg *r)
|
||||
{
|
||||
if(r == NULL)
|
||||
{
|
||||
printf(" (Virtual) Name: Address: Data size: "
|
||||
"Access size: f1_u8 f2_u8 f1_u16 f2_u16 "
|
||||
"f1_u32 f2_u32 f1_def f2_def Description:\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char const *name = get_virtual(elf, r->pointer_to_name);
|
||||
char const *desc = get_virtual(elf, r->pointer_to_description);
|
||||
|
||||
char s1[9], s2[9];
|
||||
|
||||
sprintf(s1, "%08x", r->data_size);
|
||||
if(r->data_size == 1) sprintf(s1, "u8");
|
||||
if(r->data_size == 2) sprintf(s1, "u16");
|
||||
if(r->data_size == 4) sprintf(s1, "u32");
|
||||
|
||||
sprintf(s2, "%08x", r->access_size);
|
||||
if(r->access_size == 1) sprintf(s2, "u8");
|
||||
if(r->access_size == 2) sprintf(s2, "u16");
|
||||
if(r->access_size == 4) sprintf(s2, "u32");
|
||||
|
||||
char fstr[8][9];
|
||||
print_reg_f(fstr, r->f1_u8, r->f2_u8, r->f1_u16, r->f2_u16, r->f1_u32,
|
||||
r->f2_u32, r->f1_other, r->f2_other);
|
||||
|
||||
printf(" %-16s %08x %-8s %-8s ", name, r->address, s1, s2);
|
||||
for(int i = 0; i < 8; i++) printf("%s ", fstr[i]);
|
||||
printf(" %s\n", desc);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int e;
|
||||
assert(sizeof(struct module) == 0x78);
|
||||
assert(sizeof(struct reg) == 0x7c);
|
||||
|
||||
char const *input = (argc == 1) ? "CPU73050.elf" : argv[1];
|
||||
printf("Extracting register lists from %s\n\n", input);
|
||||
|
||||
int fd = open(input, O_RDONLY);
|
||||
if(fd < 0) { perror("open"); return 1; }
|
||||
|
||||
struct stat statbuf;
|
||||
e = fstat(fd, &statbuf);
|
||||
if(e < 0) { perror("fstat"); close(fd); return 1; }
|
||||
|
||||
void *buf = malloc(statbuf.st_size);
|
||||
if(!buf) { perror("malloc"); close(fd); return 1; }
|
||||
|
||||
e = read(fd, buf, statbuf.st_size);
|
||||
close(fd);
|
||||
if(e != statbuf.st_size) { perror("read"); return 1; }
|
||||
|
||||
/** Parse ELF header **/
|
||||
|
||||
Elf32_Ehdr *elf = buf;
|
||||
check_header(elf);
|
||||
print_sections(elf);
|
||||
|
||||
/** List modules **/
|
||||
|
||||
struct module *modules = get_virtual(elf, MODULE_LIST);
|
||||
printf("\nModule list:\n");
|
||||
print_module(elf, NULL);
|
||||
|
||||
for(int i = 0; 1; i++)
|
||||
{
|
||||
struct module *m = &modules[i];
|
||||
if(!valid_looking_module(elf, m)) break;
|
||||
printf(" %08x ", MODULE_LIST + i*(int)sizeof(struct module));
|
||||
print_module(elf, m);
|
||||
}
|
||||
|
||||
/** List virtual addresses of tables **/
|
||||
|
||||
uint32_t TABLE_LIST = *(uint32_t *)get_virtual(elf,TABLE_LIST_ADDRESS);
|
||||
uint32_t *tables = get_virtual(elf, TABLE_LIST);
|
||||
|
||||
printf("\nThe table list at %08x (HARDCODED) has these tables:\n",
|
||||
TABLE_LIST);
|
||||
|
||||
for(int i = 0; tables[i]; i++)
|
||||
{
|
||||
printf(" %08x", tables[i]);
|
||||
if((i % 8) == 7 || !tables[i+1]) printf("\n");
|
||||
}
|
||||
|
||||
/** List contents of tables **/
|
||||
|
||||
int total = 0;
|
||||
|
||||
for(int i = 0; tables[i]; i++)
|
||||
{
|
||||
uint32_t entry = tables[i];
|
||||
struct reg *table = get_virtual(elf, entry);
|
||||
|
||||
char header[256];
|
||||
sprintf(header, "\nIn the table at %08x:\n", entry);
|
||||
int header_printed = 0;
|
||||
|
||||
int k = 0;
|
||||
while(valid_looking_reg(elf, table + k))
|
||||
{
|
||||
if(!header_printed)
|
||||
{
|
||||
printf("%s", header);
|
||||
print_reg(elf, NULL);
|
||||
header_printed = 1;
|
||||
}
|
||||
|
||||
struct reg *r = table + k;
|
||||
printf(" %08x ", entry + k * (int)sizeof(struct reg));
|
||||
print_reg(elf, r);
|
||||
|
||||
k++;
|
||||
}
|
||||
total += k;
|
||||
|
||||
if(k == 0)
|
||||
{
|
||||
/* Try to view it as a string */
|
||||
uint8_t const *str = (void *)table;
|
||||
if(valid_looking_string(str))
|
||||
{
|
||||
printf("\nThe table at %08x is a string:\n",
|
||||
entry);
|
||||
printf(" %s\n", str);
|
||||
}
|
||||
else printf("\nNothing in the table at %08x\n", entry);
|
||||
}
|
||||
}
|
||||
|
||||
free(elf);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue