FreeCalypso > hg > freecalypso-reveng
view leo-obj/tool/richsym.c @ 162:8d30e1722e0f
locked C139 bootloader reverse-engineered
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Thu, 15 May 2014 20:55:39 +0000 |
parents | 15743b40e03a |
children | f7943bdbb3ea |
line wrap: on
line source
/* * Code for working with the "rich" symbolic info * present in TI's GPF libraries */ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include "intstruct.h" #include "coffconst.h" #include "globals.h" extern unsigned get_u16(), get_u32(); extern char *storage_class_to_string(); int richsym_print_bitsize; static int try_typedef_hack(struct_sym) struct internal_syment *struct_sym; { unsigned tpdef_cand; struct internal_syment *tpdef_sym; if (!struct_sym->aux) return(0); tpdef_cand = get_u32(struct_sym->aux + 12); if (tpdef_cand >= nsymtab) return(0); tpdef_sym = symtab[tpdef_cand]; if (!tpdef_sym) return(0); if (tpdef_sym->class != C_TPDEF) return(0); if (tpdef_sym->type != struct_sym->type) return(0); if (tpdef_sym->name[0] != '_') return(0); if (!tpdef_sym->aux) return(0); if (get_u32(tpdef_sym->aux) != struct_sym->number) return(0); struct_sym->struct_name = tpdef_sym->name + 1; return(1); } static void preen_strtag_sym(sym, kw, expect_type) struct internal_syment *sym; char *kw; { char *buf; int isund, len; isund = (sym->name[0] == '_'); len = strlen(kw) + 1 + strlen(sym->name) + 1; if (isund) len--; else len += 2; buf = malloc(len); if (!buf) { perror("malloc"); exit(1); } if (isund) sprintf(buf, "%s %s", kw, sym->name + 1); else sprintf(buf, "%s \"%s\"", kw, sym->name); sym->struct_name = buf; sym->struct_name_raw = buf; if (sym->type != expect_type) { fprintf(stderr, "warning: type/class mismatch on tag symbol #%u\n", sym->number); return; } if (isund) return; try_typedef_hack(sym); } richsym_initial_preen() { unsigned n; struct internal_syment *sym; for (n = 0; n < nsymtab; n++) { sym = symtab[n]; if (!sym) continue; switch (sym->class) { case C_STRTAG: preen_strtag_sym(sym, "struct", T_STRUCT); continue; case C_UNTAG: preen_strtag_sym(sym, "union", T_UNION); continue; case C_ENTAG: preen_strtag_sym(sym, "enum", T_ENUM); continue; } } } char * get_struct_type_name(idx, expect_class, is_typedef) unsigned idx; { struct internal_syment *sym; if (idx >= nsymtab) { inv_idx: fprintf(stderr, "error: ref to invalid syment #%u for struct tag\n", idx); exit(1); } sym = symtab[idx]; if (!sym) goto inv_idx; if (sym->class != expect_class) { fprintf(stderr, "error: ref to syment #%u for struct tag, class != %s\n", idx, storage_class_to_string(expect_class, 0)); exit(1); } if (is_typedef) return(sym->struct_name_raw); else return(sym->struct_name); } char * get_base_type_of_syment(sym, is_typedef) struct internal_syment *sym; { unsigned idx; switch (sym->type & 0xF) { case T_VOID: return("void"); case T_CHAR: if (is_typedef) return("signed char"); else return("char"); case T_SHORT: return("short"); case T_INT: return("int"); case T_LONG: return("long"); case T_FLOAT: return("float"); case T_DOUBLE: return("double"); case T_STRUCT: idx = get_u32(sym->aux); if (idx) return get_struct_type_name(idx, C_STRTAG, is_typedef); else return("struct ?"); case T_UNION: idx = get_u32(sym->aux); if (idx) return get_struct_type_name(idx, C_UNTAG, is_typedef); else return("union ?"); case T_ENUM: idx = get_u32(sym->aux); if (idx) return get_struct_type_name(idx, C_ENTAG, is_typedef); else return("enum ?"); case T_UCHAR: if (is_typedef) return("unsigned char"); else return("u_char"); case T_USHORT: if (is_typedef) return("unsigned short"); else return("u_short"); case T_UINT: return("unsigned"); case T_ULONG: if (is_typedef) return("unsigned long"); else return("u_long"); default: return("__unknown_base_type"); } } static char * cdecl_obj_name(sym) struct internal_syment *sym; { char *buf; int isund, len; switch (sym->name[0]) { case '_': isund = 1; break; case '$': if ((sym->type & 0x30) == 0x20) isund = 1; else isund = 0; break; default: isund = 0; } len = strlen(sym->name) + 1; if (isund) len--; else len += 2; buf = malloc(len); if (!buf) { perror("malloc"); exit(1); } if (isund) strcpy(buf, sym->name + 1); else sprintf(buf, "\"%s\"", sym->name); return(buf); } richsym_print_in_c(prefix, sym, is_typedef) char *prefix; struct internal_syment *sym; { char *base_type, *s1, *s2; int dertype, last_ptr, narray; base_type = get_base_type_of_syment(sym, is_typedef); dertype = sym->type >> 4; s1 = cdecl_obj_name(sym); last_ptr = 0; narray = 0; for (; dertype; dertype >>= 2) { switch (dertype & 3) { case DT_NON: fprintf(stderr, "error: symbol #%u: DT_NON followed by more derived types\n", sym->number); exit(1); case DT_PTR: s2 = malloc(strlen(s1) + 2); if (!s2) { perror("malloc"); exit(1); } sprintf(s2, "*%s", s1); free(s1); s1 = s2; last_ptr = 1; continue; } if (last_ptr) { s2 = malloc(strlen(s1) + 3); if (!s2) { perror("malloc"); exit(1); } sprintf(s2, "(%s)", s1); free(s1); s1 = s2; } switch (dertype & 3) { case DT_FCN: s2 = malloc(strlen(s1) + 3); if (!s2) { perror("malloc"); exit(1); } sprintf(s2, "%s()", s1); free(s1); s1 = s2; break; case DT_ARY: if (narray >= 4) { fprintf(stderr, "error: symbol #%u: too many [] types\n", sym->number); exit(1); } s2 = malloc(strlen(s1) + 8); if (!s2) { perror("malloc"); exit(1); } sprintf(s2, "%s[%u]", s1, get_u16(sym->aux + 8 + narray * 2)); free(s1); s1 = s2; narray++; break; default: fprintf(stderr, "BUG in richsym_print_in_c(): bad derived type\n"); exit(1); } last_ptr = 0; } printf("%s%s %s;", prefix, base_type, s1); free(s1); if (richsym_print_bitsize && (sym->type & 0x30) != 0x20) printf("\t/* %u bits */", get_u32(sym->aux + 4)); putchar('\n'); } cmd_ctypes(argc, argv) char **argv; { int c; unsigned n; struct internal_syment *sym; int print_offsets = 0; while ((c = getopt(argc, argv, "bo")) != EOF) switch (c) { case 'b': richsym_print_bitsize++; continue; case 'o': print_offsets++; continue; default: /* error msg already printed */ exit(1); } get_int_section_table(); get_int_symbol_table(); richsym_initial_preen(); for (n = 0; n < nsymtab; n++) { sym = symtab[n]; if (!sym) continue; switch (sym->class) { case C_FILE: printf("/* from %s */\n", sym->name); continue; case C_STRTAG: case C_UNTAG: case C_ENTAG: printf("%s {", sym->struct_name_raw); if (richsym_print_bitsize && sym->aux) printf("\t/* %u bits */", get_u32(sym->aux+4)); putchar('\n'); continue; case C_EOS: fputs("};", stdout); if (richsym_print_bitsize && sym->aux) printf("\t/* %u bits */", get_u32(sym->aux+4)); putchar('\n'); continue; case C_MOS: case C_MOU: case C_MOE: case C_TPDEF: break; default: continue; } if (sym->name[0] != '_') { printf( "/* symbol #%u of class %s has no leading underscore */\n", sym->number, storage_class_to_string(sym->class, 0)); continue; } if (!sym->aux && sym->class != C_MOE) { printf( "/* symbol #%u of class %s has no aux record */\n", sym->number, storage_class_to_string(sym->class, 0)); continue; } switch (sym->class) { case C_MOS: case C_MOU: if (sym->scnum != -1) printf("\t/* MOS/MOU section != ABS! */\n"); else if (print_offsets && !(sym->value & 7)) printf("\t/* offset: 0x%x */\n", sym->value >> 3); else if (print_offsets || richsym_print_bitsize >= 2) printf("\t/* offset: %u bits */\n", sym->value); richsym_print_in_c("\t", sym, 0); continue; case C_MOE: if (sym->scnum != -1) { printf("\t/* MOE section != ABS! */\n"); continue; } printf("\t%s = %u;", sym->name + 1, sym->value); if (sym->value >= 10) printf("\t/* 0x%x */", sym->value); putchar('\n'); continue; case C_TPDEF: richsym_print_in_c("typedef ", sym, !(sym->type & 0xFFF0)); continue; } } exit(0); } static int localsym_sanity_check(sym) struct internal_syment *sym; { if (!sym->aux) { printf("; symbol #%u of class %s has no aux record\n", sym->number, storage_class_to_string(sym->class, 0)); return(-1); } if (sym->scnum != -1) { printf("; symbol #%u of class %s: section != ABS\n", sym->number, storage_class_to_string(sym->class, 0)); return(-1); } return(0); } richsym_function_locals(headsym) struct internal_syment *headsym; { unsigned n, count = 0; struct internal_syment *sym; char classbuf[8]; for (n = headsym->number + 1; n < nsymtab; n++) { sym = symtab[n]; if (!sym) continue; switch (sym->class) { case C_REG: case C_REGPARM: count++; if (localsym_sanity_check(sym) < 0) continue; if (sym->value > 0xF) { printf( "; symbol #%u of class %s: value is not a valid register number\n", sym->number, storage_class_to_string(sym->class, 0)); continue; } printf("; %s r%u: ", storage_class_to_string(sym->class, 0), sym->value); richsym_print_in_c("", sym, 0); continue; case C_ARG: case C_AUTO: count++; if (localsym_sanity_check(sym) < 0) continue; printf("; %s at 0x%x: ", storage_class_to_string(sym->class, 0), sym->value); richsym_print_in_c("", sym, 0); continue; case C_FCN: return(count); default: count++; printf( "; presumed local symbol #%u: unexpected class %s\n", sym->number, storage_class_to_string(sym->class, classbuf)); return(count); } } return(count); }