]>
Commit | Line | Data |
---|---|---|
68e9eb95 RS |
1 | /* Read and manage MIPS symbol tables from object modules. |
2 | Source originally from hartzell@boulder.colorado.edu | |
3 | Rewritten by: meissner@osf.org | |
4 | Copyright (C) 1991 Free Software Foundation, Inc. | |
5 | ||
6 | This file is part of GNU CC. | |
7 | ||
8 | GNU CC is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 2, or (at your option) | |
11 | any later version. | |
12 | ||
13 | GNU CC is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with GNU CC; see the file COPYING. If not, write to | |
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
21 | ||
22 | #include <stdio.h> | |
23 | #include <sys/types.h> | |
24 | #include <sys/file.h> | |
b2869d95 | 25 | #include <fcntl.h> |
68e9eb95 | 26 | #include <errno.h> |
68e9eb95 RS |
27 | #include "config.h" |
28 | ||
de5849f3 MM |
29 | #ifdef index |
30 | #undef index | |
31 | #undef rindex | |
32 | #endif | |
d07e072c MM |
33 | #ifndef CROSS_COMPILE |
34 | #include <a.out.h> | |
35 | #else | |
36 | #include "symconst.h" | |
37 | #define LANGUAGE_C | |
38 | #include "sym.h" | |
39 | #include "filehdr.h" | |
40 | #define ST_RFDESCAPE 0xfff | |
41 | #endif | |
42 | ||
68e9eb95 RS |
43 | #ifdef __STDC__ |
44 | typedef void *PTR_T; | |
45 | typedef const void *CPTR_T; | |
46 | #define __proto(x) x | |
47 | #else | |
48 | ||
9a78963a | 49 | #if defined(_STDIO_H_) || defined(__STDIO_H__) /* Ultrix 4.0, SGI */ |
68e9eb95 RS |
50 | typedef void *PTR_T; |
51 | typedef void *CPTR_T; | |
52 | ||
53 | #else | |
9a78963a | 54 | typedef char *PTR_T; /* Ultrix 3.1 */ |
68e9eb95 RS |
55 | typedef char *CPTR_T; |
56 | #endif | |
57 | ||
58 | #define __proto(x) () | |
59 | #define const | |
60 | #endif | |
61 | ||
62 | #define uchar unsigned char | |
63 | #define ushort unsigned short | |
64 | #define uint unsigned int | |
65 | #define ulong unsigned long | |
66 | ||
43365a35 | 67 | |
68e9eb95 RS |
68 | /* Do to size_t being defined in sys/types.h and different |
69 | in stddef.h, we have to do this by hand..... Note, these | |
70 | types are correct for MIPS based systems, and may not be | |
71 | correct for other systems. */ | |
72 | ||
73 | #define size_t uint | |
74 | #define ptrdiff_t int | |
75 | ||
76 | \f | |
64fd9134 | 77 | /* Redefinition of of storage classes as an enumeration for better |
68e9eb95 RS |
78 | debugging. */ |
79 | ||
80 | #ifndef stStaParam | |
81 | #define stStaParam 16 /* Fortran static parameters */ | |
82 | #endif | |
83 | ||
84 | #ifndef btVoid | |
85 | #define btVoid 26 /* void basic type */ | |
86 | #endif | |
87 | ||
88 | typedef enum sc { | |
89 | sc_Nil = scNil, /* no storage class */ | |
90 | sc_Text = scText, /* text symbol */ | |
91 | sc_Data = scData, /* initialized data symbol */ | |
92 | sc_Bss = scBss, /* un-initialized data symbol */ | |
93 | sc_Register = scRegister, /* value of symbol is register number */ | |
94 | sc_Abs = scAbs, /* value of symbol is absolute */ | |
95 | sc_Undefined = scUndefined, /* who knows? */ | |
96 | sc_CdbLocal = scCdbLocal, /* variable's value is IN se->va.?? */ | |
97 | sc_Bits = scBits, /* this is a bit field */ | |
98 | sc_CdbSystem = scCdbSystem, /* var's value is IN CDB's address space */ | |
99 | sc_RegImage = scRegImage, /* register value saved on stack */ | |
100 | sc_Info = scInfo, /* symbol contains debugger information */ | |
101 | sc_UserStruct = scUserStruct, /* addr in struct user for current process */ | |
102 | sc_SData = scSData, /* load time only small data */ | |
103 | sc_SBss = scSBss, /* load time only small common */ | |
104 | sc_RData = scRData, /* load time only read only data */ | |
105 | sc_Var = scVar, /* Var parameter (fortran,pascal) */ | |
106 | sc_Common = scCommon, /* common variable */ | |
107 | sc_SCommon = scSCommon, /* small common */ | |
108 | sc_VarRegister = scVarRegister, /* Var parameter in a register */ | |
109 | sc_Variant = scVariant, /* Variant record */ | |
110 | sc_SUndefined = scSUndefined, /* small undefined(external) data */ | |
111 | sc_Init = scInit, /* .init section symbol */ | |
112 | sc_Max = scMax /* Max storage class+1 */ | |
113 | } sc_t; | |
114 | ||
115 | /* Redefinition of symbol type. */ | |
116 | ||
117 | typedef enum st { | |
118 | st_Nil = stNil, /* Nuthin' special */ | |
119 | st_Global = stGlobal, /* external symbol */ | |
120 | st_Static = stStatic, /* static */ | |
121 | st_Param = stParam, /* procedure argument */ | |
122 | st_Local = stLocal, /* local variable */ | |
123 | st_Label = stLabel, /* label */ | |
124 | st_Proc = stProc, /* " " Procedure */ | |
64fd9134 | 125 | st_Block = stBlock, /* beginning of block */ |
68e9eb95 RS |
126 | st_End = stEnd, /* end (of anything) */ |
127 | st_Member = stMember, /* member (of anything - struct/union/enum */ | |
128 | st_Typedef = stTypedef, /* type definition */ | |
129 | st_File = stFile, /* file name */ | |
130 | st_RegReloc = stRegReloc, /* register relocation */ | |
131 | st_Forward = stForward, /* forwarding address */ | |
132 | st_StaticProc = stStaticProc, /* load time only static procs */ | |
133 | st_StaParam = stStaParam, /* Fortran static parameters */ | |
134 | st_Constant = stConstant, /* const */ | |
135 | st_Str = stStr, /* string */ | |
136 | st_Number = stNumber, /* pure number (ie. 4 NOR 2+2) */ | |
137 | st_Expr = stExpr, /* 2+2 vs. 4 */ | |
64fd9134 | 138 | st_Type = stType, /* post-coercion SER */ |
68e9eb95 RS |
139 | st_Max = stMax /* max type+1 */ |
140 | } st_t; | |
141 | ||
142 | /* Redefinition of type qualifiers. */ | |
143 | ||
144 | typedef enum tq { | |
145 | tq_Nil = tqNil, /* bt is what you see */ | |
146 | tq_Ptr = tqPtr, /* pointer */ | |
147 | tq_Proc = tqProc, /* procedure */ | |
148 | tq_Array = tqArray, /* duh */ | |
149 | tq_Far = tqFar, /* longer addressing - 8086/8 land */ | |
150 | tq_Vol = tqVol, /* volatile */ | |
151 | tq_Max = tqMax /* Max type qualifier+1 */ | |
152 | } tq_t; | |
153 | ||
154 | /* Redefinition of basic types. */ | |
155 | ||
156 | typedef enum bt { | |
157 | bt_Nil = btNil, /* undefined */ | |
158 | bt_Adr = btAdr, /* address - integer same size as pointer */ | |
159 | bt_Char = btChar, /* character */ | |
160 | bt_UChar = btUChar, /* unsigned character */ | |
161 | bt_Short = btShort, /* short */ | |
162 | bt_UShort = btUShort, /* unsigned short */ | |
163 | bt_Int = btInt, /* int */ | |
164 | bt_UInt = btUInt, /* unsigned int */ | |
165 | bt_Long = btLong, /* long */ | |
166 | bt_ULong = btULong, /* unsigned long */ | |
167 | bt_Float = btFloat, /* float (real) */ | |
168 | bt_Double = btDouble, /* Double (real) */ | |
169 | bt_Struct = btStruct, /* Structure (Record) */ | |
170 | bt_Union = btUnion, /* Union (variant) */ | |
171 | bt_Enum = btEnum, /* Enumerated */ | |
172 | bt_Typedef = btTypedef, /* defined via a typedef, isymRef points */ | |
173 | bt_Range = btRange, /* subrange of int */ | |
174 | bt_Set = btSet, /* pascal sets */ | |
175 | bt_Complex = btComplex, /* fortran complex */ | |
176 | bt_DComplex = btDComplex, /* fortran double complex */ | |
177 | bt_Indirect = btIndirect, /* forward or unnamed typedef */ | |
178 | bt_FixedDec = btFixedDec, /* Fixed Decimal */ | |
179 | bt_FloatDec = btFloatDec, /* Float Decimal */ | |
180 | bt_String = btString, /* Varying Length Character String */ | |
181 | bt_Bit = btBit, /* Aligned Bit String */ | |
182 | bt_Picture = btPicture, /* Picture */ | |
183 | bt_Void = btVoid, /* void */ | |
184 | bt_Max = btMax /* Max basic type+1 */ | |
185 | } bt_t; | |
186 | ||
187 | /* Redefinition of the language codes. */ | |
188 | ||
189 | typedef enum lang { | |
190 | lang_C = langC, | |
191 | lang_Pascal = langPascal, | |
192 | lang_Fortran = langFortran, | |
193 | lang_Assembler = langAssembler, | |
194 | lang_Machine = langMachine, | |
195 | lang_Nil = langNil, | |
196 | lang_Ada = langAda, | |
197 | lang_Pl1 = langPl1, | |
198 | lang_Cobol = langCobol | |
199 | } lang_t; | |
200 | ||
201 | /* Redefinition of the debug level codes. */ | |
202 | ||
203 | typedef enum glevel { | |
204 | glevel_0 = GLEVEL_0, | |
205 | glevel_1 = GLEVEL_1, | |
206 | glevel_2 = GLEVEL_2, | |
207 | glevel_3 = GLEVEL_3 | |
208 | } glevel_t; | |
209 | ||
210 | \f | |
211 | /* Keep track of the active scopes. */ | |
212 | typedef struct scope { | |
213 | struct scope *prev; /* previous scope */ | |
214 | ulong open_sym; /* symbol opening scope */ | |
215 | sc_t sc; /* storage class */ | |
216 | st_t st; /* symbol type */ | |
217 | } scope_t; | |
218 | ||
219 | struct filehdr global_hdr; /* a.out header */ | |
220 | ||
221 | int errors = 0; /* # of errors */ | |
222 | int want_aux = 0; /* print aux table */ | |
223 | int want_line = 0; /* print line numbers */ | |
224 | int want_rfd = 0; /* print relative file desc's */ | |
225 | int want_scope = 0; /* print scopes for every symbol */ | |
226 | int tfile_fd; /* file descriptor of .T file */ | |
227 | off_t tfile_offset; /* current offset in .T file */ | |
228 | scope_t *cur_scope = 0; /* list of active scopes */ | |
229 | scope_t *free_scope = 0; /* list of freed scopes */ | |
230 | HDRR sym_hdr; /* symbolic header */ | |
231 | char *l_strings; /* local strings */ | |
232 | char *e_strings; /* external strings */ | |
233 | SYMR *l_symbols; /* local symbols */ | |
234 | EXTR *e_symbols; /* external symbols */ | |
235 | LINER *lines; /* line numbers */ | |
236 | DNR *dense_nums; /* dense numbers */ | |
237 | OPTR *opt_symbols; /* optimization symbols */ | |
64fd9134 | 238 | AUXU *aux_symbols; /* Auxiliary symbols */ |
68e9eb95 RS |
239 | char *aux_used; /* map of which aux syms are used */ |
240 | FDR *file_desc; /* file tables */ | |
241 | ulong *rfile_desc; /* relative file tables */ | |
242 | PDR *proc_desc; /* procedure tables */ | |
243 | ||
244 | /* Forward reference for functions. */ | |
245 | PTR_T read_seek __proto((PTR_T, size_t, off_t, const char *)); | |
246 | void read_tfile __proto((void)); | |
247 | void print_global_hdr __proto((struct filehdr *)); | |
248 | void print_sym_hdr __proto((HDRR *)); | |
249 | void print_file_desc __proto((FDR *, int)); | |
250 | void print_symbol __proto((SYMR *, int, char *, AUXU *, int)); | |
251 | void print_aux __proto((AUXU, int, int)); | |
252 | void emit_aggregate __proto((char *, AUXU, AUXU, const char *)); | |
253 | char *st_to_string __proto((st_t)); | |
254 | char *sc_to_string __proto((sc_t)); | |
255 | char *glevel_to_string __proto((glevel_t)); | |
256 | char *lang_to_string __proto((lang_t)); | |
257 | char *type_to_string __proto((AUXU *, int)); | |
258 | ||
68e9eb95 RS |
259 | extern PTR_T malloc __proto((size_t)); |
260 | extern PTR_T calloc __proto((size_t, size_t)); | |
261 | extern PTR_T realloc __proto((PTR_T, size_t)); | |
262 | extern void free __proto((PTR_T)); | |
68e9eb95 | 263 | extern char *ctime __proto((time_t *)); |
68e9eb95 RS |
264 | |
265 | extern char *optarg; | |
266 | extern int optind; | |
267 | extern int opterr; | |
268 | ||
269 | /* Create a table of debugging stab-codes and corresponding names. */ | |
270 | ||
271 | #define __define_stab(NAME, CODE, STRING) {(int)CODE, STRING}, | |
272 | struct {short code; char string[10];} stab_names[] = { | |
273 | #include "stab.def" | |
274 | #undef __define_stab | |
275 | }; | |
276 | ||
277 | \f | |
278 | /* Read some bytes at a specified location, and return a pointer. */ | |
279 | ||
280 | PTR_T | |
281 | read_seek (ptr, size, offset, context) | |
282 | PTR_T ptr; /* pointer to buffer or NULL */ | |
283 | size_t size; /* # bytes to read */ | |
284 | off_t offset; /* offset to read at */ | |
285 | const char *context; /* context for error message */ | |
286 | { | |
287 | long read_size = 0; | |
288 | ||
289 | if (size == 0) /* nothing to read */ | |
290 | return ptr; | |
291 | ||
292 | if ((ptr == (PTR_T)0 && (ptr = malloc (size)) == (PTR_T)0) | |
293 | || (tfile_offset != offset && lseek (tfile_fd, offset, 0) == -1) | |
294 | || (read_size = read (tfile_fd, ptr, size)) < 0) | |
295 | { | |
296 | perror (context); | |
297 | exit (1); | |
298 | } | |
299 | ||
300 | if (read_size != size) | |
301 | { | |
302 | fprintf (stderr, "%s: read %ld bytes, expected %ld bytes\n", | |
303 | context, read_size, (long) size); | |
304 | exit (1); | |
305 | } | |
306 | ||
307 | tfile_offset = offset + size; | |
308 | return ptr; | |
309 | } | |
310 | ||
311 | \f | |
312 | /* Convert language code to string format. */ | |
313 | ||
314 | char * | |
315 | lang_to_string (lang) | |
316 | lang_t lang; | |
317 | { | |
318 | switch (lang) | |
319 | { | |
320 | case langC: return "C"; | |
321 | case langPascal: return "Pascal"; | |
322 | case langFortran: return "Fortran"; | |
323 | case langAssembler: return "Assembler"; | |
324 | case langMachine: return "Machine"; | |
325 | case langNil: return "Nil"; | |
326 | case langAda: return "Ada"; | |
327 | case langPl1: return "Pl1"; | |
328 | case langCobol: return "Cobol"; | |
329 | } | |
330 | ||
331 | return "Unknown language"; | |
332 | } | |
333 | ||
334 | \f | |
335 | /* Convert storage class to string. */ | |
336 | ||
337 | char * | |
338 | sc_to_string(storage_class) | |
339 | sc_t storage_class; | |
340 | { | |
341 | switch(storage_class) | |
342 | { | |
343 | case sc_Nil: return "Nil"; | |
344 | case sc_Text: return "Text"; | |
345 | case sc_Data: return "Data"; | |
346 | case sc_Bss: return "Bss"; | |
347 | case sc_Register: return "Register"; | |
348 | case sc_Abs: return "Abs"; | |
349 | case sc_Undefined: return "Undefined"; | |
350 | case sc_CdbLocal: return "CdbLocal"; | |
351 | case sc_Bits: return "Bits"; | |
352 | case sc_CdbSystem: return "CdbSystem"; | |
353 | case sc_RegImage: return "RegImage"; | |
354 | case sc_Info: return "Info"; | |
355 | case sc_UserStruct: return "UserStruct"; | |
356 | case sc_SData: return "SData"; | |
357 | case sc_SBss: return "SBss"; | |
358 | case sc_RData: return "RData"; | |
359 | case sc_Var: return "Var"; | |
360 | case sc_Common: return "Common"; | |
361 | case sc_SCommon: return "SCommon"; | |
362 | case sc_VarRegister: return "VarRegister"; | |
363 | case sc_Variant: return "Variant"; | |
364 | case sc_SUndefined: return "SUndefined"; | |
365 | case sc_Init: return "Init"; | |
366 | case sc_Max: return "Max"; | |
367 | } | |
368 | ||
369 | return "???"; | |
370 | } | |
371 | ||
372 | \f | |
373 | /* Convert symbol type to string. */ | |
374 | ||
375 | char * | |
376 | st_to_string(symbol_type) | |
377 | st_t symbol_type; | |
378 | { | |
379 | switch(symbol_type) | |
380 | { | |
381 | case st_Nil: return "Nil"; | |
382 | case st_Global: return "Global"; | |
383 | case st_Static: return "Static"; | |
384 | case st_Param: return "Param"; | |
385 | case st_Local: return "Local"; | |
386 | case st_Label: return "Label"; | |
387 | case st_Proc: return "Proc"; | |
388 | case st_Block: return "Block"; | |
389 | case st_End: return "End"; | |
390 | case st_Member: return "Member"; | |
391 | case st_Typedef: return "Typedef"; | |
392 | case st_File: return "File"; | |
393 | case st_RegReloc: return "RegReloc"; | |
394 | case st_Forward: return "Forward"; | |
395 | case st_StaticProc: return "StaticProc"; | |
396 | case st_Constant: return "Constant"; | |
397 | case st_StaParam: return "StaticParam"; | |
398 | case st_Str: return "String"; | |
399 | case st_Number: return "Number"; | |
400 | case st_Expr: return "Expr"; | |
401 | case st_Type: return "Type"; | |
402 | case st_Max: return "Max"; | |
403 | } | |
404 | ||
405 | return "???"; | |
406 | } | |
407 | ||
408 | \f | |
409 | /* Convert debug level to string. */ | |
410 | ||
411 | char * | |
412 | glevel_to_string (g_level) | |
413 | glevel_t g_level; | |
414 | { | |
415 | switch(g_level) | |
416 | { | |
417 | case GLEVEL_0: return "G0"; | |
418 | case GLEVEL_1: return "G1"; | |
419 | case GLEVEL_2: return "G2"; | |
420 | case GLEVEL_3: return "G3"; | |
421 | } | |
422 | ||
423 | return "??"; | |
424 | } | |
425 | ||
426 | \f | |
427 | /* Convert the type information to string format. */ | |
428 | ||
429 | char * | |
430 | type_to_string (aux_ptr, index) | |
431 | AUXU *aux_ptr; | |
432 | int index; | |
433 | { | |
434 | AUXU u; | |
435 | struct qual { | |
436 | tq_t type; | |
437 | int low_bound; | |
438 | int high_bound; | |
439 | int stride; | |
440 | } qualifiers[7]; | |
441 | ||
442 | bt_t basic_type; | |
443 | int i; | |
444 | static char buffer1[1024]; | |
445 | static char buffer2[1024]; | |
446 | char *p1 = buffer1; | |
447 | char *p2 = buffer2; | |
448 | char *used_ptr = aux_used + (aux_ptr - aux_symbols); | |
449 | ||
450 | for (i = 0; i < 7; i++) | |
451 | { | |
452 | qualifiers[i].low_bound = 0; | |
453 | qualifiers[i].high_bound = 0; | |
454 | qualifiers[i].stride = 0; | |
455 | } | |
456 | ||
457 | used_ptr[index] = 1; | |
458 | u = aux_ptr[index++]; | |
459 | if (u.isym == -1) | |
460 | return "-1 (no type)"; | |
461 | ||
462 | basic_type = (bt_t) u.ti.bt; | |
463 | qualifiers[0].type = (tq_t) u.ti.tq0; | |
464 | qualifiers[1].type = (tq_t) u.ti.tq1; | |
465 | qualifiers[2].type = (tq_t) u.ti.tq2; | |
466 | qualifiers[3].type = (tq_t) u.ti.tq3; | |
467 | qualifiers[4].type = (tq_t) u.ti.tq4; | |
468 | qualifiers[5].type = (tq_t) u.ti.tq5; | |
469 | qualifiers[6].type = tq_Nil; | |
470 | ||
471 | /* | |
472 | * Go get the basic type. | |
473 | */ | |
474 | switch (basic_type) | |
475 | { | |
476 | case bt_Nil: /* undefined */ | |
477 | strcpy (p1, "nil"); | |
478 | break; | |
479 | ||
480 | case bt_Adr: /* address - integer same size as pointer */ | |
481 | strcpy (p1, "address"); | |
482 | break; | |
483 | ||
484 | case bt_Char: /* character */ | |
485 | strcpy (p1, "char"); | |
486 | break; | |
487 | ||
488 | case bt_UChar: /* unsigned character */ | |
489 | strcpy (p1, "unsigned char"); | |
490 | break; | |
491 | ||
492 | case bt_Short: /* short */ | |
493 | strcpy (p1, "short"); | |
494 | break; | |
495 | ||
496 | case bt_UShort: /* unsigned short */ | |
497 | strcpy (p1, "unsigned short"); | |
498 | break; | |
499 | ||
500 | case bt_Int: /* int */ | |
501 | strcpy (p1, "int"); | |
502 | break; | |
503 | ||
504 | case bt_UInt: /* unsigned int */ | |
505 | strcpy (p1, "unsigned int"); | |
506 | break; | |
507 | ||
508 | case bt_Long: /* long */ | |
509 | strcpy (p1, "long"); | |
510 | break; | |
511 | ||
512 | case bt_ULong: /* unsigned long */ | |
513 | strcpy (p1, "unsigned long"); | |
514 | break; | |
515 | ||
516 | case bt_Float: /* float (real) */ | |
517 | strcpy (p1, "float"); | |
518 | break; | |
519 | ||
520 | case bt_Double: /* Double (real) */ | |
521 | strcpy (p1, "double"); | |
522 | break; | |
523 | ||
524 | /* Structures add 1-2 aux words: | |
525 | 1st word is [ST_RFDESCAPE, offset] pointer to struct def; | |
526 | 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ | |
527 | ||
528 | case bt_Struct: /* Structure (Record) */ | |
529 | emit_aggregate (p1, aux_ptr[index], aux_ptr[index+1], "struct"); | |
530 | used_ptr[index] = 1; | |
531 | if (aux_ptr[index].rndx.rfd == ST_RFDESCAPE) | |
532 | used_ptr[++index] = 1; | |
533 | ||
534 | index++; /* skip aux words */ | |
535 | break; | |
536 | ||
537 | /* Unions add 1-2 aux words: | |
538 | 1st word is [ST_RFDESCAPE, offset] pointer to union def; | |
539 | 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ | |
540 | ||
541 | case bt_Union: /* Union */ | |
542 | emit_aggregate (p1, aux_ptr[index], aux_ptr[index+1], "union"); | |
543 | used_ptr[index] = 1; | |
544 | if (aux_ptr[index].rndx.rfd == ST_RFDESCAPE) | |
545 | used_ptr[++index] = 1; | |
546 | ||
547 | index++; /* skip aux words */ | |
548 | break; | |
549 | ||
550 | /* Enumerations add 1-2 aux words: | |
551 | 1st word is [ST_RFDESCAPE, offset] pointer to enum def; | |
552 | 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ | |
553 | ||
554 | case bt_Enum: /* Enumeration */ | |
555 | emit_aggregate (p1, aux_ptr[index], aux_ptr[index+1], "enum"); | |
556 | used_ptr[index] = 1; | |
557 | if (aux_ptr[index].rndx.rfd == ST_RFDESCAPE) | |
558 | used_ptr[++index] = 1; | |
559 | ||
560 | index++; /* skip aux words */ | |
561 | break; | |
562 | ||
563 | case bt_Typedef: /* defined via a typedef, isymRef points */ | |
564 | strcpy (p1, "typedef"); | |
565 | break; | |
566 | ||
567 | case bt_Range: /* subrange of int */ | |
568 | strcpy (p1, "subrange"); | |
569 | break; | |
570 | ||
571 | case bt_Set: /* pascal sets */ | |
572 | strcpy (p1, "set"); | |
573 | break; | |
574 | ||
575 | case bt_Complex: /* fortran complex */ | |
576 | strcpy (p1, "complex"); | |
577 | break; | |
578 | ||
579 | case bt_DComplex: /* fortran double complex */ | |
580 | strcpy (p1, "double complex"); | |
581 | break; | |
582 | ||
583 | case bt_Indirect: /* forward or unnamed typedef */ | |
584 | strcpy (p1, "forward/unamed typedef"); | |
585 | break; | |
586 | ||
587 | case bt_FixedDec: /* Fixed Decimal */ | |
588 | strcpy (p1, "fixed decimal"); | |
589 | break; | |
590 | ||
591 | case bt_FloatDec: /* Float Decimal */ | |
592 | strcpy (p1, "float decimal"); | |
593 | break; | |
594 | ||
595 | case bt_String: /* Varying Length Character String */ | |
596 | strcpy (p1, "string"); | |
597 | break; | |
598 | ||
599 | case bt_Bit: /* Aligned Bit String */ | |
600 | strcpy (p1, "bit"); | |
601 | break; | |
602 | ||
603 | case bt_Picture: /* Picture */ | |
604 | strcpy (p1, "picture"); | |
605 | break; | |
606 | ||
607 | case bt_Void: /* Void */ | |
608 | strcpy (p1, "void"); | |
609 | break; | |
610 | ||
611 | default: | |
612 | sprintf (p1, "Unknown basic type %d", (int) basic_type); | |
613 | break; | |
614 | } | |
615 | ||
616 | p1 += strlen (buffer1); | |
617 | ||
618 | /* | |
619 | * If this is a bitfield, get the bitsize. | |
620 | */ | |
621 | if (u.ti.fBitfield) | |
622 | { | |
623 | int bitsize; | |
624 | ||
625 | used_ptr[index] = 1; | |
626 | bitsize = aux_ptr[index++].width; | |
627 | sprintf (p1, " : %d", bitsize); | |
628 | p1 += strlen (buffer1); | |
629 | } | |
630 | ||
631 | ||
632 | /* | |
633 | * Deal with any qualifiers. | |
634 | */ | |
635 | if (qualifiers[0].type != tq_Nil) | |
636 | { | |
637 | /* | |
638 | * Snarf up any array bounds in the correct order. Arrays | |
64fd9134 | 639 | * store 5 successive words in the aux. table: |
68e9eb95 RS |
640 | * word 0 RNDXR to type of the bounds (ie, int) |
641 | * word 1 Current file descriptor index | |
642 | * word 2 low bound | |
643 | * word 3 high bound (or -1 if []) | |
644 | * word 4 stride size in bits | |
645 | */ | |
646 | for (i = 0; i < 7; i++) | |
647 | { | |
648 | if (qualifiers[i].type == tq_Array) | |
649 | { | |
650 | qualifiers[i].low_bound = aux_ptr[index+2].dnLow; | |
651 | qualifiers[i].high_bound = aux_ptr[index+3].dnHigh; | |
652 | qualifiers[i].stride = aux_ptr[index+4].width; | |
653 | used_ptr[index] = 1; | |
654 | used_ptr[index+1] = 1; | |
655 | used_ptr[index+2] = 1; | |
656 | used_ptr[index+3] = 1; | |
657 | used_ptr[index+4] = 1; | |
658 | index += 5; | |
659 | } | |
660 | } | |
661 | ||
662 | /* | |
663 | * Now print out the qualifiers. | |
664 | */ | |
665 | for (i = 0; i < 6; i++) | |
666 | { | |
667 | switch (qualifiers[i].type) | |
668 | { | |
669 | case tq_Nil: | |
670 | case tq_Max: | |
671 | break; | |
672 | ||
673 | case tq_Ptr: | |
674 | strcpy (p2, "ptr to "); | |
675 | p2 += sizeof ("ptr to ")-1; | |
676 | break; | |
677 | ||
678 | case tq_Vol: | |
679 | strcpy (p2, "volatile "); | |
680 | p2 += sizeof ("volatile ")-1; | |
681 | break; | |
682 | ||
683 | case tq_Far: | |
684 | strcpy (p2, "far "); | |
685 | p2 += sizeof ("far ")-1; | |
686 | break; | |
687 | ||
688 | case tq_Proc: | |
689 | strcpy (p2, "func. ret. "); | |
690 | p2 += sizeof ("func. ret. "); | |
691 | break; | |
692 | ||
693 | case tq_Array: | |
694 | { | |
695 | int first_array = i; | |
696 | int j; | |
697 | ||
698 | /* Print array bounds reversed (ie, in the order the C | |
699 | programmer writes them). C is such a fun language.... */ | |
700 | ||
701 | while (i < 5 && qualifiers[i+1].type == tq_Array) | |
702 | i++; | |
703 | ||
704 | for (j = i; j >= first_array; j--) | |
705 | { | |
706 | strcpy (p2, "array ["); | |
707 | p2 += sizeof ("array [")-1; | |
708 | if (qualifiers[j].low_bound != 0) | |
709 | sprintf (p2, | |
710 | "%ld:%ld {%ld bits}", | |
711 | (long) qualifiers[j].low_bound, | |
712 | (long) qualifiers[j].high_bound, | |
713 | (long) qualifiers[j].stride); | |
714 | ||
715 | else if (qualifiers[j].high_bound != -1) | |
716 | sprintf (p2, | |
717 | "%ld {%ld bits}", | |
718 | (long) (qualifiers[j].high_bound + 1), | |
719 | (long) (qualifiers[j].stride)); | |
720 | ||
721 | else | |
722 | sprintf (p2, " {%ld bits}", (long) (qualifiers[j].stride)); | |
723 | ||
724 | p2 += strlen (p2); | |
725 | strcpy (p2, "] of "); | |
726 | p2 += sizeof ("] of ")-1; | |
727 | } | |
728 | } | |
729 | break; | |
730 | } | |
731 | } | |
732 | } | |
733 | ||
734 | strcpy (p2, buffer1); | |
735 | return buffer2; | |
736 | } | |
737 | ||
738 | \f | |
739 | /* Print out the global file header for object files. */ | |
740 | ||
741 | void | |
742 | print_global_hdr (ptr) | |
743 | struct filehdr *ptr; | |
744 | { | |
745 | char *time = ctime ((off_t *)&ptr->f_timdat); | |
746 | ushort flags = ptr->f_flags; | |
747 | ||
748 | printf("Global file header:\n"); | |
749 | printf(" %-*s 0x%x\n", 24, "magic number", (ushort) ptr->f_magic); | |
750 | printf(" %-*s %d\n", 24, "# sections", (int) ptr->f_nscns); | |
751 | printf(" %-*s %ld, %s", 24, "timestamp", (long) ptr->f_timdat, time); | |
752 | printf(" %-*s %ld\n", 24, "symbolic header offset", (long) ptr->f_symptr); | |
753 | printf(" %-*s %ld\n", 24, "symbolic header size", (long) ptr->f_nsyms); | |
754 | printf(" %-*s %ld\n", 24, "optional header", (long) ptr->f_opthdr); | |
755 | printf(" %-*s 0x%lx", 24, "flags", (ushort) flags); | |
756 | ||
757 | if ((flags & F_RELFLG) != 0) | |
758 | printf (", F_RELFLG"); | |
759 | ||
760 | if ((flags & F_EXEC) != 0) | |
761 | printf (", F_EXEC"); | |
762 | ||
763 | if ((flags & F_LNNO) != 0) | |
764 | printf (", F_LNNO"); | |
765 | ||
766 | if ((flags & F_LSYMS) != 0) | |
767 | printf (", F_LSYMS"); | |
768 | ||
769 | if ((flags & F_MINMAL) != 0) | |
770 | printf (", F_MINMAL"); | |
771 | ||
772 | if ((flags & F_UPDATE) != 0) | |
773 | printf (", F_UPDATE"); | |
774 | ||
775 | if ((flags & F_SWABD) != 0) | |
776 | printf (", F_SWABD"); | |
777 | ||
778 | if ((flags & F_AR16WR) != 0) | |
779 | printf (", F_AR16WR"); | |
780 | ||
781 | if ((flags & F_AR32WR) != 0) | |
782 | printf (", F_AR32WR"); | |
783 | ||
784 | if ((flags & F_AR32W) != 0) | |
785 | printf (", F_AR32W"); | |
786 | ||
787 | if ((flags & F_PATCH) != 0) | |
788 | printf (", F_PATCH/F_NODF"); | |
789 | ||
790 | printf ("\n\n"); | |
791 | } | |
792 | ||
793 | \f | |
794 | /* Print out the symbolic header. */ | |
795 | ||
796 | void | |
797 | print_sym_hdr (sym_ptr) | |
798 | HDRR *sym_ptr; | |
799 | { | |
800 | int width = 20; | |
801 | ||
802 | printf("Symbolic header, magic number = 0x%04x, vstamp = %d.%d:\n\n", | |
803 | sym_ptr->magic & 0xffff, | |
804 | (sym_ptr->vstamp & 0xffff) >> 8, | |
805 | sym_ptr->vstamp & 0xff); | |
806 | ||
807 | printf(" %-*s %11s %11s %11s\n", width, "Info", "Offset", "Number", "Bytes"); | |
808 | printf(" %-*s %11s %11s %11s\n", width, "====", "======", "======", "=====\n"); | |
809 | ||
810 | printf(" %-*s %11ld %11d %11d [%d]\n", width, "Line numbers", | |
811 | sym_ptr->cbLineOffset, sym_ptr->cbLine, sym_ptr->cbLine, sym_ptr->ilineMax); | |
812 | ||
813 | printf(" %-*s %11ld %11d %11d\n", width, "Dense numbers", | |
814 | sym_ptr->cbDnOffset, sym_ptr->idnMax, sym_ptr->idnMax * sizeof (DNR)); | |
815 | ||
816 | printf(" %-*s %11ld %11d %11d\n", width, "Procedures Tables", | |
817 | sym_ptr->cbPdOffset, sym_ptr->ipdMax, sym_ptr->ipdMax * sizeof (PDR)); | |
818 | ||
819 | printf(" %-*s %11ld %11d %11d\n", width, "Local Symbols", | |
820 | sym_ptr->cbSymOffset, sym_ptr->isymMax, sym_ptr->isymMax * sizeof (SYMR)); | |
821 | ||
822 | printf(" %-*s %11ld %11d %11d\n", width, "Optimization Symbols", | |
823 | sym_ptr->cbOptOffset, sym_ptr->ioptMax, sym_ptr->ioptMax * sizeof (OPTR)); | |
824 | ||
64fd9134 | 825 | printf(" %-*s %11ld %11d %11d\n", width, "Auxiliary Symbols", |
68e9eb95 RS |
826 | sym_ptr->cbAuxOffset, sym_ptr->iauxMax, sym_ptr->iauxMax * sizeof (AUXU)); |
827 | ||
828 | printf(" %-*s %11ld %11d %11d\n", width, "Local Strings", | |
829 | sym_ptr->cbSsOffset, sym_ptr->issMax, sym_ptr->issMax); | |
830 | ||
831 | printf(" %-*s %11ld %11d %11d\n", width, "External Strings", | |
832 | sym_ptr->cbSsExtOffset, sym_ptr->issExtMax, sym_ptr->issExtMax); | |
833 | ||
834 | printf(" %-*s %11ld %11d %11d\n", width, "File Tables", | |
835 | sym_ptr->cbFdOffset, sym_ptr->ifdMax, sym_ptr->ifdMax * sizeof (FDR)); | |
836 | ||
837 | printf(" %-*s %11ld %11d %11d\n", width, "Relative Files", | |
838 | sym_ptr->cbRfdOffset, sym_ptr->crfd, sym_ptr->crfd * sizeof (ulong)); | |
839 | ||
840 | printf(" %-*s %11ld %11d %11d\n", width, "External Symbols", | |
841 | sym_ptr->cbExtOffset, sym_ptr->iextMax, sym_ptr->iextMax * sizeof (EXTR)); | |
842 | } | |
843 | ||
844 | \f | |
845 | /* Print out a symbol. */ | |
846 | ||
847 | void | |
848 | print_symbol (sym_ptr, number, strbase, aux_base, ifd) | |
849 | SYMR *sym_ptr; | |
850 | int number; | |
851 | char *strbase; | |
852 | AUXU *aux_base; | |
853 | int ifd; | |
854 | { | |
855 | sc_t storage_class = (sc_t) sym_ptr->sc; | |
856 | st_t symbol_type = (st_t) sym_ptr->st; | |
857 | ulong index = sym_ptr->index; | |
858 | char *used_ptr = aux_used + (aux_base - aux_symbols); | |
859 | scope_t *scope_ptr; | |
860 | ||
861 | printf ("\n Symbol# %d: \"%s\"\n", number, sym_ptr->iss + strbase); | |
862 | ||
863 | if (aux_base != (AUXU *)0 && index != indexNil) | |
864 | switch (symbol_type) | |
865 | { | |
866 | case st_Nil: | |
867 | case st_Label: | |
868 | break; | |
869 | ||
870 | case st_File: | |
871 | case st_Block: | |
872 | printf (" End+1 symbol: %ld\n", index); | |
873 | if (want_scope) | |
874 | { | |
875 | if (free_scope == (scope_t *)0) | |
876 | scope_ptr = (scope_t *) malloc (sizeof (scope_t)); | |
877 | else | |
878 | { | |
879 | scope_ptr = free_scope; | |
880 | free_scope = scope_ptr->prev; | |
881 | } | |
882 | scope_ptr->open_sym = number; | |
883 | scope_ptr->st = symbol_type; | |
884 | scope_ptr->sc = storage_class; | |
885 | scope_ptr->prev = cur_scope; | |
886 | cur_scope = scope_ptr; | |
887 | } | |
888 | break; | |
889 | ||
890 | case st_End: | |
891 | if (storage_class == sc_Text || storage_class == sc_Info) | |
892 | printf (" First symbol: %ld\n", index); | |
893 | else | |
894 | { | |
895 | used_ptr[index] = 1; | |
896 | printf (" First symbol: %ld\n", aux_base[index].isym); | |
897 | } | |
898 | ||
899 | if (want_scope) | |
900 | { | |
901 | if (cur_scope == (scope_t *)0) | |
902 | printf (" Can't pop end scope\n"); | |
903 | else | |
904 | { | |
905 | scope_ptr = cur_scope; | |
906 | cur_scope = scope_ptr->prev; | |
907 | scope_ptr->prev = free_scope; | |
908 | free_scope = scope_ptr; | |
909 | } | |
910 | } | |
911 | break; | |
912 | ||
913 | case st_Proc: | |
914 | case st_StaticProc: | |
915 | if (MIPS_IS_STAB(sym_ptr)) | |
916 | ; | |
917 | else if (ifd == -1) /* local symbol */ | |
918 | { | |
919 | used_ptr[index] = used_ptr[index+1] = 1; | |
920 | printf (" End+1 symbol: %-7ld Type: %s\n", | |
921 | aux_base[index].isym, type_to_string (aux_base, index+1)); | |
922 | } | |
923 | else /* global symbol */ | |
924 | { | |
925 | used_ptr[index] = 1; | |
926 | printf (" Type: %s\n", | |
927 | type_to_string (aux_base, index)); | |
928 | } | |
929 | ||
930 | if (want_scope) | |
931 | { | |
932 | if (free_scope == (scope_t *)0) | |
933 | scope_ptr = (scope_t *) malloc (sizeof (scope_t)); | |
934 | else | |
935 | { | |
936 | scope_ptr = free_scope; | |
937 | free_scope = scope_ptr->prev; | |
938 | } | |
939 | scope_ptr->open_sym = number; | |
940 | scope_ptr->st = symbol_type; | |
941 | scope_ptr->sc = storage_class; | |
942 | scope_ptr->prev = cur_scope; | |
943 | cur_scope = scope_ptr; | |
944 | } | |
945 | break; | |
946 | ||
947 | default: | |
948 | if (!MIPS_IS_STAB (sym_ptr)) | |
949 | { | |
950 | used_ptr[index] = 1; | |
951 | printf (" Type: %s\n", | |
952 | type_to_string (aux_base, index)); | |
953 | } | |
954 | break; | |
955 | } | |
956 | ||
957 | if (want_scope) | |
958 | { | |
959 | printf (" Scopes: "); | |
960 | if (cur_scope == (scope_t *)0) | |
961 | printf (" none\n"); | |
962 | else | |
963 | { | |
964 | for (scope_ptr = cur_scope; | |
965 | scope_ptr != (scope_t *)0; | |
966 | scope_ptr = scope_ptr->prev) | |
967 | { | |
968 | char *class; | |
969 | if (scope_ptr->st == st_Proc || scope_ptr->st == st_StaticProc) | |
970 | class = "func."; | |
971 | else if (scope_ptr->st == st_File) | |
972 | class = "file"; | |
973 | else if (scope_ptr->st == st_Block && scope_ptr->sc == sc_Text) | |
974 | class = "block"; | |
975 | else if (scope_ptr->st == st_Block && scope_ptr->sc == sc_Info) | |
976 | class = "type"; | |
977 | else | |
978 | class = "???"; | |
979 | ||
980 | printf (" %d [%s]", scope_ptr->open_sym, class); | |
981 | } | |
982 | printf ("\n"); | |
983 | } | |
984 | } | |
985 | ||
986 | printf (" Value: %-13ld ", | |
987 | (long)sym_ptr->value); | |
988 | if (ifd == -1) | |
989 | printf ("String index: %ld\n", (long)sym_ptr->iss); | |
990 | else | |
991 | printf ("String index: %-11ld Ifd: %d\n", | |
992 | (long)sym_ptr->iss, ifd); | |
993 | ||
994 | printf (" Symbol type: %-11sStorage class: %-11s", | |
995 | st_to_string (symbol_type), sc_to_string (storage_class)); | |
996 | ||
997 | if (MIPS_IS_STAB(sym_ptr)) | |
998 | { | |
999 | register int i = sizeof(stab_names) / sizeof(stab_names[0]); | |
1000 | char *stab_name = "stab"; | |
1001 | short code = MIPS_UNMARK_STAB(sym_ptr->index); | |
1002 | while (--i >= 0) | |
1003 | if (stab_names[i].code == code) | |
1004 | { | |
1005 | stab_name = stab_names[i].string; | |
1006 | break; | |
1007 | } | |
1008 | printf ("Index: 0x%lx (%s)\n", (long)sym_ptr->index, stab_name); | |
1009 | } | |
1010 | else if (sym_ptr->st == stLabel && sym_ptr->index != indexNil) | |
1011 | printf ("Index: %ld (line#)\n", (long)sym_ptr->index); | |
1012 | else | |
1013 | printf ("Index: %ld\n", (long)sym_ptr->index); | |
1014 | ||
1015 | } | |
1016 | ||
1017 | \f | |
1018 | /* Print out a word from the aux. table in various formats. */ | |
1019 | ||
1020 | void | |
1021 | print_aux (u, auxi, used) | |
1022 | AUXU u; | |
1023 | int auxi; | |
1024 | int used; | |
1025 | { | |
1026 | printf ("\t%s#%-5d %11ld, [%4ld/%7ld], [%2d %1d:%1d %1x:%1x:%1x:%1x:%1x:%1x]\n", | |
1027 | (used) ? " " : "* ", | |
1028 | auxi, | |
1029 | (long) u.isym, | |
1030 | (long) u.rndx.rfd, | |
1031 | (long) u.rndx.index, | |
1032 | u.ti.bt, | |
1033 | u.ti.fBitfield, | |
1034 | u.ti.continued, | |
1035 | u.ti.tq0, | |
1036 | u.ti.tq1, | |
1037 | u.ti.tq2, | |
1038 | u.ti.tq3, | |
1039 | u.ti.tq4, | |
1040 | u.ti.tq5); | |
1041 | } | |
1042 | ||
1043 | \f | |
1044 | /* Write aggregate information to a string. */ | |
1045 | ||
1046 | void | |
1047 | emit_aggregate (string, u, u2, which) | |
1048 | char *string; | |
1049 | AUXU u; | |
1050 | AUXU u2; | |
1051 | const char *which; | |
1052 | { | |
1053 | int ifd = u.rndx.rfd; | |
1054 | int index = u.rndx.index; | |
1055 | int sym_base, ss_base; | |
1056 | int name; | |
1057 | ||
1058 | if (ifd == ST_RFDESCAPE) | |
1059 | ifd = u2.isym; | |
1060 | ||
1061 | sym_base = file_desc[ifd].isymBase; | |
1062 | ss_base = file_desc[ifd].issBase; | |
1063 | ||
1064 | name = (index == indexNil) ? 0 : l_symbols[index + sym_base].iss; | |
1065 | sprintf (string, | |
1066 | "%s %s { ifd = %d, index = %d }", | |
1067 | which, | |
1068 | (name == 0) ? "/* no name */" : &l_strings[ ss_base + name ], | |
1069 | ifd, | |
1070 | index); | |
1071 | } | |
1072 | ||
1073 | \f | |
1074 | /* Print out information about a file descriptor, and the symbols, | |
1075 | procedures, and line numbers within it. */ | |
1076 | ||
1077 | void | |
1078 | print_file_desc (fdp, number) | |
1079 | FDR *fdp; | |
1080 | int number; | |
1081 | { | |
1082 | char *str_base; | |
1083 | AUXU *aux_base; | |
1084 | int symi, pdi; | |
1085 | int width = 20; | |
1086 | char *used_base; | |
1087 | ||
1088 | str_base = l_strings + fdp->issBase; | |
1089 | aux_base = aux_symbols + fdp->iauxBase; | |
1090 | used_base = aux_used + (aux_base - aux_symbols); | |
1091 | ||
1092 | printf ("\nFile #%d, \"%s\"\n\n", number, str_base + fdp->rss); | |
1093 | ||
1094 | printf (" Name index = %-10d Readin = %s\n", | |
1095 | (long) fdp->rss, (fdp->fReadin) ? "Yes" : "No"); | |
1096 | ||
1097 | printf (" Merge = %-10s Endian = %s\n", | |
1098 | (fdp->fMerge) ? "Yes" : "No", | |
1099 | (fdp->fBigendian) ? "BIG" : "LITTLE"); | |
1100 | ||
1101 | printf (" Debug level = %-10s Language = %s\n", | |
1102 | glevel_to_string (fdp->glevel), | |
1103 | lang_to_string((lang_t) fdp->lang)); | |
1104 | ||
1105 | printf (" Adr = 0x%08lx\n\n", (long) fdp->adr); | |
1106 | ||
1107 | printf(" %-*s %11s %11s %11s %11s\n", width, "Info", "Start", "Number", "Size", "Offset"); | |
1108 | printf(" %-*s %11s %11s %11s %11s\n", width, "====", "=====", "======", "====", "======"); | |
1109 | ||
1110 | printf(" %-*s %11lu %11lu %11lu %11lu\n", | |
1111 | width, "Local strings", | |
1112 | (ulong) fdp->issBase, | |
1113 | (ulong) fdp->cbSs, | |
1114 | (ulong) fdp->cbSs, | |
1115 | (ulong) (fdp->issBase + sym_hdr.cbSsOffset)); | |
1116 | ||
1117 | printf(" %-*s %11lu %11u %11u %11lu\n", | |
1118 | width, "Local symbols", | |
1119 | (ulong) fdp->isymBase, | |
1120 | (ulong) fdp->csym, | |
1121 | (ulong) (fdp->csym * sizeof (SYMR)), | |
1122 | (ulong) (fdp->isymBase * sizeof (SYMR) + sym_hdr.cbSymOffset)); | |
1123 | ||
1124 | printf(" %-*s %11lu %11lu %11lu %11lu\n", | |
1125 | width, "Line numbers", | |
1126 | (ulong) fdp->cbLineOffset, | |
1127 | (ulong) fdp->cline, | |
1128 | (ulong) fdp->cline, | |
1129 | (ulong) (fdp->cbLineOffset + sym_hdr.cbLineOffset)); | |
1130 | ||
1131 | printf(" %-*s %11lu %11lu %11lu %11lu\n", | |
1132 | width, "Optimization symbols", | |
1133 | (ulong) fdp->ioptBase, | |
1134 | (ulong) fdp->copt, | |
1135 | (ulong) (fdp->copt * sizeof (OPTR)), | |
1136 | (ulong) (fdp->ioptBase * sizeof (OPTR) + sym_hdr.cbOptOffset)); | |
1137 | ||
1138 | printf(" %-*s %11llu %11lu %11lu %11lu\n", | |
1139 | width, "Procedures", | |
1140 | (ulong) fdp->ipdFirst, | |
1141 | (ulong) fdp->cpd, | |
1142 | (ulong) (fdp->cpd * sizeof (PDR)), | |
1143 | (ulong) (fdp->ipdFirst * sizeof (PDR) + sym_hdr.cbPdOffset)); | |
1144 | ||
1145 | printf(" %-*s %11lu %11lu %11lu %11lu\n", | |
1146 | width, "Auxiliary symbols", | |
1147 | (ulong) fdp->iauxBase, | |
1148 | (ulong) fdp->caux, | |
1149 | (ulong) (fdp->caux * sizeof (AUXU)), | |
1150 | (ulong) (fdp->iauxBase * sizeof(AUXU) + sym_hdr.cbAuxOffset)); | |
1151 | ||
1152 | printf(" %-*s %11lu %11lu %11lu %11lu\n", | |
1153 | width, "Relative Files", | |
1154 | (ulong) fdp->rfdBase, | |
1155 | (ulong) fdp->crfd, | |
1156 | (ulong) (fdp->crfd * sizeof (ulong)), | |
1157 | (ulong) (fdp->rfdBase * sizeof(ulong) + sym_hdr.cbRfdOffset)); | |
1158 | ||
1159 | ||
1160 | if (want_scope && cur_scope != (scope_t *)0) | |
1161 | printf ("\n Warning scope does not start at 0!\n"); | |
1162 | ||
1163 | /* | |
1164 | * print the info about the symbol table. | |
1165 | */ | |
1166 | printf ("\n There are %lu local symbols, starting at %lu\n", | |
1167 | (ulong) fdp->csym, | |
1168 | (ulong) (fdp->isymBase + sym_hdr.cbSymOffset)); | |
1169 | ||
1170 | for(symi = fdp->isymBase; symi < (fdp->csym + fdp->isymBase); symi++) | |
1171 | print_symbol (&l_symbols[symi], | |
1172 | symi - fdp->isymBase, | |
1173 | str_base, | |
1174 | aux_base, | |
1175 | -1); | |
1176 | ||
1177 | if (want_scope && cur_scope != (scope_t *)0) | |
1178 | printf ("\n Warning scope does not end at 0!\n"); | |
1179 | ||
1180 | /* | |
1181 | * print the aux. table if desired. | |
1182 | */ | |
1183 | ||
1184 | if (want_aux && fdp->caux != 0) | |
1185 | { | |
1186 | int auxi; | |
1187 | ||
1188 | printf ("\n There are %lu auxiliary table entries, starting at %lu.\n\n", | |
1189 | (ulong) fdp->caux, | |
1190 | (ulong) (fdp->iauxBase + sym_hdr.cbAuxOffset)); | |
1191 | ||
1192 | for (auxi = fdp->iauxBase; auxi < (fdp->caux + fdp->iauxBase); auxi++) | |
1193 | print_aux (aux_base[auxi], auxi, used_base[auxi]); | |
1194 | } | |
1195 | ||
1196 | /* | |
1197 | * print the relative file descriptors. | |
1198 | */ | |
1199 | if (want_rfd && fdp->crfd != 0) | |
1200 | { | |
1201 | ulong *rfd_ptr, i; | |
1202 | ||
1203 | printf ("\n There are %lu relative file descriptors, starting at %lu.\n", | |
1204 | (ulong) fdp->crfd, | |
1205 | (ulong) fdp->rfdBase); | |
1206 | ||
f11f1fb5 | 1207 | rfd_ptr = rfile_desc + fdp->rfdBase; |
68e9eb95 RS |
1208 | for (i = 0; i < fdp->crfd; i++) |
1209 | { | |
1210 | printf ("\t#%-5ld %11ld, 0x%08lx\n", i, *rfd_ptr, *rfd_ptr); | |
1211 | rfd_ptr++; | |
1212 | } | |
1213 | } | |
1214 | ||
1215 | /* | |
1216 | * do the procedure descriptors. | |
1217 | */ | |
1218 | printf ("\n There are %lu procedure descriptor entries, ", (ulong) fdp->cpd); | |
1219 | printf ("starting at %lu.\n", (ulong) fdp->ipdFirst); | |
1220 | ||
1221 | for (pdi = fdp->ipdFirst; pdi < (fdp->cpd + fdp->ipdFirst); pdi++) | |
1222 | { | |
1223 | PDR *proc_ptr = &proc_desc[pdi]; | |
1224 | printf ("\n\tProcedure descriptor %d:\n", (pdi - fdp->ipdFirst)); | |
1225 | ||
1226 | printf ("\t Name index = %-11ld Name = \"%s\"\n", | |
1227 | (long) l_symbols[proc_ptr->isym + fdp->isymBase].iss, | |
1228 | l_symbols[proc_ptr->isym + fdp->isymBase].iss + str_base); | |
1229 | ||
1230 | printf ("\t .mask 0x%08lx,%-9ld .fmask 0x%08lx,%ld\n", | |
1231 | (long) proc_ptr->regmask, | |
1232 | (long) proc_ptr->regoffset, | |
1233 | (long) proc_ptr->fregmask, | |
1234 | (long) proc_ptr->fregoffset); | |
1235 | ||
1236 | printf ("\t .frame $%d,%ld,$%d\n", | |
1237 | (int) proc_ptr->framereg, | |
1238 | (long) proc_ptr->frameoffset, | |
1239 | (int) proc_ptr->pcreg); | |
1240 | ||
1241 | printf ("\t Opt. start = %-11ld Symbols start = %ld\n", | |
1242 | (long) proc_ptr->iopt, | |
1243 | (long) proc_ptr->isym); | |
1244 | ||
1245 | printf ("\t First line # = %-11ld Last line # = %ld\n", | |
1246 | (long) proc_ptr->lnLow, | |
1247 | (long) proc_ptr->lnHigh); | |
1248 | ||
1249 | printf ("\t Line Offset = %-11ld Address = 0x%08lx\n", | |
1250 | (long) proc_ptr->cbLineOffset, | |
1251 | (long) proc_ptr->adr); | |
1252 | ||
1253 | /* | |
1254 | * print the line number entries. | |
1255 | */ | |
1256 | ||
1257 | if (want_line && fdp->cline != 0) | |
1258 | { | |
1259 | int delta, count; | |
1260 | long cur_line = proc_ptr->lnLow; | |
1261 | uchar *line_ptr = ((uchar *)lines) + proc_ptr->cbLineOffset; | |
1262 | uchar *line_end; | |
1263 | ||
1264 | if (pdi == fdp->cpd + fdp->ipdFirst - 1) /* last procedure */ | |
1265 | line_end = ((uchar *)lines) + fdp->cbLine + fdp->ilineBase; | |
1266 | else /* not last proc. */ | |
1267 | line_end = ((uchar *)lines) + proc_desc[pdi+1].cbLineOffset; | |
1268 | ||
1269 | ||
1270 | printf ("\n\tThere are %lu bytes holding line numbers, starting at %lu.\n", | |
1271 | (ulong) (line_end - line_ptr), | |
1272 | (ulong) (fdp->ilineBase + sym_hdr.cbLineOffset)); | |
1273 | ||
1274 | while (line_ptr < line_end) | |
1275 | { /* sign extend nibble */ | |
1276 | delta = ((*line_ptr >> 4) ^ 0x8) - 0x8; | |
1277 | count = (*line_ptr & 0xf) + 1; | |
1278 | if (delta != -8) | |
1279 | line_ptr++; | |
1280 | else | |
1281 | { | |
1282 | delta = (((line_ptr[1]) & 0xff) << 8) + ((line_ptr[2]) & 0xff); | |
1283 | delta = (delta ^ 0x8000) - 0x8000; | |
1284 | line_ptr += 3; | |
1285 | } | |
1286 | ||
1287 | cur_line += delta; | |
1288 | printf ("\t Line %11ld, delta %5d, count %2d\n", | |
1289 | cur_line, | |
1290 | delta, | |
1291 | count); | |
1292 | } | |
1293 | } | |
1294 | } | |
1295 | } | |
1296 | ||
1297 | \f | |
1298 | /* Read in the portions of the .T file that we will print out. */ | |
1299 | ||
1300 | void | |
1301 | read_tfile __proto((void)) | |
1302 | { | |
1303 | short magic; | |
1304 | off_t sym_hdr_offset = 0; | |
1305 | ||
1306 | /* Determine if this is a .T file (which has no file header), or some | |
1307 | sort of object file (which does have a file header) via the magic | |
1308 | number. */ | |
1309 | (void) read_seek ((PTR_T) &magic, sizeof (magic), (off_t)0, "Magic number"); | |
1310 | if (magic == MIPSELMAGIC || magic == MIPSEBMAGIC) | |
1311 | { | |
1312 | (void) read_seek ((PTR_T) &global_hdr, sizeof (global_hdr), (off_t)0, | |
1313 | "Global file header"); | |
1314 | ||
1315 | print_global_hdr (&global_hdr); | |
1316 | ||
1317 | if (global_hdr.f_symptr == 0) | |
1318 | { | |
1319 | printf ("No symbolic header, Goodbye!\n"); | |
1320 | exit (1); | |
1321 | } | |
1322 | ||
1323 | sym_hdr_offset = global_hdr.f_symptr; | |
1324 | } | |
1325 | ||
1326 | (void) read_seek ((PTR_T) &sym_hdr, | |
1327 | sizeof (sym_hdr), | |
1328 | sym_hdr_offset, | |
1329 | "Symbolic header"); | |
1330 | ||
1331 | print_sym_hdr (&sym_hdr); | |
1332 | ||
1333 | lines = (LINER *) read_seek ((PTR_T)0, | |
1334 | sym_hdr.cbLine, | |
1335 | sym_hdr.cbLineOffset, | |
1336 | "Line numbers"); | |
1337 | ||
1338 | dense_nums = (DNR *) read_seek ((PTR_T)0, | |
1339 | sym_hdr.idnMax * sizeof (DNR), | |
1340 | sym_hdr.cbDnOffset, | |
1341 | "Dense numbers"); | |
1342 | ||
1343 | proc_desc = (PDR *) read_seek ((PTR_T)0, | |
1344 | sym_hdr.ipdMax * sizeof (PDR), | |
1345 | sym_hdr.cbPdOffset, | |
1346 | "Procedure tables"); | |
1347 | ||
1348 | l_symbols = (SYMR *) read_seek ((PTR_T)0, | |
1349 | sym_hdr.isymMax * sizeof (SYMR), | |
1350 | sym_hdr.cbSymOffset, | |
1351 | "Local symbols"); | |
1352 | ||
1353 | opt_symbols = (OPTR *) read_seek ((PTR_T)0, | |
1354 | sym_hdr.ioptMax * sizeof (OPTR), | |
1355 | sym_hdr.cbOptOffset, | |
1356 | "Optimization symbols"); | |
1357 | ||
1358 | aux_symbols = (AUXU *) read_seek ((PTR_T)0, | |
1359 | sym_hdr.iauxMax * sizeof (AUXU), | |
1360 | sym_hdr.cbAuxOffset, | |
64fd9134 | 1361 | "Auxiliary symbols"); |
68e9eb95 RS |
1362 | |
1363 | if (sym_hdr.iauxMax > 0) | |
1364 | { | |
1365 | aux_used = calloc (sym_hdr.iauxMax, 1); | |
1366 | if (aux_used == (char *)0) | |
1367 | { | |
1368 | perror ("calloc"); | |
1369 | exit (1); | |
1370 | } | |
1371 | } | |
1372 | ||
1373 | l_strings = (char *) read_seek ((PTR_T)0, | |
1374 | sym_hdr.issMax, | |
1375 | sym_hdr.cbSsOffset, | |
1376 | "Local string table"); | |
1377 | ||
1378 | e_strings = (char *) read_seek ((PTR_T)0, | |
1379 | sym_hdr.issExtMax, | |
1380 | sym_hdr.cbSsExtOffset, | |
1381 | "External string table"); | |
1382 | ||
1383 | file_desc = (FDR *) read_seek ((PTR_T)0, | |
1384 | sym_hdr.ifdMax * sizeof (FDR), | |
1385 | sym_hdr.cbFdOffset, | |
1386 | "File tables"); | |
1387 | ||
1388 | rfile_desc = (ulong *) read_seek ((PTR_T)0, | |
1389 | sym_hdr.crfd * sizeof (ulong), | |
1390 | sym_hdr.cbRfdOffset, | |
1391 | "Relative file tables"); | |
1392 | ||
1393 | e_symbols = (EXTR *) read_seek ((PTR_T)0, | |
1394 | sym_hdr.iextMax * sizeof (EXTR), | |
1395 | sym_hdr.cbExtOffset, | |
1396 | "External symbols"); | |
1397 | } | |
1398 | ||
1399 | \f | |
1400 | ||
1401 | int | |
1402 | main (argc, argv) | |
1403 | int argc; | |
1404 | char **argv; | |
1405 | { | |
1406 | int i, opt; | |
1407 | ||
1408 | /* | |
1409 | * Process arguments | |
1410 | */ | |
1411 | while ((opt = getopt (argc, argv, "alrs")) != EOF) | |
1412 | switch (opt) | |
1413 | { | |
1414 | default: errors++; break; | |
1415 | case 'a': want_aux++; break; /* print aux table */ | |
1416 | case 'l': want_line++; break; /* print line numbers */ | |
1417 | case 'r': want_rfd++; break; /* print relative fd's */ | |
1418 | case 's': want_scope++; break; /* print scope info */ | |
1419 | } | |
1420 | ||
1421 | if (errors || optind != argc - 1) | |
1422 | { | |
1423 | fprintf (stderr, "Calling Sequence:\n"); | |
1424 | fprintf (stderr, "\t%0 [-alrs] <object-or-T-file>\n", argv[0]); | |
1425 | fprintf (stderr, "\n"); | |
1426 | fprintf (stderr, "switches:\n"); | |
1427 | fprintf (stderr, "\t-a Print out auxiliary table.\n"); | |
1428 | fprintf (stderr, "\t-l Print out line numbers.\n"); | |
1429 | fprintf (stderr, "\t-r Print out relative file descriptors.\n"); | |
1430 | fprintf (stderr, "\t-s Print out the current scopes for an item.\n"); | |
1431 | return 1; | |
1432 | } | |
1433 | ||
1434 | /* | |
1435 | * Open and process the input file. | |
1436 | */ | |
1437 | tfile_fd = open (argv[optind], O_RDONLY); | |
1438 | if (tfile_fd < 0) | |
1439 | { | |
1440 | perror (argv[optind]); | |
1441 | return 1; | |
1442 | } | |
1443 | ||
1444 | read_tfile (); | |
1445 | ||
1446 | /* | |
1447 | * Print any global aux words if any. | |
1448 | */ | |
1449 | if (want_aux) | |
1450 | { | |
1451 | long last_aux_in_use; | |
1452 | ||
1453 | if (sym_hdr.ifdMax != 0 && file_desc[0].iauxBase != 0) | |
1454 | { | |
1455 | printf ("\nGlobal auxiliary entries before first file:\n"); | |
1456 | for (i = 0; i < file_desc[0].iauxBase; i++) | |
1457 | print_aux (aux_symbols[i], 0, aux_used[i]); | |
1458 | } | |
1459 | ||
1460 | if (sym_hdr.ifdMax == 0) | |
1461 | last_aux_in_use = 0; | |
1462 | else | |
1463 | last_aux_in_use = | |
1464 | file_desc[sym_hdr.ifdMax-1].iauxBase + | |
1465 | file_desc[sym_hdr.ifdMax-1].caux - 1; | |
1466 | ||
1467 | if (last_aux_in_use < sym_hdr.iauxMax-1) | |
1468 | { | |
1469 | printf ("\nGlobal auxiliary entries after last file:\n"); | |
1470 | for (i = last_aux_in_use; i < sym_hdr.iauxMax; i++) | |
1471 | print_aux (aux_symbols[i], i - last_aux_in_use, aux_used[i]); | |
1472 | } | |
1473 | } | |
1474 | ||
1475 | /* | |
1476 | * Print the information for each file. | |
1477 | */ | |
1478 | for (i = 0; i < sym_hdr.ifdMax; i++) | |
1479 | print_file_desc (&file_desc[i], i); | |
1480 | ||
1481 | /* | |
1482 | * Print the external symbols. | |
1483 | */ | |
1484 | want_scope = 0; /* scope info is meaning for extern symbols */ | |
1485 | printf ("\nThere are %lu external symbols, starting at %lu\n", | |
1486 | (ulong) sym_hdr.iextMax, | |
1487 | (ulong) sym_hdr.cbExtOffset); | |
1488 | ||
1489 | for(i = 0; i < sym_hdr.iextMax; i++) | |
1490 | print_symbol (&e_symbols[i].asym, i, e_strings, | |
1491 | aux_symbols + file_desc[e_symbols[i].ifd].iauxBase, | |
1492 | e_symbols[i].ifd); | |
1493 | ||
1494 | /* | |
1495 | * Print unused aux symbols now. | |
1496 | */ | |
1497 | ||
1498 | if (want_aux) | |
1499 | { | |
1500 | int first_time = 1; | |
1501 | ||
1502 | for (i = 0; i < sym_hdr.iauxMax; i++) | |
1503 | { | |
1504 | if (! aux_used[i]) | |
1505 | { | |
1506 | if (first_time) | |
1507 | { | |
1508 | printf ("\nThe following auxiliary table entries were unused:\n\n"); | |
1509 | first_time = 0; | |
1510 | } | |
1511 | ||
1512 | printf (" #%-5d %11ld 0x%08lx %s\n", | |
1513 | i, | |
1514 | (long) aux_symbols[i].isym, | |
1515 | (long) aux_symbols[i].isym, | |
1516 | type_to_string (aux_symbols, i)); | |
1517 | } | |
1518 | } | |
1519 | } | |
1520 | ||
1521 | return 0; | |
1522 | } | |
1523 | ||
1524 | \f | |
1525 | void | |
1526 | fancy_abort () | |
1527 | { | |
1528 | fprintf (stderr, "mips-tdump internal error"); | |
1529 | exit (1); | |
1530 | } | |
1531 | ||
1532 | void | |
1533 | fatal(s) | |
1534 | char *s; | |
1535 | { | |
1536 | fprintf(stderr, "%s\n", s); | |
1537 | exit(1); | |
1538 | } | |
1539 | ||
1540 | /* Same as `malloc' but report error if no memory available. */ | |
1541 | ||
1542 | PTR_T | |
1543 | xmalloc (size) | |
1544 | unsigned size; | |
1545 | { | |
1546 | register PTR_T value = malloc (size); | |
1547 | if (value == 0) | |
1548 | fatal ("Virtual memory exhausted."); | |
1549 | return value; | |
1550 | } |