#include #include #include #include #include #include #include #include #include #include //--- // Structure of CPU73050.dll //--- /* Large tabe of [struct module] objects */ uint32_t const MODULE_TABLE = 0x100903e4; /* List of register tables, pin input tables, pin output tables, and setting tables (one of each per module) */ uint32_t const REGISTER_TABLE_LIST = 0x10090184; uint32_t const PIN_INPUT_TABLE_LIST = 0x1009021c; uint32_t const PIN_OUTPUT_TABLE_LIST = 0x100902b4; uint32_t const SETTING_TABLE_LIST = 0x1009034c; /* These function pointers are trivial reads used at a lot of places */ uint32_t const REGu8_fun1_generic = 0x10028982; uint32_t const REGu16_fun1_generic = 0x10028987; uint32_t const REGu32_fun1_generic = 0x1002898b; /* 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_1[4]; uint32_t register_count; uint32_t pin_input_count; uint32_t pin_output_count; uint32_t setting_count; uint32_t unknown_2[20]; }; /* 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]; }; struct pin_input { uint32_t pointer_to_name; uint32_t pointer_to_description; uint32_t unknown_1[3]; uint32_t zero_1[6]; /* Always zero in reachable instances */ uint32_t func; uint32_t zero_2[6]; /* Always zero in reachable instances */ }; struct pin_output { uint32_t pointer_to_name; uint32_t pointer_to_description; uint32_t unknown[3]; uint32_t zero_1[4]; /* Always zero in reachable instances */ }; struct setting { uint32_t pointer_to_name; uint32_t pointer_to_description; uint32_t zero_1[1]; /* Always zero in reachable instances */ uint32_t unknown; uint32_t zero_2[3]; /* Always zero in reachable instances */ uint32_t func1; uint32_t func2; uint32_t zero_3[3]; /* Always zero in reachable instances */ }; //--- // 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; } //--- // 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][32], ...) { 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 if(ptr == REGu8_fun1_generic || ptr == REGu16_fun1_generic || ptr == REGu32_fun1_generic) { sprintf(str[i], "\x1b[32m%08x\x1b[0m", ptr); } else { sprintf(str[i], "%08x", ptr); } } va_end(args); } void print_reg(Elf32_Ehdr *elf, struct reg *r) { if(r == NULL) { printf(" Name: Address: Data size: " "Access size: read8 write8 read16 write16 " "read32 write32 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][32]; 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); } void print_pin_input(Elf32_Ehdr *elf, struct pin_input *p) { if(p == NULL) { printf(" Name: ?1: ?2: ?3: func: " "Description:\n"); return; } char const *name = get_virtual(elf, p->pointer_to_name); char const *desc = get_virtual(elf, p->pointer_to_description); printf(" %-8s %08x %08x %08x %08x %s\n", name, p->unknown_1[0], p->unknown_1[1], p->unknown_1[2], p->func, desc); } void print_pin_output(Elf32_Ehdr *elf, struct pin_output *p) { if(p == NULL) { printf(" Name: ?1: ?2: ?3: " "Description:\n"); return; } char const *name = get_virtual(elf, p->pointer_to_name); char const *desc = get_virtual(elf, p->pointer_to_description); printf(" %-8s %08x %08x %08x %s\n", name, p->unknown[0], p->unknown[1], p->unknown[2], desc); } void print_setting(Elf32_Ehdr *elf, struct setting *s) { if(s == NULL) { printf(" Name: ?1: func1: func2: " "Description:\n"); return; } char const *name = get_virtual(elf, s->pointer_to_name); char const *desc = get_virtual(elf, s->pointer_to_description); printf(" %-8s %08x %08x %08x %s\n", name, s->unknown, s->func1, s->func2, 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); /** Reminder of extracted addresses **/ printf("\nAddresses extracted via reverse-engineering:\n"); printf(" Module table: 100903e4\n"); printf(" Register table list: 10090184\n"); printf(" Pin input table list: 1009021c\n"); printf(" Pin output table list: 100902b4\n"); printf(" Setting table list: 1009034c\n"); /** List modules **/ struct module *modules = get_virtual(elf, MODULE_TABLE); printf("\nModule list:\n"); print_module(elf, NULL); int i = 0; while(1) { struct module *m = &modules[i]; if(!valid_looking_module(elf, m)) break; printf(" %08x ", MODULE_TABLE + i*(int)sizeof(struct module)); print_module(elf, m); i++; } int module_count = i - 1; printf("Total: %d modules (excluding CPU73050)\n", module_count); /** Print information for each module **/ uint32_t *register_tables = get_virtual(elf, REGISTER_TABLE_LIST); uint32_t *pin_input_tables = get_virtual(elf, PIN_INPUT_TABLE_LIST); uint32_t *pin_output_tables = get_virtual(elf, PIN_OUTPUT_TABLE_LIST); uint32_t *setting_tables = get_virtual(elf, SETTING_TABLE_LIST); int entry_count = 0; for(int i = 0; i < module_count; i++) { struct reg *regs = get_virtual(elf, register_tables[i]); struct pin_input *pin_inputs = get_virtual(elf, pin_input_tables[i]); struct pin_output *pin_outputs = get_virtual(elf, pin_output_tables[i]); struct setting *settings = get_virtual(elf, setting_tables[i]); struct module *m = &modules[i]; char *name = get_virtual(elf, m->pointer_to_name); printf("\nRegister table for %s (%d registers):\n", name, m->register_count); if(m->register_count) { print_reg(elf, NULL); for(uint k = 0; k < m->register_count; k++) print_reg(elf, regs + k); } else printf(" No registers!\n"); if(m->pin_input_count) { printf("Pin input table for %s (%d pins):\n", name, m->pin_input_count); print_pin_input(elf, NULL); for(uint k = 0; k < m->pin_input_count; k++) print_pin_input(elf, pin_inputs + k); } if(m->pin_output_count) { printf("Pin output table for %s (%d pins):\n", name, m->pin_output_count); print_pin_output(elf, NULL); for(uint k = 0; k < m->pin_output_count; k++) print_pin_output(elf, pin_outputs + k); } if(m->setting_count) { printf("Setting table for %s (%d settings):\n", name, m->setting_count); print_setting(elf, NULL); for(uint k = 0; k < m->setting_count; k++) print_setting(elf, settings + k); } entry_count += m->register_count; entry_count += m->pin_input_count; entry_count += m->pin_output_count; entry_count += m->setting_count; } printf("\nFound a total of %d objects.\n", entry_count); free(elf); return 0; }