| /* Read and manage MIPS symbol tables from object modules. |
| Copyright (C) 1991, 1994, 1995 Free Software Foundation, Inc. |
| Contributed by hartzell@boulder.colorado.edu, |
| Rewritten by meissner@osf.org. |
| |
| This file is part of GNU CC. |
| |
| GNU CC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU CC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU CC; see the file COPYING. If not, write to |
| the Free Software Foundation, 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. */ |
| |
| #include <stdio.h> |
| #include <sys/types.h> |
| #include <sys/file.h> |
| #include <time.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include "config.h" |
| |
| #ifdef index |
| #undef index |
| #undef rindex |
| #endif |
| #ifndef CROSS_COMPILE |
| #include <a.out.h> |
| #else |
| #include "mips/a.out.h" |
| #endif /* CROSS_COMPILE */ |
| |
| #ifndef MIPS_IS_STAB |
| /* Macros for mips-tfile.c to encapsulate stabs in ECOFF, and for |
| and mips-tdump.c to print them out. This is used on the Alpha, |
| which does not include mips.h. |
| |
| These must match the corresponding definitions in gdb/mipsread.c. |
| Unfortunately, gcc and gdb do not currently share any directories. */ |
| |
| #define CODE_MASK 0x8F300 |
| #define MIPS_IS_STAB(sym) (((sym)->index & 0xFFF00) == CODE_MASK) |
| #define MIPS_MARK_STAB(code) ((code)+CODE_MASK) |
| #define MIPS_UNMARK_STAB(code) ((code)-CODE_MASK) |
| #endif |
| |
| #ifdef __STDC__ |
| typedef void *PTR_T; |
| typedef const void *CPTR_T; |
| #define __proto(x) x |
| #else |
| |
| #if defined(_STDIO_H_) || defined(__STDIO_H__) /* Ultrix 4.0, SGI */ |
| typedef void *PTR_T; |
| typedef void *CPTR_T; |
| |
| #else |
| typedef char *PTR_T; /* Ultrix 3.1 */ |
| typedef char *CPTR_T; |
| #endif |
| |
| #define __proto(x) () |
| #define const |
| #endif |
| |
| #define uchar unsigned char |
| #define ushort unsigned short |
| #define uint unsigned int |
| #define ulong unsigned long |
| |
| |
| /* Do to size_t being defined in sys/types.h and different |
| in stddef.h, we have to do this by hand..... Note, these |
| types are correct for MIPS based systems, and may not be |
| correct for other systems. */ |
| |
| #define size_t uint |
| #define ptrdiff_t int |
| |
| |
| /* Redefinition of of storage classes as an enumeration for better |
| debugging. */ |
| |
| #ifndef stStaParam |
| #define stStaParam 16 /* Fortran static parameters */ |
| #endif |
| |
| #ifndef btVoid |
| #define btVoid 26 /* void basic type */ |
| #endif |
| |
| typedef enum sc { |
| sc_Nil = scNil, /* no storage class */ |
| sc_Text = scText, /* text symbol */ |
| sc_Data = scData, /* initialized data symbol */ |
| sc_Bss = scBss, /* un-initialized data symbol */ |
| sc_Register = scRegister, /* value of symbol is register number */ |
| sc_Abs = scAbs, /* value of symbol is absolute */ |
| sc_Undefined = scUndefined, /* who knows? */ |
| sc_CdbLocal = scCdbLocal, /* variable's value is IN se->va.?? */ |
| sc_Bits = scBits, /* this is a bit field */ |
| sc_CdbSystem = scCdbSystem, /* var's value is IN CDB's address space */ |
| sc_RegImage = scRegImage, /* register value saved on stack */ |
| sc_Info = scInfo, /* symbol contains debugger information */ |
| sc_UserStruct = scUserStruct, /* addr in struct user for current process */ |
| sc_SData = scSData, /* load time only small data */ |
| sc_SBss = scSBss, /* load time only small common */ |
| sc_RData = scRData, /* load time only read only data */ |
| sc_Var = scVar, /* Var parameter (fortran,pascal) */ |
| sc_Common = scCommon, /* common variable */ |
| sc_SCommon = scSCommon, /* small common */ |
| sc_VarRegister = scVarRegister, /* Var parameter in a register */ |
| sc_Variant = scVariant, /* Variant record */ |
| sc_SUndefined = scSUndefined, /* small undefined(external) data */ |
| sc_Init = scInit, /* .init section symbol */ |
| sc_Max = scMax /* Max storage class+1 */ |
| } sc_t; |
| |
| /* Redefinition of symbol type. */ |
| |
| typedef enum st { |
| st_Nil = stNil, /* Nuthin' special */ |
| st_Global = stGlobal, /* external symbol */ |
| st_Static = stStatic, /* static */ |
| st_Param = stParam, /* procedure argument */ |
| st_Local = stLocal, /* local variable */ |
| st_Label = stLabel, /* label */ |
| st_Proc = stProc, /* " " Procedure */ |
| st_Block = stBlock, /* beginning of block */ |
| st_End = stEnd, /* end (of anything) */ |
| st_Member = stMember, /* member (of anything - struct/union/enum */ |
| st_Typedef = stTypedef, /* type definition */ |
| st_File = stFile, /* file name */ |
| st_RegReloc = stRegReloc, /* register relocation */ |
| st_Forward = stForward, /* forwarding address */ |
| st_StaticProc = stStaticProc, /* load time only static procs */ |
| st_StaParam = stStaParam, /* Fortran static parameters */ |
| st_Constant = stConstant, /* const */ |
| #ifdef stStruct |
| st_Struct = stStruct, /* struct */ |
| st_Union = stUnion, /* union */ |
| st_Enum = stEnum, /* enum */ |
| #endif |
| st_Str = stStr, /* string */ |
| st_Number = stNumber, /* pure number (ie. 4 NOR 2+2) */ |
| st_Expr = stExpr, /* 2+2 vs. 4 */ |
| st_Type = stType, /* post-coercion SER */ |
| st_Max = stMax /* max type+1 */ |
| } st_t; |
| |
| /* Redefinition of type qualifiers. */ |
| |
| typedef enum tq { |
| tq_Nil = tqNil, /* bt is what you see */ |
| tq_Ptr = tqPtr, /* pointer */ |
| tq_Proc = tqProc, /* procedure */ |
| tq_Array = tqArray, /* duh */ |
| tq_Far = tqFar, /* longer addressing - 8086/8 land */ |
| tq_Vol = tqVol, /* volatile */ |
| tq_Max = tqMax /* Max type qualifier+1 */ |
| } tq_t; |
| |
| /* Redefinition of basic types. */ |
| |
| typedef enum bt { |
| bt_Nil = btNil, /* undefined */ |
| bt_Adr = btAdr, /* address - integer same size as pointer */ |
| bt_Char = btChar, /* character */ |
| bt_UChar = btUChar, /* unsigned character */ |
| bt_Short = btShort, /* short */ |
| bt_UShort = btUShort, /* unsigned short */ |
| bt_Int = btInt, /* int */ |
| bt_UInt = btUInt, /* unsigned int */ |
| bt_Long = btLong, /* long */ |
| bt_ULong = btULong, /* unsigned long */ |
| bt_Float = btFloat, /* float (real) */ |
| bt_Double = btDouble, /* Double (real) */ |
| bt_Struct = btStruct, /* Structure (Record) */ |
| bt_Union = btUnion, /* Union (variant) */ |
| bt_Enum = btEnum, /* Enumerated */ |
| bt_Typedef = btTypedef, /* defined via a typedef, isymRef points */ |
| bt_Range = btRange, /* subrange of int */ |
| bt_Set = btSet, /* pascal sets */ |
| bt_Complex = btComplex, /* fortran complex */ |
| bt_DComplex = btDComplex, /* fortran double complex */ |
| bt_Indirect = btIndirect, /* forward or unnamed typedef */ |
| bt_FixedDec = btFixedDec, /* Fixed Decimal */ |
| bt_FloatDec = btFloatDec, /* Float Decimal */ |
| bt_String = btString, /* Varying Length Character String */ |
| bt_Bit = btBit, /* Aligned Bit String */ |
| bt_Picture = btPicture, /* Picture */ |
| bt_Void = btVoid, /* void */ |
| bt_Max = btMax /* Max basic type+1 */ |
| } bt_t; |
| |
| /* Redefinition of the language codes. */ |
| |
| typedef enum lang { |
| lang_C = langC, |
| lang_Pascal = langPascal, |
| lang_Fortran = langFortran, |
| lang_Assembler = langAssembler, |
| lang_Machine = langMachine, |
| lang_Nil = langNil, |
| lang_Ada = langAda, |
| lang_Pl1 = langPl1, |
| lang_Cobol = langCobol |
| } lang_t; |
| |
| /* Redefinition of the debug level codes. */ |
| |
| typedef enum glevel { |
| glevel_0 = GLEVEL_0, |
| glevel_1 = GLEVEL_1, |
| glevel_2 = GLEVEL_2, |
| glevel_3 = GLEVEL_3 |
| } glevel_t; |
| |
| |
| /* Keep track of the active scopes. */ |
| typedef struct scope { |
| struct scope *prev; /* previous scope */ |
| ulong open_sym; /* symbol opening scope */ |
| sc_t sc; /* storage class */ |
| st_t st; /* symbol type */ |
| } scope_t; |
| |
| struct filehdr global_hdr; /* a.out header */ |
| |
| int errors = 0; /* # of errors */ |
| int want_aux = 0; /* print aux table */ |
| int want_line = 0; /* print line numbers */ |
| int want_rfd = 0; /* print relative file desc's */ |
| int want_scope = 0; /* print scopes for every symbol */ |
| int tfile = 0; /* no global header file */ |
| int tfile_fd; /* file descriptor of .T file */ |
| off_t tfile_offset; /* current offset in .T file */ |
| scope_t *cur_scope = 0; /* list of active scopes */ |
| scope_t *free_scope = 0; /* list of freed scopes */ |
| HDRR sym_hdr; /* symbolic header */ |
| char *l_strings; /* local strings */ |
| char *e_strings; /* external strings */ |
| SYMR *l_symbols; /* local symbols */ |
| EXTR *e_symbols; /* external symbols */ |
| LINER *lines; /* line numbers */ |
| DNR *dense_nums; /* dense numbers */ |
| OPTR *opt_symbols; /* optimization symbols */ |
| AUXU *aux_symbols; /* Auxiliary symbols */ |
| char *aux_used; /* map of which aux syms are used */ |
| FDR *file_desc; /* file tables */ |
| ulong *rfile_desc; /* relative file tables */ |
| PDR *proc_desc; /* procedure tables */ |
| |
| /* Forward reference for functions. */ |
| PTR_T read_seek __proto((PTR_T, size_t, off_t, const char *)); |
| void read_tfile __proto((void)); |
| void print_global_hdr __proto((struct filehdr *)); |
| void print_sym_hdr __proto((HDRR *)); |
| void print_file_desc __proto((FDR *, int)); |
| void print_symbol __proto((SYMR *, int, char *, AUXU *, int, FDR *)); |
| void print_aux __proto((AUXU, int, int)); |
| void emit_aggregate __proto((char *, AUXU, AUXU, const char *, FDR *)); |
| char *st_to_string __proto((st_t)); |
| char *sc_to_string __proto((sc_t)); |
| char *glevel_to_string __proto((glevel_t)); |
| char *lang_to_string __proto((lang_t)); |
| char *type_to_string __proto((AUXU *, int, FDR *)); |
| |
| #ifndef __alpha |
| extern PTR_T malloc __proto((size_t)); |
| extern PTR_T calloc __proto((size_t, size_t)); |
| extern PTR_T realloc __proto((PTR_T, size_t)); |
| extern void free __proto((PTR_T)); |
| #endif |
| |
| extern char *optarg; |
| extern int optind; |
| extern int opterr; |
| |
| /* Create a table of debugging stab-codes and corresponding names. */ |
| |
| #define __define_stab(NAME, CODE, STRING) {(int)CODE, STRING}, |
| struct {short code; char string[10];} stab_names[] = { |
| #include "stab.def" |
| #undef __define_stab |
| }; |
| |
| |
| /* Read some bytes at a specified location, and return a pointer. */ |
| |
| PTR_T |
| read_seek (ptr, size, offset, context) |
| PTR_T ptr; /* pointer to buffer or NULL */ |
| size_t size; /* # bytes to read */ |
| off_t offset; /* offset to read at */ |
| const char *context; /* context for error message */ |
| { |
| long read_size = 0; |
| |
| if (size == 0) /* nothing to read */ |
| return ptr; |
| |
| if ((ptr == (PTR_T) 0 && (ptr = malloc (size)) == (PTR_T) 0) |
| || (tfile_offset != offset && lseek (tfile_fd, offset, 0) == -1) |
| || (read_size = read (tfile_fd, ptr, size)) < 0) |
| { |
| perror (context); |
| exit (1); |
| } |
| |
| if (read_size != size) |
| { |
| fprintf (stderr, "%s: read %ld bytes, expected %ld bytes\n", |
| context, read_size, (long) size); |
| exit (1); |
| } |
| |
| tfile_offset = offset + size; |
| return ptr; |
| } |
| |
| |
| /* Convert language code to string format. */ |
| |
| char * |
| lang_to_string (lang) |
| lang_t lang; |
| { |
| switch (lang) |
| { |
| case langC: return "C"; |
| case langPascal: return "Pascal"; |
| case langFortran: return "Fortran"; |
| case langAssembler: return "Assembler"; |
| case langMachine: return "Machine"; |
| case langNil: return "Nil"; |
| case langAda: return "Ada"; |
| case langPl1: return "Pl1"; |
| case langCobol: return "Cobol"; |
| } |
| |
| return "Unknown language"; |
| } |
| |
| |
| /* Convert storage class to string. */ |
| |
| char * |
| sc_to_string(storage_class) |
| sc_t storage_class; |
| { |
| switch(storage_class) |
| { |
| case sc_Nil: return "Nil"; |
| case sc_Text: return "Text"; |
| case sc_Data: return "Data"; |
| case sc_Bss: return "Bss"; |
| case sc_Register: return "Register"; |
| case sc_Abs: return "Abs"; |
| case sc_Undefined: return "Undefined"; |
| case sc_CdbLocal: return "CdbLocal"; |
| case sc_Bits: return "Bits"; |
| case sc_CdbSystem: return "CdbSystem"; |
| case sc_RegImage: return "RegImage"; |
| case sc_Info: return "Info"; |
| case sc_UserStruct: return "UserStruct"; |
| case sc_SData: return "SData"; |
| case sc_SBss: return "SBss"; |
| case sc_RData: return "RData"; |
| case sc_Var: return "Var"; |
| case sc_Common: return "Common"; |
| case sc_SCommon: return "SCommon"; |
| case sc_VarRegister: return "VarRegister"; |
| case sc_Variant: return "Variant"; |
| case sc_SUndefined: return "SUndefined"; |
| case sc_Init: return "Init"; |
| case sc_Max: return "Max"; |
| } |
| |
| return "???"; |
| } |
| |
| |
| /* Convert symbol type to string. */ |
| |
| char * |
| st_to_string(symbol_type) |
| st_t symbol_type; |
| { |
| switch(symbol_type) |
| { |
| case st_Nil: return "Nil"; |
| case st_Global: return "Global"; |
| case st_Static: return "Static"; |
| case st_Param: return "Param"; |
| case st_Local: return "Local"; |
| case st_Label: return "Label"; |
| case st_Proc: return "Proc"; |
| case st_Block: return "Block"; |
| case st_End: return "End"; |
| case st_Member: return "Member"; |
| case st_Typedef: return "Typedef"; |
| case st_File: return "File"; |
| case st_RegReloc: return "RegReloc"; |
| case st_Forward: return "Forward"; |
| case st_StaticProc: return "StaticProc"; |
| case st_Constant: return "Constant"; |
| case st_StaParam: return "StaticParam"; |
| #ifdef stStruct |
| case st_Struct: return "Struct"; |
| case st_Union: return "Union"; |
| case st_Enum: return "Enum"; |
| #endif |
| case st_Str: return "String"; |
| case st_Number: return "Number"; |
| case st_Expr: return "Expr"; |
| case st_Type: return "Type"; |
| case st_Max: return "Max"; |
| } |
| |
| return "???"; |
| } |
| |
| |
| /* Convert debug level to string. */ |
| |
| char * |
| glevel_to_string (g_level) |
| glevel_t g_level; |
| { |
| switch(g_level) |
| { |
| case GLEVEL_0: return "G0"; |
| case GLEVEL_1: return "G1"; |
| case GLEVEL_2: return "G2"; |
| case GLEVEL_3: return "G3"; |
| } |
| |
| return "??"; |
| } |
| |
| |
| /* Convert the type information to string format. */ |
| |
| char * |
| type_to_string (aux_ptr, index, fdp) |
| AUXU *aux_ptr; |
| int index; |
| FDR *fdp; |
| { |
| AUXU u; |
| struct qual { |
| tq_t type; |
| int low_bound; |
| int high_bound; |
| int stride; |
| } qualifiers[7]; |
| |
| bt_t basic_type; |
| int i; |
| static char buffer1[1024]; |
| static char buffer2[1024]; |
| char *p1 = buffer1; |
| char *p2 = buffer2; |
| char *used_ptr = aux_used + (aux_ptr - aux_symbols); |
| |
| for (i = 0; i < 7; i++) |
| { |
| qualifiers[i].low_bound = 0; |
| qualifiers[i].high_bound = 0; |
| qualifiers[i].stride = 0; |
| } |
| |
| used_ptr[index] = 1; |
| u = aux_ptr[index++]; |
| if (u.isym == -1) |
| return "-1 (no type)"; |
| |
| basic_type = (bt_t) u.ti.bt; |
| qualifiers[0].type = (tq_t) u.ti.tq0; |
| qualifiers[1].type = (tq_t) u.ti.tq1; |
| qualifiers[2].type = (tq_t) u.ti.tq2; |
| qualifiers[3].type = (tq_t) u.ti.tq3; |
| qualifiers[4].type = (tq_t) u.ti.tq4; |
| qualifiers[5].type = (tq_t) u.ti.tq5; |
| qualifiers[6].type = tq_Nil; |
| |
| /* |
| * Go get the basic type. |
| */ |
| switch (basic_type) |
| { |
| case bt_Nil: /* undefined */ |
| strcpy (p1, "nil"); |
| break; |
| |
| case bt_Adr: /* address - integer same size as pointer */ |
| strcpy (p1, "address"); |
| break; |
| |
| case bt_Char: /* character */ |
| strcpy (p1, "char"); |
| break; |
| |
| case bt_UChar: /* unsigned character */ |
| strcpy (p1, "unsigned char"); |
| break; |
| |
| case bt_Short: /* short */ |
| strcpy (p1, "short"); |
| break; |
| |
| case bt_UShort: /* unsigned short */ |
| strcpy (p1, "unsigned short"); |
| break; |
| |
| case bt_Int: /* int */ |
| strcpy (p1, "int"); |
| break; |
| |
| case bt_UInt: /* unsigned int */ |
| strcpy (p1, "unsigned int"); |
| break; |
| |
| case bt_Long: /* long */ |
| strcpy (p1, "long"); |
| break; |
| |
| case bt_ULong: /* unsigned long */ |
| strcpy (p1, "unsigned long"); |
| break; |
| |
| case bt_Float: /* float (real) */ |
| strcpy (p1, "float"); |
| break; |
| |
| case bt_Double: /* Double (real) */ |
| strcpy (p1, "double"); |
| break; |
| |
| /* Structures add 1-2 aux words: |
| 1st word is [ST_RFDESCAPE, offset] pointer to struct def; |
| 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ |
| |
| case bt_Struct: /* Structure (Record) */ |
| emit_aggregate (p1, aux_ptr[index], aux_ptr[index+1], "struct", fdp); |
| used_ptr[index] = 1; |
| if (aux_ptr[index].rndx.rfd == ST_RFDESCAPE) |
| used_ptr[++index] = 1; |
| |
| index++; /* skip aux words */ |
| break; |
| |
| /* Unions add 1-2 aux words: |
| 1st word is [ST_RFDESCAPE, offset] pointer to union def; |
| 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ |
| |
| case bt_Union: /* Union */ |
| emit_aggregate (p1, aux_ptr[index], aux_ptr[index+1], "union", fdp); |
| used_ptr[index] = 1; |
| if (aux_ptr[index].rndx.rfd == ST_RFDESCAPE) |
| used_ptr[++index] = 1; |
| |
| index++; /* skip aux words */ |
| break; |
| |
| /* Enumerations add 1-2 aux words: |
| 1st word is [ST_RFDESCAPE, offset] pointer to enum def; |
| 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ |
| |
| case bt_Enum: /* Enumeration */ |
| emit_aggregate (p1, aux_ptr[index], aux_ptr[index+1], "enum", fdp); |
| used_ptr[index] = 1; |
| if (aux_ptr[index].rndx.rfd == ST_RFDESCAPE) |
| used_ptr[++index] = 1; |
| |
| index++; /* skip aux words */ |
| break; |
| |
| case bt_Typedef: /* defined via a typedef, isymRef points */ |
| strcpy (p1, "typedef"); |
| break; |
| |
| case bt_Range: /* subrange of int */ |
| strcpy (p1, "subrange"); |
| break; |
| |
| case bt_Set: /* pascal sets */ |
| strcpy (p1, "set"); |
| break; |
| |
| case bt_Complex: /* fortran complex */ |
| strcpy (p1, "complex"); |
| break; |
| |
| case bt_DComplex: /* fortran double complex */ |
| strcpy (p1, "double complex"); |
| break; |
| |
| case bt_Indirect: /* forward or unnamed typedef */ |
| strcpy (p1, "forward/unnamed typedef"); |
| break; |
| |
| case bt_FixedDec: /* Fixed Decimal */ |
| strcpy (p1, "fixed decimal"); |
| break; |
| |
| case bt_FloatDec: /* Float Decimal */ |
| strcpy (p1, "float decimal"); |
| break; |
| |
| case bt_String: /* Varying Length Character String */ |
| strcpy (p1, "string"); |
| break; |
| |
| case bt_Bit: /* Aligned Bit String */ |
| strcpy (p1, "bit"); |
| break; |
| |
| case bt_Picture: /* Picture */ |
| strcpy (p1, "picture"); |
| break; |
| |
| case bt_Void: /* Void */ |
| strcpy (p1, "void"); |
| break; |
| |
| default: |
| sprintf (p1, "Unknown basic type %d", (int) basic_type); |
| break; |
| } |
| |
| p1 += strlen (buffer1); |
| |
| /* |
| * If this is a bitfield, get the bitsize. |
| */ |
| if (u.ti.fBitfield) |
| { |
| int bitsize; |
| |
| used_ptr[index] = 1; |
| bitsize = aux_ptr[index++].width; |
| sprintf (p1, " : %d", bitsize); |
| p1 += strlen (buffer1); |
| } |
| |
| |
| /* |
| * Deal with any qualifiers. |
| */ |
| if (qualifiers[0].type != tq_Nil) |
| { |
| /* |
| * Snarf up any array bounds in the correct order. Arrays |
| * store 5 successive words in the aux. table: |
| * word 0 RNDXR to type of the bounds (ie, int) |
| * word 1 Current file descriptor index |
| * word 2 low bound |
| * word 3 high bound (or -1 if []) |
| * word 4 stride size in bits |
| */ |
| for (i = 0; i < 7; i++) |
| { |
| if (qualifiers[i].type == tq_Array) |
| { |
| qualifiers[i].low_bound = aux_ptr[index+2].dnLow; |
| qualifiers[i].high_bound = aux_ptr[index+3].dnHigh; |
| qualifiers[i].stride = aux_ptr[index+4].width; |
| used_ptr[index] = 1; |
| used_ptr[index+1] = 1; |
| used_ptr[index+2] = 1; |
| used_ptr[index+3] = 1; |
| used_ptr[index+4] = 1; |
| index += 5; |
| } |
| } |
| |
| /* |
| * Now print out the qualifiers. |
| */ |
| for (i = 0; i < 6; i++) |
| { |
| switch (qualifiers[i].type) |
| { |
| case tq_Nil: |
| case tq_Max: |
| break; |
| |
| case tq_Ptr: |
| strcpy (p2, "ptr to "); |
| p2 += sizeof ("ptr to ")-1; |
| break; |
| |
| case tq_Vol: |
| strcpy (p2, "volatile "); |
| p2 += sizeof ("volatile ")-1; |
| break; |
| |
| case tq_Far: |
| strcpy (p2, "far "); |
| p2 += sizeof ("far ")-1; |
| break; |
| |
| case tq_Proc: |
| strcpy (p2, "func. ret. "); |
| p2 += sizeof ("func. ret. "); |
| break; |
| |
| case tq_Array: |
| { |
| int first_array = i; |
| int j; |
| |
| /* Print array bounds reversed (ie, in the order the C |
| programmer writes them). C is such a fun language.... */ |
| |
| while (i < 5 && qualifiers[i+1].type == tq_Array) |
| i++; |
| |
| for (j = i; j >= first_array; j--) |
| { |
| strcpy (p2, "array ["); |
| p2 += sizeof ("array [")-1; |
| if (qualifiers[j].low_bound != 0) |
| sprintf (p2, |
| "%ld:%ld {%ld bits}", |
| (long) qualifiers[j].low_bound, |
| (long) qualifiers[j].high_bound, |
| (long) qualifiers[j].stride); |
| |
| else if (qualifiers[j].high_bound != -1) |
| sprintf (p2, |
| "%ld {%ld bits}", |
| (long) (qualifiers[j].high_bound + 1), |
| (long) (qualifiers[j].stride)); |
| |
| else |
| sprintf (p2, " {%ld bits}", (long) (qualifiers[j].stride)); |
| |
| p2 += strlen (p2); |
| strcpy (p2, "] of "); |
| p2 += sizeof ("] of ")-1; |
| } |
| } |
| break; |
| } |
| } |
| } |
| |
| strcpy (p2, buffer1); |
| return buffer2; |
| } |
| |
| |
| /* Print out the global file header for object files. */ |
| |
| void |
| print_global_hdr (ptr) |
| struct filehdr *ptr; |
| { |
| char *time = ctime ((time_t *)&ptr->f_timdat); |
| ushort flags = ptr->f_flags; |
| |
| printf("Global file header:\n"); |
| printf(" %-*s 0x%x\n", 24, "magic number", (ushort) ptr->f_magic); |
| printf(" %-*s %d\n", 24, "# sections", (int) ptr->f_nscns); |
| printf(" %-*s %ld, %s", 24, "timestamp", (long) ptr->f_timdat, time); |
| printf(" %-*s %ld\n", 24, "symbolic header offset", (long) ptr->f_symptr); |
| printf(" %-*s %ld\n", 24, "symbolic header size", (long) ptr->f_nsyms); |
| printf(" %-*s %ld\n", 24, "optional header", (long) ptr->f_opthdr); |
| printf(" %-*s 0x%x", 24, "flags", (ushort) flags); |
| |
| if ((flags & F_RELFLG) != 0) |
| printf (", F_RELFLG"); |
| |
| if ((flags & F_EXEC) != 0) |
| printf (", F_EXEC"); |
| |
| if ((flags & F_LNNO) != 0) |
| printf (", F_LNNO"); |
| |
| if ((flags & F_LSYMS) != 0) |
| printf (", F_LSYMS"); |
| |
| if ((flags & F_MINMAL) != 0) |
| printf (", F_MINMAL"); |
| |
| if ((flags & F_UPDATE) != 0) |
| printf (", F_UPDATE"); |
| |
| if ((flags & F_SWABD) != 0) |
| printf (", F_SWABD"); |
| |
| if ((flags & F_AR16WR) != 0) |
| printf (", F_AR16WR"); |
| |
| if ((flags & F_AR32WR) != 0) |
| printf (", F_AR32WR"); |
| |
| if ((flags & F_AR32W) != 0) |
| printf (", F_AR32W"); |
| |
| if ((flags & F_PATCH) != 0) |
| printf (", F_PATCH/F_NODF"); |
| |
| printf ("\n\n"); |
| } |
| |
| |
| /* Print out the symbolic header. */ |
| |
| void |
| print_sym_hdr (sym_ptr) |
| HDRR *sym_ptr; |
| { |
| int width = 20; |
| |
| printf("Symbolic header, magic number = 0x%04x, vstamp = %d.%d:\n\n", |
| sym_ptr->magic & 0xffff, |
| (sym_ptr->vstamp & 0xffff) >> 8, |
| sym_ptr->vstamp & 0xff); |
| |
| printf(" %-*s %11s %11s %11s\n", width, "Info", "Offset", "Number", "Bytes"); |
| printf(" %-*s %11s %11s %11s\n", width, "====", "======", "======", "=====\n"); |
| |
| printf(" %-*s %11ld %11ld %11ld [%d]\n", width, "Line numbers", |
| (long) sym_ptr->cbLineOffset, |
| (long) sym_ptr->cbLine, |
| (long) sym_ptr->cbLine, |
| (int) sym_ptr->ilineMax); |
| |
| printf(" %-*s %11ld %11ld %11ld\n", width, "Dense numbers", |
| (long) sym_ptr->cbDnOffset, |
| (long) sym_ptr->idnMax, |
| (long) (sym_ptr->idnMax * sizeof (DNR))); |
| |
| printf(" %-*s %11ld %11ld %11ld\n", width, "Procedures Tables", |
| (long) sym_ptr->cbPdOffset, |
| (long) sym_ptr->ipdMax, |
| (long) (sym_ptr->ipdMax * sizeof (PDR))); |
| |
| printf(" %-*s %11ld %11ld %11ld\n", width, "Local Symbols", |
| (long) sym_ptr->cbSymOffset, |
| (long) sym_ptr->isymMax, |
| (long) (sym_ptr->isymMax * sizeof (SYMR))); |
| |
| printf(" %-*s %11ld %11ld %11ld\n", width, "Optimization Symbols", |
| (long) sym_ptr->cbOptOffset, |
| (long) sym_ptr->ioptMax, |
| (long) (sym_ptr->ioptMax * sizeof (OPTR))); |
| |
| printf(" %-*s %11ld %11ld %11ld\n", width, "Auxiliary Symbols", |
| (long) sym_ptr->cbAuxOffset, |
| (long) sym_ptr->iauxMax, |
| (long) (sym_ptr->iauxMax * sizeof (AUXU))); |
| |
| printf(" %-*s %11ld %11ld %11ld\n", width, "Local Strings", |
| (long) sym_ptr->cbSsOffset, |
| (long) sym_ptr->issMax, |
| (long) sym_ptr->issMax); |
| |
| printf(" %-*s %11ld %11ld %11ld\n", width, "External Strings", |
| (long) sym_ptr->cbSsExtOffset, |
| (long) sym_ptr->issExtMax, |
| (long) sym_ptr->issExtMax); |
| |
| printf(" %-*s %11ld %11ld %11ld\n", width, "File Tables", |
| (long) sym_ptr->cbFdOffset, |
| (long) sym_ptr->ifdMax, |
| (long) (sym_ptr->ifdMax * sizeof (FDR))); |
| |
| printf(" %-*s %11ld %11ld %11ld\n", width, "Relative Files", |
| (long) sym_ptr->cbRfdOffset, |
| (long) sym_ptr->crfd, |
| (long) (sym_ptr->crfd * sizeof (ulong))); |
| |
| printf(" %-*s %11ld %11ld %11ld\n", width, "External Symbols", |
| (long) sym_ptr->cbExtOffset, |
| (long) sym_ptr->iextMax, |
| (long) (sym_ptr->iextMax * sizeof (EXTR))); |
| } |
| |
| |
| /* Print out a symbol. */ |
| |
| void |
| print_symbol (sym_ptr, number, strbase, aux_base, ifd, fdp) |
| SYMR *sym_ptr; |
| int number; |
| char *strbase; |
| AUXU *aux_base; |
| int ifd; |
| FDR *fdp; |
| { |
| sc_t storage_class = (sc_t) sym_ptr->sc; |
| st_t symbol_type = (st_t) sym_ptr->st; |
| ulong index = sym_ptr->index; |
| char *used_ptr = aux_used + (aux_base - aux_symbols); |
| scope_t *scope_ptr; |
| |
| printf ("\n Symbol# %d: \"%s\"\n", number, sym_ptr->iss + strbase); |
| |
| if (aux_base != (AUXU *) 0 && index != indexNil) |
| switch (symbol_type) |
| { |
| case st_Nil: |
| case st_Label: |
| break; |
| |
| case st_File: |
| case st_Block: |
| printf (" End+1 symbol: %ld\n", index); |
| if (want_scope) |
| { |
| if (free_scope == (scope_t *) 0) |
| scope_ptr = (scope_t *) malloc (sizeof (scope_t)); |
| else |
| { |
| scope_ptr = free_scope; |
| free_scope = scope_ptr->prev; |
| } |
| scope_ptr->open_sym = number; |
| scope_ptr->st = symbol_type; |
| scope_ptr->sc = storage_class; |
| scope_ptr->prev = cur_scope; |
| cur_scope = scope_ptr; |
| } |
| break; |
| |
| case st_End: |
| if (storage_class == sc_Text || storage_class == sc_Info) |
| printf (" First symbol: %ld\n", index); |
| else |
| { |
| used_ptr[index] = 1; |
| printf (" First symbol: %ld\n", aux_base[index].isym); |
| } |
| |
| if (want_scope) |
| { |
| if (cur_scope == (scope_t *) 0) |
| printf (" Can't pop end scope\n"); |
| else |
| { |
| scope_ptr = cur_scope; |
| cur_scope = scope_ptr->prev; |
| scope_ptr->prev = free_scope; |
| free_scope = scope_ptr; |
| } |
| } |
| break; |
| |
| case st_Proc: |
| case st_StaticProc: |
| if (MIPS_IS_STAB(sym_ptr)) |
| ; |
| else if (ifd == -1) /* local symbol */ |
| { |
| used_ptr[index] = used_ptr[index+1] = 1; |
| printf (" End+1 symbol: %-7ld Type: %s\n", |
| aux_base[index].isym, |
| type_to_string (aux_base, index+1, fdp)); |
| } |
| else /* global symbol */ |
| printf (" Local symbol: %ld\n", index); |
| |
| if (want_scope) |
| { |
| if (free_scope == (scope_t *) 0) |
| scope_ptr = (scope_t *) malloc (sizeof (scope_t)); |
| else |
| { |
| scope_ptr = free_scope; |
| free_scope = scope_ptr->prev; |
| } |
| scope_ptr->open_sym = number; |
| scope_ptr->st = symbol_type; |
| scope_ptr->sc = storage_class; |
| scope_ptr->prev = cur_scope; |
| cur_scope = scope_ptr; |
| } |
| break; |
| |
| #ifdef stStruct |
| case st_Struct: |
| case st_Union: |
| case st_Enum: |
| printf (" End+1 symbol: %lu\n", index); |
| break; |
| #endif |
| |
| default: |
| if (!MIPS_IS_STAB (sym_ptr)) |
| { |
| used_ptr[index] = 1; |
| printf (" Type: %s\n", |
| type_to_string (aux_base, index, fdp)); |
| } |
| break; |
| } |
| |
| if (want_scope) |
| { |
| printf (" Scopes: "); |
| if (cur_scope == (scope_t *) 0) |
| printf (" none\n"); |
| else |
| { |
| for (scope_ptr = cur_scope; |
| scope_ptr != (scope_t *) 0; |
| scope_ptr = scope_ptr->prev) |
| { |
| char *class; |
| if (scope_ptr->st == st_Proc || scope_ptr->st == st_StaticProc) |
| class = "func."; |
| else if (scope_ptr->st == st_File) |
| class = "file"; |
| else if (scope_ptr->st == st_Block && scope_ptr->sc == sc_Text) |
| class = "block"; |
| else if (scope_ptr->st == st_Block && scope_ptr->sc == sc_Info) |
| class = "type"; |
| else |
| class = "???"; |
| |
| printf (" %ld [%s]", scope_ptr->open_sym, class); |
| } |
| printf ("\n"); |
| } |
| } |
| |
| printf (" Value: %-13ld ", |
| (long)sym_ptr->value); |
| if (ifd == -1) |
| printf ("String index: %ld\n", (long)sym_ptr->iss); |
| else |
| printf ("String index: %-11ld Ifd: %d\n", |
| (long)sym_ptr->iss, ifd); |
| |
| printf (" Symbol type: %-11sStorage class: %-11s", |
| st_to_string (symbol_type), sc_to_string (storage_class)); |
| |
| if (MIPS_IS_STAB(sym_ptr)) |
| { |
| register int i = sizeof(stab_names) / sizeof(stab_names[0]); |
| char *stab_name = "stab"; |
| short code = MIPS_UNMARK_STAB(sym_ptr->index); |
| while (--i >= 0) |
| if (stab_names[i].code == code) |
| { |
| stab_name = stab_names[i].string; |
| break; |
| } |
| printf ("Index: 0x%lx (%s)\n", (long)sym_ptr->index, stab_name); |
| } |
| else if (sym_ptr->st == stLabel && sym_ptr->index != indexNil) |
| printf ("Index: %ld (line#)\n", (long)sym_ptr->index); |
| else |
| printf ("Index: %ld\n", (long)sym_ptr->index); |
| |
| } |
| |
| |
| /* Print out a word from the aux. table in various formats. */ |
| |
| void |
| print_aux (u, auxi, used) |
| AUXU u; |
| int auxi; |
| int used; |
| { |
| printf ("\t%s#%-5d %11ld, [%4ld/%7ld], [%2d %1d:%1d %1x:%1x:%1x:%1x:%1x:%1x]\n", |
| (used) ? " " : "* ", |
| auxi, |
| (long) u.isym, |
| (long) u.rndx.rfd, |
| (long) u.rndx.index, |
| u.ti.bt, |
| u.ti.fBitfield, |
| u.ti.continued, |
| u.ti.tq0, |
| u.ti.tq1, |
| u.ti.tq2, |
| u.ti.tq3, |
| u.ti.tq4, |
| u.ti.tq5); |
| } |
| |
| |
| /* Write aggregate information to a string. */ |
| |
| void |
| emit_aggregate (string, u, u2, which, fdp) |
| char *string; |
| AUXU u; |
| AUXU u2; |
| const char *which; |
| FDR *fdp; |
| { |
| unsigned int ifd = u.rndx.rfd; |
| unsigned int index = u.rndx.index; |
| const char *name; |
| |
| if (ifd == ST_RFDESCAPE) |
| ifd = u2.isym; |
| |
| /* An ifd of -1 is an opaque type. An escaped index of 0 is a |
| struct return type of a procedure compiled without -g. */ |
| if (ifd == 0xffffffff |
| || (u.rndx.rfd == ST_RFDESCAPE && index == 0)) |
| name = "<undefined>"; |
| else if (index == indexNil) |
| name = "<no name>"; |
| else |
| { |
| if (fdp == 0 || sym_hdr.crfd == 0) |
| fdp = &file_desc[ifd]; |
| else |
| fdp = &file_desc[rfile_desc[fdp->rfdBase + ifd]]; |
| name = &l_strings[fdp->issBase + l_symbols[index + fdp->isymBase].iss]; |
| } |
| |
| sprintf (string, |
| "%s %s { ifd = %u, index = %u }", |
| which, name, ifd, index); |
| } |
| |
| |
| /* Print out information about a file descriptor, and the symbols, |
| procedures, and line numbers within it. */ |
| |
| void |
| print_file_desc (fdp, number) |
| FDR *fdp; |
| int number; |
| { |
| char *str_base; |
| AUXU *aux_base; |
| int symi, pdi; |
| int width = 20; |
| char *used_base; |
| |
| str_base = l_strings + fdp->issBase; |
| aux_base = aux_symbols + fdp->iauxBase; |
| used_base = aux_used + (aux_base - aux_symbols); |
| |
| printf ("\nFile #%d, \"%s\"\n\n", number, str_base + fdp->rss); |
| |
| printf (" Name index = %-10ld Readin = %s\n", |
| (long) fdp->rss, (fdp->fReadin) ? "Yes" : "No"); |
| |
| printf (" Merge = %-10s Endian = %s\n", |
| (fdp->fMerge) ? "Yes" : "No", |
| (fdp->fBigendian) ? "BIG" : "LITTLE"); |
| |
| printf (" Debug level = %-10s Language = %s\n", |
| glevel_to_string (fdp->glevel), |
| lang_to_string((lang_t) fdp->lang)); |
| |
| printf (" Adr = 0x%08lx\n\n", (long) fdp->adr); |
| |
| printf(" %-*s %11s %11s %11s %11s\n", width, "Info", "Start", "Number", "Size", "Offset"); |
| printf(" %-*s %11s %11s %11s %11s\n", width, "====", "=====", "======", "====", "======"); |
| |
| printf(" %-*s %11lu %11lu %11lu %11lu\n", |
| width, "Local strings", |
| (ulong) fdp->issBase, |
| (ulong) fdp->cbSs, |
| (ulong) fdp->cbSs, |
| (ulong) (fdp->issBase + sym_hdr.cbSsOffset)); |
| |
| printf(" %-*s %11lu %11lu %11lu %11lu\n", |
| width, "Local symbols", |
| (ulong) fdp->isymBase, |
| (ulong) fdp->csym, |
| (ulong) (fdp->csym * sizeof (SYMR)), |
| (ulong) (fdp->isymBase * sizeof (SYMR) + sym_hdr.cbSymOffset)); |
| |
| printf(" %-*s %11lu %11lu %11lu %11lu\n", |
| width, "Line numbers", |
| (ulong) fdp->cbLineOffset, |
| (ulong) fdp->cline, |
| (ulong) fdp->cbLine, |
| (ulong) (fdp->cbLineOffset + sym_hdr.cbLineOffset)); |
| |
| printf(" %-*s %11lu %11lu %11lu %11lu\n", |
| width, "Optimization symbols", |
| (ulong) fdp->ioptBase, |
| (ulong) fdp->copt, |
| (ulong) (fdp->copt * sizeof (OPTR)), |
| (ulong) (fdp->ioptBase * sizeof (OPTR) + sym_hdr.cbOptOffset)); |
| |
| printf(" %-*s %11lu %11lu %11lu %11lu\n", |
| width, "Procedures", |
| (ulong) fdp->ipdFirst, |
| (ulong) fdp->cpd, |
| (ulong) (fdp->cpd * sizeof (PDR)), |
| (ulong) (fdp->ipdFirst * sizeof (PDR) + sym_hdr.cbPdOffset)); |
| |
| printf(" %-*s %11lu %11lu %11lu %11lu\n", |
| width, "Auxiliary symbols", |
| (ulong) fdp->iauxBase, |
| (ulong) fdp->caux, |
| (ulong) (fdp->caux * sizeof (AUXU)), |
| (ulong) (fdp->iauxBase * sizeof(AUXU) + sym_hdr.cbAuxOffset)); |
| |
| printf(" %-*s %11lu %11lu %11lu %11lu\n", |
| width, "Relative Files", |
| (ulong) fdp->rfdBase, |
| (ulong) fdp->crfd, |
| (ulong) (fdp->crfd * sizeof (ulong)), |
| (ulong) (fdp->rfdBase * sizeof(ulong) + sym_hdr.cbRfdOffset)); |
| |
| |
| if (want_scope && cur_scope != (scope_t *) 0) |
| printf ("\n Warning scope does not start at 0!\n"); |
| |
| /* |
| * print the info about the symbol table. |
| */ |
| printf ("\n There are %lu local symbols, starting at %lu\n", |
| (ulong) fdp->csym, |
| (ulong) (fdp->isymBase + sym_hdr.cbSymOffset)); |
| |
| for(symi = fdp->isymBase; symi < (fdp->csym + fdp->isymBase); symi++) |
| print_symbol (&l_symbols[symi], |
| symi - fdp->isymBase, |
| str_base, |
| aux_base, |
| -1, |
| fdp); |
| |
| if (want_scope && cur_scope != (scope_t *) 0) |
| printf ("\n Warning scope does not end at 0!\n"); |
| |
| /* |
| * print the aux. table if desired. |
| */ |
| |
| if (want_aux && fdp->caux != 0) |
| { |
| int auxi; |
| |
| printf ("\n There are %lu auxiliary table entries, starting at %lu.\n\n", |
| (ulong) fdp->caux, |
| (ulong) (fdp->iauxBase + sym_hdr.cbAuxOffset)); |
| |
| for (auxi = fdp->iauxBase; auxi < (fdp->caux + fdp->iauxBase); auxi++) |
| print_aux (aux_base[auxi], auxi, used_base[auxi]); |
| } |
| |
| /* |
| * print the relative file descriptors. |
| */ |
| if (want_rfd && fdp->crfd != 0) |
| { |
| ulong *rfd_ptr, i; |
| |
| printf ("\n There are %lu relative file descriptors, starting at %lu.\n", |
| (ulong) fdp->crfd, |
| (ulong) fdp->rfdBase); |
| |
| rfd_ptr = rfile_desc + fdp->rfdBase; |
| for (i = 0; i < fdp->crfd; i++) |
| { |
| printf ("\t#%-5ld %11ld, 0x%08lx\n", i, *rfd_ptr, *rfd_ptr); |
| rfd_ptr++; |
| } |
| } |
| |
| /* |
| * do the procedure descriptors. |
| */ |
| printf ("\n There are %lu procedure descriptor entries, ", (ulong) fdp->cpd); |
| printf ("starting at %lu.\n", (ulong) fdp->ipdFirst); |
| |
| for (pdi = fdp->ipdFirst; pdi < (fdp->cpd + fdp->ipdFirst); pdi++) |
| { |
| PDR *proc_ptr = &proc_desc[pdi]; |
| printf ("\n\tProcedure descriptor %d:\n", (pdi - fdp->ipdFirst)); |
| |
| printf ("\t Name index = %-11ld Name = \"%s\"\n", |
| (long) l_symbols[proc_ptr->isym + fdp->isymBase].iss, |
| l_symbols[proc_ptr->isym + fdp->isymBase].iss + str_base); |
| |
| printf ("\t .mask 0x%08lx,%-9ld .fmask 0x%08lx,%ld\n", |
| (long) proc_ptr->regmask, |
| (long) proc_ptr->regoffset, |
| (long) proc_ptr->fregmask, |
| (long) proc_ptr->fregoffset); |
| |
| printf ("\t .frame $%d,%ld,$%d\n", |
| (int) proc_ptr->framereg, |
| (long) proc_ptr->frameoffset, |
| (int) proc_ptr->pcreg); |
| |
| printf ("\t Opt. start = %-11ld Symbols start = %ld\n", |
| (long) proc_ptr->iopt, |
| (long) proc_ptr->isym); |
| |
| printf ("\t First line # = %-11ld Last line # = %ld\n", |
| (long) proc_ptr->lnLow, |
| (long) proc_ptr->lnHigh); |
| |
| printf ("\t Line Offset = %-11ld Address = 0x%08lx\n", |
| (long) proc_ptr->cbLineOffset, |
| (long) proc_ptr->adr); |
| |
| /* |
| * print the line number entries. |
| */ |
| |
| if (want_line && fdp->cline != 0) |
| { |
| int delta, count; |
| long cur_line = proc_ptr->lnLow; |
| uchar *line_ptr = (((uchar *)lines) + proc_ptr->cbLineOffset |
| + fdp->cbLineOffset); |
| uchar *line_end; |
| |
| if (pdi == fdp->cpd + fdp->ipdFirst - 1) /* last procedure */ |
| line_end = ((uchar *)lines) + fdp->cbLine + fdp->cbLineOffset; |
| else /* not last proc. */ |
| line_end = (((uchar *)lines) + proc_desc[pdi+1].cbLineOffset |
| + fdp->cbLineOffset); |
| |
| printf ("\n\tThere are %lu bytes holding line numbers, starting at %lu.\n", |
| (ulong) (line_end - line_ptr), |
| (ulong) (fdp->ilineBase + sym_hdr.cbLineOffset)); |
| |
| while (line_ptr < line_end) |
| { /* sign extend nibble */ |
| delta = ((*line_ptr >> 4) ^ 0x8) - 0x8; |
| count = (*line_ptr & 0xf) + 1; |
| if (delta != -8) |
| line_ptr++; |
| else |
| { |
| delta = (((line_ptr[1]) & 0xff) << 8) + ((line_ptr[2]) & 0xff); |
| delta = (delta ^ 0x8000) - 0x8000; |
| line_ptr += 3; |
| } |
| |
| cur_line += delta; |
| printf ("\t Line %11ld, delta %5d, count %2d\n", |
| cur_line, |
| delta, |
| count); |
| } |
| } |
| } |
| } |
| |
| |
| /* Read in the portions of the .T file that we will print out. */ |
| |
| void |
| read_tfile __proto((void)) |
| { |
| short magic; |
| off_t sym_hdr_offset = 0; |
| |
| (void) read_seek ((PTR_T) &magic, sizeof (magic), (off_t) 0, "Magic number"); |
| if (!tfile) |
| { |
| /* Print out the global header, since this is not a T-file. */ |
| |
| (void) read_seek ((PTR_T) &global_hdr, sizeof (global_hdr), (off_t) 0, |
| "Global file header"); |
| |
| print_global_hdr (&global_hdr); |
| |
| if (global_hdr.f_symptr == 0) |
| { |
| printf ("No symbolic header, Goodbye!\n"); |
| exit (1); |
| } |
| |
| sym_hdr_offset = global_hdr.f_symptr; |
| } |
| |
| (void) read_seek ((PTR_T) &sym_hdr, |
| sizeof (sym_hdr), |
| sym_hdr_offset, |
| "Symbolic header"); |
| |
| print_sym_hdr (&sym_hdr); |
| |
| lines = (LINER *) read_seek ((PTR_T) 0, |
| sym_hdr.cbLine, |
| sym_hdr.cbLineOffset, |
| "Line numbers"); |
| |
| dense_nums = (DNR *) read_seek ((PTR_T) 0, |
| sym_hdr.idnMax * sizeof (DNR), |
| sym_hdr.cbDnOffset, |
| "Dense numbers"); |
| |
| proc_desc = (PDR *) read_seek ((PTR_T) 0, |
| sym_hdr.ipdMax * sizeof (PDR), |
| sym_hdr.cbPdOffset, |
| "Procedure tables"); |
| |
| l_symbols = (SYMR *) read_seek ((PTR_T) 0, |
| sym_hdr.isymMax * sizeof (SYMR), |
| sym_hdr.cbSymOffset, |
| "Local symbols"); |
| |
| opt_symbols = (OPTR *) read_seek ((PTR_T) 0, |
| sym_hdr.ioptMax * sizeof (OPTR), |
| sym_hdr.cbOptOffset, |
| "Optimization symbols"); |
| |
| aux_symbols = (AUXU *) read_seek ((PTR_T) 0, |
| sym_hdr.iauxMax * sizeof (AUXU), |
| sym_hdr.cbAuxOffset, |
| "Auxiliary symbols"); |
| |
| if (sym_hdr.iauxMax > 0) |
| { |
| aux_used = calloc (sym_hdr.iauxMax, 1); |
| if (aux_used == (char *) 0) |
| { |
| perror ("calloc"); |
| exit (1); |
| } |
| } |
| |
| l_strings = (char *) read_seek ((PTR_T) 0, |
| sym_hdr.issMax, |
| sym_hdr.cbSsOffset, |
| "Local string table"); |
| |
| e_strings = (char *) read_seek ((PTR_T) 0, |
| sym_hdr.issExtMax, |
| sym_hdr.cbSsExtOffset, |
| "External string table"); |
| |
| file_desc = (FDR *) read_seek ((PTR_T) 0, |
| sym_hdr.ifdMax * sizeof (FDR), |
| sym_hdr.cbFdOffset, |
| "File tables"); |
| |
| rfile_desc = (ulong *) read_seek ((PTR_T) 0, |
| sym_hdr.crfd * sizeof (ulong), |
| sym_hdr.cbRfdOffset, |
| "Relative file tables"); |
| |
| e_symbols = (EXTR *) read_seek ((PTR_T) 0, |
| sym_hdr.iextMax * sizeof (EXTR), |
| sym_hdr.cbExtOffset, |
| "External symbols"); |
| } |
| |
| |
| |
| int |
| main (argc, argv) |
| int argc; |
| char **argv; |
| { |
| int i, opt; |
| |
| /* |
| * Process arguments |
| */ |
| while ((opt = getopt (argc, argv, "alrst")) != EOF) |
| switch (opt) |
| { |
| default: errors++; break; |
| case 'a': want_aux++; break; /* print aux table */ |
| case 'l': want_line++; break; /* print line numbers */ |
| case 'r': want_rfd++; break; /* print relative fd's */ |
| case 's': want_scope++; break; /* print scope info */ |
| case 't': tfile++; break; /* this is a tfile (without header), and not a .o */ |
| } |
| |
| if (errors || optind != argc - 1) |
| { |
| fprintf (stderr, "Calling Sequence:\n"); |
| fprintf (stderr, "\t%s [-alrst] <object-or-T-file>\n", argv[0]); |
| fprintf (stderr, "\n"); |
| fprintf (stderr, "switches:\n"); |
| fprintf (stderr, "\t-a Print out auxiliary table.\n"); |
| fprintf (stderr, "\t-l Print out line numbers.\n"); |
| fprintf (stderr, "\t-r Print out relative file descriptors.\n"); |
| fprintf (stderr, "\t-s Print out the current scopes for an item.\n"); |
| fprintf (stderr, "\t-t Assume there is no global header (ie, a T-file).\n"); |
| return 1; |
| } |
| |
| /* |
| * Open and process the input file. |
| */ |
| tfile_fd = open (argv[optind], O_RDONLY); |
| if (tfile_fd < 0) |
| { |
| perror (argv[optind]); |
| return 1; |
| } |
| |
| read_tfile (); |
| |
| /* |
| * Print any global aux words if any. |
| */ |
| if (want_aux) |
| { |
| long last_aux_in_use; |
| |
| if (sym_hdr.ifdMax != 0 && file_desc[0].iauxBase != 0) |
| { |
| printf ("\nGlobal auxiliary entries before first file:\n"); |
| for (i = 0; i < file_desc[0].iauxBase; i++) |
| print_aux (aux_symbols[i], 0, aux_used[i]); |
| } |
| |
| if (sym_hdr.ifdMax == 0) |
| last_aux_in_use = 0; |
| else |
| last_aux_in_use |
| = (file_desc[sym_hdr.ifdMax-1].iauxBase |
| + file_desc[sym_hdr.ifdMax-1].caux - 1); |
| |
| if (last_aux_in_use < sym_hdr.iauxMax-1) |
| { |
| printf ("\nGlobal auxiliary entries after last file:\n"); |
| for (i = last_aux_in_use; i < sym_hdr.iauxMax; i++) |
| print_aux (aux_symbols[i], i - last_aux_in_use, aux_used[i]); |
| } |
| } |
| |
| /* |
| * Print the information for each file. |
| */ |
| for (i = 0; i < sym_hdr.ifdMax; i++) |
| print_file_desc (&file_desc[i], i); |
| |
| /* |
| * Print the external symbols. |
| */ |
| want_scope = 0; /* scope info is meaning for extern symbols */ |
| printf ("\nThere are %lu external symbols, starting at %lu\n", |
| (ulong) sym_hdr.iextMax, |
| (ulong) sym_hdr.cbExtOffset); |
| |
| for(i = 0; i < sym_hdr.iextMax; i++) |
| print_symbol (&e_symbols[i].asym, i, e_strings, |
| aux_symbols + file_desc[e_symbols[i].ifd].iauxBase, |
| e_symbols[i].ifd, |
| &file_desc[e_symbols[i].ifd]); |
| |
| /* |
| * Print unused aux symbols now. |
| */ |
| |
| if (want_aux) |
| { |
| int first_time = 1; |
| |
| for (i = 0; i < sym_hdr.iauxMax; i++) |
| { |
| if (! aux_used[i]) |
| { |
| if (first_time) |
| { |
| printf ("\nThe following auxiliary table entries were unused:\n\n"); |
| first_time = 0; |
| } |
| |
| printf (" #%-5d %11ld 0x%08lx %s\n", |
| i, |
| (long) aux_symbols[i].isym, |
| (long) aux_symbols[i].isym, |
| type_to_string (aux_symbols, i, (FDR *) 0)); |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| void |
| fancy_abort () |
| { |
| fprintf (stderr, "mips-tdump internal error"); |
| exit (1); |
| } |
| |
| void |
| fatal(s) |
| char *s; |
| { |
| fprintf(stderr, "%s\n", s); |
| exit(1); |
| } |
| |
| /* Same as `malloc' but report error if no memory available. */ |
| |
| PTR_T |
| xmalloc (size) |
| unsigned size; |
| { |
| register PTR_T value = malloc (size); |
| if (value == 0) |
| fatal ("Virtual memory exhausted."); |
| return value; |
| } |