#include #include #include #include #include #include #include #include #include #include //--- // 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; }