/* * vobjdump * Views the contents of a VOBJ file. * Written by Frank Wille . */ /* VOBJ Format (WILL CHANGE!): .byte 0x56,0x4f,0x42,0x4a .byte flags 1: BIGENDIAN 2: LITTLENDIAN .number bitsperbyte .number bytespertaddr .string cpu .number nsections [1-based] .number nsymbols [1-based] nsymbols .string name .number type .number flags .number secindex .number val .number size nsections .string name .string attr .number flags .number align .number size .number nrelocs .number databytes .byte[databytes] nrelocs [standard|special] standard .number type .number byteoffset .number bitoffset .number size .number mask .number addend .number symbolindex | 0 (sectionbase) special .number type .number size .byte[size] .number:[taddr] .byte 0--127 [0--127] .byte 128-255 [x-0x80 bytes little-endian] */ #include "vobjdump.h" static const char *endian_name[] = { "big", "little" }; static const char emptystr[] = ""; static const char sstr[] = "s"; static const char *reloc_name[] = { "NONE","ABS","PC","GOT","GOTPC","GOTOFF","GLOBDAT","PLT","PLTPC","PLTOFF", "SD","UABS","LOCALPC","LOADREL","COPY","JMPSLOT","SECOFF",NULL }; static const char *type_name[] = { "","obj","func","sect","file",NULL }; static ubyte *vobj; /* base address of VOBJ buffer */ static size_t vlen; /* length of VOBJ file in buffer */ static ubyte *p; /* current object pointer */ static int bpb,bpt; /* bits per byte, bytes per taddr */ static taddr bptmask; /* mask LSB to fit bytes per taddr */ #define BPTMASK(x) (unsigned long long)((x)&bptmask) static void print_sep(void) { printf("\n------------------------------------------------------------" "------------------\n"); } static taddr read_number(int is_signed) { taddr val; ubyte n,*q; int size; if (p=vobj+vlen) { corrupt: fprintf(stderr,"\nObject file is corrupt! Aborting.\n"); exit(1); } if ((n = *p++) <= 0x7f) return (taddr)n; val = 0; if (n -= 0x80) { size = n << 3; p += n; q = p; if (p > vobj+vlen) goto corrupt; while (n--) val = (val<<8) | *(--q); if (is_signed && (val & (1LL<<(size-1)))) val |= ~makemask(size); } return val; } static void skip_string(void) { if (p < vobj) goto corrupt; while (*p) { p++; if (p >= vobj+vlen) { corrupt: fprintf(stderr,"\nObject file is corrupt! Aborting.\n"); exit(1); } } p++; } static void read_symbol(struct vobj_symbol *vsym) { vsym->offs = p - vobj; vsym->name = (const char *)p; skip_string(); vsym->type = (int)read_number(0); vsym->flags = (int)read_number(0); vsym->sec = (int)read_number(0); vsym->val = read_number(1); vsym->size = (int)read_number(0); } static void read_section(struct vobj_section *vsect, struct vobj_symbol *vsym,int nsyms) { const char *attr; unsigned long flags; int align,nrelocs,i; vsect->offs = p - vobj; vsect->name = p; skip_string(); attr = p; skip_string(); flags = (unsigned long)read_number(0); align = (int)read_number(0); vsect->dsize = read_number(0); nrelocs = (int)read_number(0); vsect->fsize = read_number(0); print_sep(); printf("%08llx: SECTION \"%s\" (attributes=\"%s\")\n" "Flags: %-8lx Alignment: %-6d " "Total size: %-9lld File size: %-9lld\n", BPTMASK(vsect->offs),vsect->name,attr,flags,align, vsect->dsize,vsect->fsize); if (nrelocs) printf("%d Relocation%s present.\n",nrelocs,nrelocs==1?emptystr:sstr); p += vsect->fsize; /* skip section contents */ /* read and print relocations for this section */ for (i=0; i>3)>=vsect->dsize) { printf("offset 0x%llx is outside of section!\n", BPTMASK(offs+(bpos>>3))); continue; } if (sym<0 || sym>=nsyms) { printf("symbol index %d is illegal!\n",sym+1); continue; } if (bsiz<0 || bsiz>bpt*bpb) { printf("size of %d bits is illegal!\n",bsiz); continue; } if (bpos<0 || bpos+bsiz>bpt*bpb) { printf("bit field start=%d, size=%d doesn't fit into target address " "type (%d bits)!\n",bpos,bsiz,bpt*bpb); continue; } basesym = vsym[sym].name; if (!strncmp(basesym," *current pc",12)) { basesym = vsect->name; /*addend += offs;*/ } printf("%08llx %02d %02d %8llx %-8s %s%+lld\n", BPTMASK(offs),bpos,bsiz,BPTMASK(mask), reloc_name[type],basesym,addend); } else { /* non-standard relocation */ taddr rsize; rsize = read_number(0); /* size of special relocation entry */ if (rsize < 0) { printf("Bad special relocation size (%d)!\n",(int)rsize); exit(1); } p += rsize; if (pvobj+vlen) break; printf("special relocation type %-3d with a size of %d bytes\n", (int)type,(int)rsize); } } if (pvobj+vlen) { fprintf(stderr,"\nSection \"%s\" is corrupt! Aborting.\n",vsect->name); exit(1); } } static const char *bind_name(int flags) { if (flags & WEAK) return "WEAK"; if (flags & EXPORT) return "GLOB"; if (flags & COMMON) return "COMM"; return "LOCL"; } static const char *def_name(struct vobj_symbol *vs, struct vobj_section *sec,int nsecs) { switch (vs->type) { case EXPRESSION: return "*ABS*"; case IMPORT: return "*UND*"; case LABSYM: if (vs->sec>0 && vs->sec<=nsecs) return sec[vs->sec-1].name; } return "???"; } static int vobjdump(void) { p = vobj; if (vlen>4 && p[0]==0x56 && p[1]==0x4f && p[2]==0x42 && p[3]==0x4a) { int endian,nsecs,nsyms,i; const char *cpu_name; struct vobj_symbol *vsymbols = NULL; struct vobj_section *vsect = NULL; p += 4; /* skip ID */ endian = (int)*p++; /* endianess */ if (endian<1 || endian>2) { fprintf(stderr,"Wrong endianess: %d\n",endian); return 1; } bpb = (int)read_number(0); /* bits per byte */ if (bpb != 8) { fprintf(stderr,"%d bits per byte not supported!\n",bpb); return 1; } bpt = (int)read_number(0); /* bytes per taddr */ if (bpt > sizeof(taddr)) { fprintf(stderr,"%d bytes per taddr not supported!\n",bpt); return 1; } bptmask = makemask(bpt*bpb); cpu_name = p; skip_string(); /* skip cpu-string */ nsecs = (int)read_number(0); /* number of sections */ nsyms = (int)read_number(0); /* number of symbols */ /* print header */ print_sep(); printf("VOBJ %s (%s endian), %d bits per byte, %d bytes per word.\n" "%d symbol%s.\n%d section%s.\n", cpu_name,endian_name[endian-1],bpb,bpt, nsyms,nsyms==1?emptystr:sstr,nsecs,nsecs==1?emptystr:sstr); /* read symbols */ if (nsyms) { if (vsymbols = malloc(nsyms * sizeof(struct vobj_symbol))) { for (i=0; iname," *current pc",12)) continue; printf("%08llx: %-4s %08x %-4s %8.8s %8llx %s\n", BPTMASK(vs->offs),bind_name(vs->flags),(unsigned)vs->size, type_name[TYPE(vs)],def_name(vs,vsect,nsecs), BPTMASK(vs->val),vs->name); } } else { fprintf(stderr,"Not a VOBJ file!\n"); return 1; } return 0; } static size_t filesize(FILE *fp,const char *name) { long oldpos,size; if ((oldpos = ftell(fp)) >= 0) if (fseek(fp,0,SEEK_END) >= 0) if ((size = ftell(fp)) >= 0) if (fseek(fp,oldpos,SEEK_SET) >= 0) return (size_t)size; fprintf(stderr,"Cannot determine size of file \"%s\"!\n",name); return 0; } int main(int argc,char *argv[]) { int rc = 1; if (argc == 2) { FILE *f; if (f = fopen(argv[1],"rb")) { if (vlen = filesize(f,argv[1])) { if (vobj = malloc(vlen)) { if (fread(vobj,1,vlen,f) == vlen) rc = vobjdump(); else fprintf(stderr,"Read error on \"%s\"!\n",argv[1]); free(vobj); } else fprintf(stderr,"Unable to allocate %lu bytes " "to buffer file \"%s\"!\n",vlen,argv[1]); } fclose(f); } else fprintf(stderr,"Cannot open \"%s\" for reading!\n",argv[1]); } else fprintf(stderr,"vobjdump V0.5\nWritten by Frank Wille\n" "Usage: %s \n",argv[0]); return rc; }