1 /* Read and manage MIPS symbol tables from object modules.
2 Copyright (C) 1991, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2003, 2004,
3 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4 Contributed by hartzell@boulder.colorado.edu,
5 Rewritten by meissner@osf.org.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 3, or (at your option) any later
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3. If not see
21 <http://www.gnu.org/licenses/>. */
25 #include "coretypes.h"
31 #ifndef CROSS_DIRECTORY_STRUCTURE
34 #include "mips/a.out.h"
35 #endif /* CROSS_DIRECTORY_STRUCTURE */
37 /* Include getopt.h for the sake of getopt_long. */
41 /* Macros for mips-tfile.c to encapsulate stabs in ECOFF, and for
42 and mips-tdump.c to print them out. This is used on the Alpha,
43 which does not include mips.h.
45 These must match the corresponding definitions in gdb/mipsread.c.
46 Unfortunately, gcc and gdb do not currently share any directories. */
48 #define CODE_MASK 0x8F300
49 #define MIPS_IS_STAB(sym) (((sym)->index & 0xFFF00) == CODE_MASK)
50 #define MIPS_MARK_STAB(code) ((code)+CODE_MASK)
51 #define MIPS_UNMARK_STAB(code) ((code)-CODE_MASK)
54 #define uchar unsigned char
55 #define ushort unsigned short
56 #define uint unsigned int
57 #define ulong unsigned long
60 /* Redefinition of storage classes as an enumeration for better
64 #define stStaParam 16 /* Fortran static parameters */
68 #define btVoid 26 /* void basic type */
72 sc_Nil
= scNil
, /* no storage class */
73 sc_Text
= scText
, /* text symbol */
74 sc_Data
= scData
, /* initialized data symbol */
75 sc_Bss
= scBss
, /* un-initialized data symbol */
76 sc_Register
= scRegister
, /* value of symbol is register number */
77 sc_Abs
= scAbs
, /* value of symbol is absolute */
78 sc_Undefined
= scUndefined
, /* who knows? */
79 sc_CdbLocal
= scCdbLocal
, /* variable's value is IN se->va.?? */
80 sc_Bits
= scBits
, /* this is a bit field */
81 sc_CdbSystem
= scCdbSystem
, /* var's value is IN CDB's address space */
82 sc_RegImage
= scRegImage
, /* register value saved on stack */
83 sc_Info
= scInfo
, /* symbol contains debugger information */
84 sc_UserStruct
= scUserStruct
, /* addr in struct user for current process */
85 sc_SData
= scSData
, /* load time only small data */
86 sc_SBss
= scSBss
, /* load time only small common */
87 sc_RData
= scRData
, /* load time only read only data */
88 sc_Var
= scVar
, /* Var parameter (fortran,pascal) */
89 sc_Common
= scCommon
, /* common variable */
90 sc_SCommon
= scSCommon
, /* small common */
91 sc_VarRegister
= scVarRegister
, /* Var parameter in a register */
92 sc_Variant
= scVariant
, /* Variant record */
93 sc_SUndefined
= scSUndefined
, /* small undefined(external) data */
94 sc_Init
= scInit
, /* .init section symbol */
95 sc_Max
= scMax
/* Max storage class+1 */
98 /* Redefinition of symbol type. */
101 st_Nil
= stNil
, /* Nuthin' special */
102 st_Global
= stGlobal
, /* external symbol */
103 st_Static
= stStatic
, /* static */
104 st_Param
= stParam
, /* procedure argument */
105 st_Local
= stLocal
, /* local variable */
106 st_Label
= stLabel
, /* label */
107 st_Proc
= stProc
, /* " " Procedure */
108 st_Block
= stBlock
, /* beginning of block */
109 st_End
= stEnd
, /* end (of anything) */
110 st_Member
= stMember
, /* member (of anything - struct/union/enum */
111 st_Typedef
= stTypedef
, /* type definition */
112 st_File
= stFile
, /* file name */
113 st_RegReloc
= stRegReloc
, /* register relocation */
114 st_Forward
= stForward
, /* forwarding address */
115 st_StaticProc
= stStaticProc
, /* load time only static procs */
116 st_StaParam
= stStaParam
, /* Fortran static parameters */
117 st_Constant
= stConstant
, /* const */
119 st_Struct
= stStruct
, /* struct */
120 st_Union
= stUnion
, /* union */
121 st_Enum
= stEnum
, /* enum */
123 st_Str
= stStr
, /* string */
124 st_Number
= stNumber
, /* pure number (i.e. 4 NOR 2+2) */
125 st_Expr
= stExpr
, /* 2+2 vs. 4 */
126 st_Type
= stType
, /* post-coercion SER */
127 st_Max
= stMax
/* max type+1 */
130 /* Redefinition of type qualifiers. */
133 tq_Nil
= tqNil
, /* bt is what you see */
134 tq_Ptr
= tqPtr
, /* pointer */
135 tq_Proc
= tqProc
, /* procedure */
136 tq_Array
= tqArray
, /* duh */
137 tq_Far
= tqFar
, /* longer addressing - 8086/8 land */
138 tq_Vol
= tqVol
, /* volatile */
139 tq_Max
= tqMax
/* Max type qualifier+1 */
142 /* Redefinition of basic types. */
145 bt_Nil
= btNil
, /* undefined */
146 bt_Adr
= btAdr
, /* address - integer same size as pointer */
147 bt_Char
= btChar
, /* character */
148 bt_UChar
= btUChar
, /* unsigned character */
149 bt_Short
= btShort
, /* short */
150 bt_UShort
= btUShort
, /* unsigned short */
151 bt_Int
= btInt
, /* int */
152 bt_UInt
= btUInt
, /* unsigned int */
153 bt_Long
= btLong
, /* long */
154 bt_ULong
= btULong
, /* unsigned long */
155 bt_Float
= btFloat
, /* float (real) */
156 bt_Double
= btDouble
, /* Double (real) */
157 bt_Struct
= btStruct
, /* Structure (Record) */
158 bt_Union
= btUnion
, /* Union (variant) */
159 bt_Enum
= btEnum
, /* Enumerated */
160 bt_Typedef
= btTypedef
, /* defined via a typedef, isymRef points */
161 bt_Range
= btRange
, /* subrange of int */
162 bt_Set
= btSet
, /* pascal sets */
163 bt_Complex
= btComplex
, /* fortran complex */
164 bt_DComplex
= btDComplex
, /* fortran double complex */
165 bt_Indirect
= btIndirect
, /* forward or unnamed typedef */
166 bt_FixedDec
= btFixedDec
, /* Fixed Decimal */
167 bt_FloatDec
= btFloatDec
, /* Float Decimal */
168 bt_String
= btString
, /* Varying Length Character String */
169 bt_Bit
= btBit
, /* Aligned Bit String */
170 bt_Picture
= btPicture
, /* Picture */
171 bt_Void
= btVoid
, /* void */
172 bt_Max
= btMax
/* Max basic type+1 */
175 /* Redefinition of the language codes. */
179 lang_Pascal
= langPascal
,
180 lang_Fortran
= langFortran
,
181 lang_Assembler
= langAssembler
,
182 lang_Machine
= langMachine
,
186 lang_Cobol
= langCobol
189 /* Redefinition of the debug level codes. */
191 typedef enum glevel
{
199 /* Keep track of the active scopes. */
200 typedef struct scope
{
201 struct scope
*prev
; /* previous scope */
202 ulong open_sym
; /* symbol opening scope */
203 sc_t sc
; /* storage class */
204 st_t st
; /* symbol type */
207 struct filehdr global_hdr
; /* a.out header */
209 int errors
= 0; /* # of errors */
210 int want_aux
= 0; /* print aux table */
211 int want_line
= 0; /* print line numbers */
212 int want_rfd
= 0; /* print relative file desc's */
213 int want_scope
= 0; /* print scopes for every symbol */
214 int tfile
= 0; /* no global header file */
215 int version
= 0; /* print version # */
217 int tfile_fd
; /* file descriptor of .T file */
218 off_t tfile_offset
; /* current offset in .T file */
219 scope_t
*cur_scope
= 0; /* list of active scopes */
220 scope_t
*free_scope
= 0; /* list of freed scopes */
221 HDRR sym_hdr
; /* symbolic header */
222 char *l_strings
; /* local strings */
223 char *e_strings
; /* external strings */
224 SYMR
*l_symbols
; /* local symbols */
225 EXTR
*e_symbols
; /* external symbols */
226 LINER
*lines
; /* line numbers */
227 DNR
*dense_nums
; /* dense numbers */
228 OPTR
*opt_symbols
; /* optimization symbols */
229 AUXU
*aux_symbols
; /* Auxiliary symbols */
230 char *aux_used
; /* map of which aux syms are used */
231 FDR
*file_desc
; /* file tables */
232 ulong
*rfile_desc
; /* relative file tables */
233 PDR
*proc_desc
; /* procedure tables */
235 /* Forward reference for functions. */
236 static void *read_seek (void *, size_t, off_t
, const char *);
237 static void read_tfile (void);
238 static void print_global_hdr (struct filehdr
*);
239 static void print_sym_hdr (HDRR
*);
240 static void print_file_desc (FDR
*, int);
241 static void print_symbol (SYMR
*, int, const char *, AUXU
*, int, FDR
*);
242 static void print_aux (AUXU
, int, int);
243 static void emit_aggregate (char *, AUXU
, AUXU
, const char *, FDR
*);
244 static const char *st_to_string (st_t
);
245 static const char *sc_to_string (sc_t
);
246 static const char *glevel_to_string (glevel_t
);
247 static const char *lang_to_string (lang_t
);
248 static const char *type_to_string (AUXU
*, int, FDR
*);
254 /* Create a table of debugging stab-codes and corresponding names. */
256 #define __define_stab(NAME, CODE, STRING) {(int)CODE, STRING},
257 const struct {const short code
; const char string
[10];} stab_names
[] = {
262 /* Command line options for getopt_long. */
264 static const struct option options
[] =
266 { "version", 0, 0, 'V' },
267 { "verbose", 0, 0, 'v' },
271 /* Read some bytes at a specified location, and return a pointer.
272 Read_seek takes a pointer PTR to a buffer or NULL and reads SIZE
273 bytes from offset OFFSET. In case of errors CONTEXT is used as
277 read_seek (void *ptr
, size_t size
, off_t offset
, const char *context
)
281 if (size
== 0) /* nothing to read */
285 ptr
= xmalloc (size
);
287 if ((tfile_offset
!= offset
&& lseek (tfile_fd
, offset
, 0) == -1)
288 || (read_size
= read (tfile_fd
, ptr
, size
)) < 0)
294 if (read_size
!= (long) size
)
296 fprintf (stderr
, "%s: read %ld bytes, expected %ld bytes\n",
297 context
, read_size
, (long) size
);
301 tfile_offset
= offset
+ size
;
306 /* Convert language code to string format. */
309 lang_to_string (lang_t lang
)
313 case langC
: return "C";
314 case langPascal
: return "Pascal";
315 case langFortran
: return "Fortran";
316 case langAssembler
: return "Assembler";
317 case langMachine
: return "Machine";
318 case langNil
: return "Nil";
319 case langAda
: return "Ada";
320 case langPl1
: return "Pl1";
321 case langCobol
: return "Cobol";
324 return "Unknown language";
328 /* Convert storage class to string. */
331 sc_to_string (sc_t storage_class
)
333 switch(storage_class
)
335 case sc_Nil
: return "Nil";
336 case sc_Text
: return "Text";
337 case sc_Data
: return "Data";
338 case sc_Bss
: return "Bss";
339 case sc_Register
: return "Register";
340 case sc_Abs
: return "Abs";
341 case sc_Undefined
: return "Undefined";
342 case sc_CdbLocal
: return "CdbLocal";
343 case sc_Bits
: return "Bits";
344 case sc_CdbSystem
: return "CdbSystem";
345 case sc_RegImage
: return "RegImage";
346 case sc_Info
: return "Info";
347 case sc_UserStruct
: return "UserStruct";
348 case sc_SData
: return "SData";
349 case sc_SBss
: return "SBss";
350 case sc_RData
: return "RData";
351 case sc_Var
: return "Var";
352 case sc_Common
: return "Common";
353 case sc_SCommon
: return "SCommon";
354 case sc_VarRegister
: return "VarRegister";
355 case sc_Variant
: return "Variant";
356 case sc_SUndefined
: return "SUndefined";
357 case sc_Init
: return "Init";
358 case sc_Max
: return "Max";
365 /* Convert symbol type to string. */
368 st_to_string (st_t symbol_type
)
372 case st_Nil
: return "Nil";
373 case st_Global
: return "Global";
374 case st_Static
: return "Static";
375 case st_Param
: return "Param";
376 case st_Local
: return "Local";
377 case st_Label
: return "Label";
378 case st_Proc
: return "Proc";
379 case st_Block
: return "Block";
380 case st_End
: return "End";
381 case st_Member
: return "Member";
382 case st_Typedef
: return "Typedef";
383 case st_File
: return "File";
384 case st_RegReloc
: return "RegReloc";
385 case st_Forward
: return "Forward";
386 case st_StaticProc
: return "StaticProc";
387 case st_Constant
: return "Constant";
388 case st_StaParam
: return "StaticParam";
390 case st_Struct
: return "Struct";
391 case st_Union
: return "Union";
392 case st_Enum
: return "Enum";
394 case st_Str
: return "String";
395 case st_Number
: return "Number";
396 case st_Expr
: return "Expr";
397 case st_Type
: return "Type";
398 case st_Max
: return "Max";
405 /* Convert debug level to string. */
408 glevel_to_string (glevel_t g_level
)
412 case GLEVEL_0
: return "G0";
413 case GLEVEL_1
: return "G1";
414 case GLEVEL_2
: return "G2";
415 case GLEVEL_3
: return "G3";
422 /* Convert the type information to string format. */
425 type_to_string (AUXU
*aux_ptr
, int index
, FDR
*fdp
)
437 static char buffer1
[1024];
438 static char buffer2
[1024];
441 char *used_ptr
= aux_used
+ (aux_ptr
- aux_symbols
);
443 for (i
= 0; i
< 7; i
++)
445 qualifiers
[i
].low_bound
= 0;
446 qualifiers
[i
].high_bound
= 0;
447 qualifiers
[i
].stride
= 0;
451 u
= aux_ptr
[index
++];
453 return "-1 (no type)";
455 basic_type
= (bt_t
) u
.ti
.bt
;
456 qualifiers
[0].type
= (tq_t
) u
.ti
.tq0
;
457 qualifiers
[1].type
= (tq_t
) u
.ti
.tq1
;
458 qualifiers
[2].type
= (tq_t
) u
.ti
.tq2
;
459 qualifiers
[3].type
= (tq_t
) u
.ti
.tq3
;
460 qualifiers
[4].type
= (tq_t
) u
.ti
.tq4
;
461 qualifiers
[5].type
= (tq_t
) u
.ti
.tq5
;
462 qualifiers
[6].type
= tq_Nil
;
465 * Go get the basic type.
469 case bt_Nil
: /* undefined */
473 case bt_Adr
: /* address - integer same size as pointer */
474 strcpy (p1
, "address");
477 case bt_Char
: /* character */
481 case bt_UChar
: /* unsigned character */
482 strcpy (p1
, "unsigned char");
485 case bt_Short
: /* short */
486 strcpy (p1
, "short");
489 case bt_UShort
: /* unsigned short */
490 strcpy (p1
, "unsigned short");
493 case bt_Int
: /* int */
497 case bt_UInt
: /* unsigned int */
498 strcpy (p1
, "unsigned int");
501 case bt_Long
: /* long */
505 case bt_ULong
: /* unsigned long */
506 strcpy (p1
, "unsigned long");
509 case bt_Float
: /* float (real) */
510 strcpy (p1
, "float");
513 case bt_Double
: /* Double (real) */
514 strcpy (p1
, "double");
517 /* Structures add 1-2 aux words:
518 1st word is [ST_RFDESCAPE, offset] pointer to struct def;
519 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
521 case bt_Struct
: /* Structure (Record) */
522 emit_aggregate (p1
, aux_ptr
[index
], aux_ptr
[index
+1], "struct", fdp
);
524 if (aux_ptr
[index
].rndx
.rfd
== ST_RFDESCAPE
)
525 used_ptr
[++index
] = 1;
527 index
++; /* skip aux words */
530 /* Unions add 1-2 aux words:
531 1st word is [ST_RFDESCAPE, offset] pointer to union def;
532 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
534 case bt_Union
: /* Union */
535 emit_aggregate (p1
, aux_ptr
[index
], aux_ptr
[index
+1], "union", fdp
);
537 if (aux_ptr
[index
].rndx
.rfd
== ST_RFDESCAPE
)
538 used_ptr
[++index
] = 1;
540 index
++; /* skip aux words */
543 /* Enumerations add 1-2 aux words:
544 1st word is [ST_RFDESCAPE, offset] pointer to enum def;
545 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
547 case bt_Enum
: /* Enumeration */
548 emit_aggregate (p1
, aux_ptr
[index
], aux_ptr
[index
+1], "enum", fdp
);
550 if (aux_ptr
[index
].rndx
.rfd
== ST_RFDESCAPE
)
551 used_ptr
[++index
] = 1;
553 index
++; /* skip aux words */
556 case bt_Typedef
: /* defined via a typedef, isymRef points */
557 strcpy (p1
, "typedef");
560 case bt_Range
: /* subrange of int */
561 strcpy (p1
, "subrange");
564 case bt_Set
: /* pascal sets */
568 case bt_Complex
: /* fortran complex */
569 strcpy (p1
, "complex");
572 case bt_DComplex
: /* fortran double complex */
573 strcpy (p1
, "double complex");
576 case bt_Indirect
: /* forward or unnamed typedef */
577 strcpy (p1
, "forward/unnamed typedef");
580 case bt_FixedDec
: /* Fixed Decimal */
581 strcpy (p1
, "fixed decimal");
584 case bt_FloatDec
: /* Float Decimal */
585 strcpy (p1
, "float decimal");
588 case bt_String
: /* Varying Length Character String */
589 strcpy (p1
, "string");
592 case bt_Bit
: /* Aligned Bit String */
596 case bt_Picture
: /* Picture */
597 strcpy (p1
, "picture");
600 case bt_Void
: /* Void */
605 sprintf (p1
, "Unknown basic type %d", (int) basic_type
);
609 p1
+= strlen (buffer1
);
612 * If this is a bitfield, get the bitsize.
619 bitsize
= aux_ptr
[index
++].width
;
620 sprintf (p1
, " : %d", bitsize
);
621 p1
+= strlen (buffer1
);
626 * Deal with any qualifiers.
628 if (qualifiers
[0].type
!= tq_Nil
)
631 * Snarf up any array bounds in the correct order. Arrays
632 * store 5 successive words in the aux. table:
633 * word 0 RNDXR to type of the bounds (i.e., int)
634 * word 1 Current file descriptor index
636 * word 3 high bound (or -1 if [])
637 * word 4 stride size in bits
639 for (i
= 0; i
< 7; i
++)
641 if (qualifiers
[i
].type
== tq_Array
)
643 qualifiers
[i
].low_bound
= aux_ptr
[index
+2].dnLow
;
644 qualifiers
[i
].high_bound
= aux_ptr
[index
+3].dnHigh
;
645 qualifiers
[i
].stride
= aux_ptr
[index
+4].width
;
647 used_ptr
[index
+1] = 1;
648 used_ptr
[index
+2] = 1;
649 used_ptr
[index
+3] = 1;
650 used_ptr
[index
+4] = 1;
656 * Now print out the qualifiers.
658 for (i
= 0; i
< 6; i
++)
660 switch (qualifiers
[i
].type
)
667 strcpy (p2
, "ptr to ");
668 p2
+= sizeof ("ptr to ")-1;
672 strcpy (p2
, "volatile ");
673 p2
+= sizeof ("volatile ")-1;
678 p2
+= sizeof ("far ")-1;
682 strcpy (p2
, "func. ret. ");
683 p2
+= sizeof ("func. ret. ");
691 /* Print array bounds reversed (i.e., in the order the C
692 programmer writes them). C is such a fun language.... */
694 while (i
< 5 && qualifiers
[i
+1].type
== tq_Array
)
697 for (j
= i
; j
>= first_array
; j
--)
699 strcpy (p2
, "array [");
700 p2
+= sizeof ("array [")-1;
701 if (qualifiers
[j
].low_bound
!= 0)
703 "%ld:%ld {%ld bits}",
704 (long) qualifiers
[j
].low_bound
,
705 (long) qualifiers
[j
].high_bound
,
706 (long) qualifiers
[j
].stride
);
708 else if (qualifiers
[j
].high_bound
!= -1)
711 (long) (qualifiers
[j
].high_bound
+ 1),
712 (long) (qualifiers
[j
].stride
));
715 sprintf (p2
, " {%ld bits}", (long) (qualifiers
[j
].stride
));
718 strcpy (p2
, "] of ");
719 p2
+= sizeof ("] of ")-1;
727 strcpy (p2
, buffer1
);
732 /* Print out the global file header for object files. */
735 print_global_hdr (struct filehdr
*ptr
)
737 char *time
= ctime ((time_t *)&ptr
->f_timdat
);
738 ushort flags
= ptr
->f_flags
;
740 printf("Global file header:\n");
741 printf(" %-*s 0x%x\n", 24, "magic number", (ushort
) ptr
->f_magic
);
742 printf(" %-*s %d\n", 24, "# sections", (int) ptr
->f_nscns
);
743 printf(" %-*s %ld, %s", 24, "timestamp", (long) ptr
->f_timdat
, time
);
744 printf(" %-*s %ld\n", 24, "symbolic header offset", (long) ptr
->f_symptr
);
745 printf(" %-*s %ld\n", 24, "symbolic header size", (long) ptr
->f_nsyms
);
746 printf(" %-*s %ld\n", 24, "optional header", (long) ptr
->f_opthdr
);
747 printf(" %-*s 0x%x", 24, "flags", (ushort
) flags
);
749 if ((flags
& F_RELFLG
) != 0)
750 printf (", F_RELFLG");
752 if ((flags
& F_EXEC
) != 0)
755 if ((flags
& F_LNNO
) != 0)
758 if ((flags
& F_LSYMS
) != 0)
759 printf (", F_LSYMS");
761 if ((flags
& F_MINMAL
) != 0)
762 printf (", F_MINMAL");
764 if ((flags
& F_UPDATE
) != 0)
765 printf (", F_UPDATE");
767 if ((flags
& F_SWABD
) != 0)
768 printf (", F_SWABD");
770 if ((flags
& F_AR16WR
) != 0)
771 printf (", F_AR16WR");
773 if ((flags
& F_AR32WR
) != 0)
774 printf (", F_AR32WR");
776 if ((flags
& F_AR32W
) != 0)
777 printf (", F_AR32W");
779 if ((flags
& F_PATCH
) != 0)
780 printf (", F_PATCH/F_NODF");
786 /* Print out the symbolic header. */
789 print_sym_hdr (HDRR
*sym_ptr
)
793 printf("Symbolic header, magic number = 0x%04x, vstamp = %d.%d:\n\n",
794 sym_ptr
->magic
& 0xffff,
795 (sym_ptr
->vstamp
& 0xffff) >> 8,
796 sym_ptr
->vstamp
& 0xff);
798 printf(" %-*s %11s %11s %11s\n", width
, "Info", "Offset", "Number", "Bytes");
799 printf(" %-*s %11s %11s %11s\n", width
, "====", "======", "======", "=====\n");
801 printf(" %-*s %11ld %11ld %11ld [%d]\n", width
, "Line numbers",
802 (long) sym_ptr
->cbLineOffset
,
803 (long) sym_ptr
->cbLine
,
804 (long) sym_ptr
->cbLine
,
805 (int) sym_ptr
->ilineMax
);
807 printf(" %-*s %11ld %11ld %11ld\n", width
, "Dense numbers",
808 (long) sym_ptr
->cbDnOffset
,
809 (long) sym_ptr
->idnMax
,
810 (long) (sym_ptr
->idnMax
* sizeof (DNR
)));
812 printf(" %-*s %11ld %11ld %11ld\n", width
, "Procedures Tables",
813 (long) sym_ptr
->cbPdOffset
,
814 (long) sym_ptr
->ipdMax
,
815 (long) (sym_ptr
->ipdMax
* sizeof (PDR
)));
817 printf(" %-*s %11ld %11ld %11ld\n", width
, "Local Symbols",
818 (long) sym_ptr
->cbSymOffset
,
819 (long) sym_ptr
->isymMax
,
820 (long) (sym_ptr
->isymMax
* sizeof (SYMR
)));
822 printf(" %-*s %11ld %11ld %11ld\n", width
, "Optimization Symbols",
823 (long) sym_ptr
->cbOptOffset
,
824 (long) sym_ptr
->ioptMax
,
825 (long) (sym_ptr
->ioptMax
* sizeof (OPTR
)));
827 printf(" %-*s %11ld %11ld %11ld\n", width
, "Auxiliary Symbols",
828 (long) sym_ptr
->cbAuxOffset
,
829 (long) sym_ptr
->iauxMax
,
830 (long) (sym_ptr
->iauxMax
* sizeof (AUXU
)));
832 printf(" %-*s %11ld %11ld %11ld\n", width
, "Local Strings",
833 (long) sym_ptr
->cbSsOffset
,
834 (long) sym_ptr
->issMax
,
835 (long) sym_ptr
->issMax
);
837 printf(" %-*s %11ld %11ld %11ld\n", width
, "External Strings",
838 (long) sym_ptr
->cbSsExtOffset
,
839 (long) sym_ptr
->issExtMax
,
840 (long) sym_ptr
->issExtMax
);
842 printf(" %-*s %11ld %11ld %11ld\n", width
, "File Tables",
843 (long) sym_ptr
->cbFdOffset
,
844 (long) sym_ptr
->ifdMax
,
845 (long) (sym_ptr
->ifdMax
* sizeof (FDR
)));
847 printf(" %-*s %11ld %11ld %11ld\n", width
, "Relative Files",
848 (long) sym_ptr
->cbRfdOffset
,
849 (long) sym_ptr
->crfd
,
850 (long) (sym_ptr
->crfd
* sizeof (ulong
)));
852 printf(" %-*s %11ld %11ld %11ld\n", width
, "External Symbols",
853 (long) sym_ptr
->cbExtOffset
,
854 (long) sym_ptr
->iextMax
,
855 (long) (sym_ptr
->iextMax
* sizeof (EXTR
)));
859 /* Print out a symbol. */
862 print_symbol (SYMR
*sym_ptr
, int number
, const char *strbase
, AUXU
*aux_base
,
865 sc_t storage_class
= (sc_t
) sym_ptr
->sc
;
866 st_t symbol_type
= (st_t
) sym_ptr
->st
;
867 ulong index
= sym_ptr
->index
;
868 char *used_ptr
= aux_used
+ (aux_base
- aux_symbols
);
871 printf ("\n Symbol# %d: \"%s\"\n", number
, sym_ptr
->iss
+ strbase
);
873 if (aux_base
!= (AUXU
*) 0 && index
!= indexNil
)
882 printf (" End+1 symbol: %ld\n", index
);
885 if (free_scope
== (scope_t
*) 0)
886 scope_ptr
= (scope_t
*) xmalloc (sizeof (scope_t
));
889 scope_ptr
= free_scope
;
890 free_scope
= scope_ptr
->prev
;
892 scope_ptr
->open_sym
= number
;
893 scope_ptr
->st
= symbol_type
;
894 scope_ptr
->sc
= storage_class
;
895 scope_ptr
->prev
= cur_scope
;
896 cur_scope
= scope_ptr
;
901 if (storage_class
== sc_Text
|| storage_class
== sc_Info
)
902 printf (" First symbol: %ld\n", index
);
906 printf (" First symbol: %ld\n", (long) aux_base
[index
].isym
);
911 if (cur_scope
== (scope_t
*) 0)
912 printf (" Can't pop end scope\n");
915 scope_ptr
= cur_scope
;
916 cur_scope
= scope_ptr
->prev
;
917 scope_ptr
->prev
= free_scope
;
918 free_scope
= scope_ptr
;
925 if (MIPS_IS_STAB(sym_ptr
))
927 else if (ifd
== -1) /* local symbol */
929 used_ptr
[index
] = used_ptr
[index
+1] = 1;
930 printf (" End+1 symbol: %-7ld Type: %s\n",
931 (long) aux_base
[index
].isym
,
932 type_to_string (aux_base
, index
+1, fdp
));
934 else /* global symbol */
935 printf (" Local symbol: %ld\n", index
);
939 if (free_scope
== (scope_t
*) 0)
940 scope_ptr
= (scope_t
*) xmalloc (sizeof (scope_t
));
943 scope_ptr
= free_scope
;
944 free_scope
= scope_ptr
->prev
;
946 scope_ptr
->open_sym
= number
;
947 scope_ptr
->st
= symbol_type
;
948 scope_ptr
->sc
= storage_class
;
949 scope_ptr
->prev
= cur_scope
;
950 cur_scope
= scope_ptr
;
958 printf (" End+1 symbol: %lu\n", index
);
963 if (!MIPS_IS_STAB (sym_ptr
))
966 printf (" Type: %s\n",
967 type_to_string (aux_base
, index
, fdp
));
974 printf (" Scopes: ");
975 if (cur_scope
== (scope_t
*) 0)
979 for (scope_ptr
= cur_scope
;
980 scope_ptr
!= (scope_t
*) 0;
981 scope_ptr
= scope_ptr
->prev
)
984 if (scope_ptr
->st
== st_Proc
|| scope_ptr
->st
== st_StaticProc
)
986 else if (scope_ptr
->st
== st_File
)
988 else if (scope_ptr
->st
== st_Block
&& scope_ptr
->sc
== sc_Text
)
990 else if (scope_ptr
->st
== st_Block
&& scope_ptr
->sc
== sc_Info
)
995 printf (" %ld [%s]", scope_ptr
->open_sym
, sclass
);
1001 printf (" Value: %-13ld ",
1002 (long)sym_ptr
->value
);
1004 printf ("String index: %ld\n", (long)sym_ptr
->iss
);
1006 printf ("String index: %-11ld Ifd: %d\n",
1007 (long)sym_ptr
->iss
, ifd
);
1009 printf (" Symbol type: %-11sStorage class: %-11s",
1010 st_to_string (symbol_type
), sc_to_string (storage_class
));
1012 if (MIPS_IS_STAB(sym_ptr
))
1014 int i
= ARRAY_SIZE (stab_names
);
1015 const char *stab_name
= "stab";
1016 short code
= MIPS_UNMARK_STAB(sym_ptr
->index
);
1019 if (stab_names
[i
].code
== code
)
1021 stab_name
= stab_names
[i
].string
;
1024 printf ("Index: 0x%lx (%s)\n", (long)sym_ptr
->index
, stab_name
);
1026 else if (sym_ptr
->st
== stLabel
&& sym_ptr
->index
!= indexNil
)
1027 printf ("Index: %ld (line#)\n", (long)sym_ptr
->index
);
1029 printf ("Index: %ld\n", (long)sym_ptr
->index
);
1034 /* Print out a word from the aux. table in various formats. */
1037 print_aux (AUXU u
, int auxi
, int used
)
1039 printf ("\t%s#%-5d %11ld, [%4ld/%7ld], [%2d %1d:%1d %1x:%1x:%1x:%1x:%1x:%1x]\n",
1040 (used
) ? " " : "* ",
1044 (long) u
.rndx
.index
,
1057 /* Write aggregate information to a string. */
1060 emit_aggregate (char *string
, AUXU u
, AUXU u2
, const char *which
, FDR
*fdp
)
1062 unsigned int ifd
= u
.rndx
.rfd
;
1063 unsigned int index
= u
.rndx
.index
;
1066 if (ifd
== ST_RFDESCAPE
)
1069 /* An ifd of -1 is an opaque type. An escaped index of 0 is a
1070 struct return type of a procedure compiled without -g. */
1071 if (ifd
== 0xffffffff
1072 || (u
.rndx
.rfd
== ST_RFDESCAPE
&& index
== 0))
1073 name
= "<undefined>";
1074 else if (index
== indexNil
)
1078 if (fdp
== 0 || sym_hdr
.crfd
== 0)
1079 fdp
= &file_desc
[ifd
];
1081 fdp
= &file_desc
[rfile_desc
[fdp
->rfdBase
+ ifd
]];
1082 name
= &l_strings
[fdp
->issBase
+ l_symbols
[index
+ fdp
->isymBase
].iss
];
1086 "%s %s { ifd = %u, index = %u }",
1087 which
, name
, ifd
, index
);
1091 /* Print out information about a file descriptor, and the symbols,
1092 procedures, and line numbers within it. */
1095 print_file_desc (FDR
*fdp
, int number
)
1103 str_base
= l_strings
+ fdp
->issBase
;
1104 aux_base
= aux_symbols
+ fdp
->iauxBase
;
1105 used_base
= aux_used
+ (aux_base
- aux_symbols
);
1107 printf ("\nFile #%d, \"%s\"\n\n",
1109 fdp
->rss
!= issNil
? str_base
+ fdp
->rss
: "<unknown>");
1111 printf (" Name index = %-10ld Readin = %s\n",
1112 (long) fdp
->rss
, (fdp
->fReadin
) ? "Yes" : "No");
1114 printf (" Merge = %-10s Endian = %s\n",
1115 (fdp
->fMerge
) ? "Yes" : "No",
1116 (fdp
->fBigendian
) ? "BIG" : "LITTLE");
1118 printf (" Debug level = %-10s Language = %s\n",
1119 glevel_to_string ((glevel_t
) fdp
->glevel
),
1120 lang_to_string((lang_t
) fdp
->lang
));
1122 printf (" Adr = 0x%08lx\n\n", (long) fdp
->adr
);
1124 printf(" %-*s %11s %11s %11s %11s\n", width
, "Info", "Start", "Number", "Size", "Offset");
1125 printf(" %-*s %11s %11s %11s %11s\n", width
, "====", "=====", "======", "====", "======");
1127 printf(" %-*s %11lu %11lu %11lu %11lu\n",
1128 width
, "Local strings",
1129 (ulong
) fdp
->issBase
,
1132 (ulong
) (fdp
->issBase
+ sym_hdr
.cbSsOffset
));
1134 printf(" %-*s %11lu %11lu %11lu %11lu\n",
1135 width
, "Local symbols",
1136 (ulong
) fdp
->isymBase
,
1138 (ulong
) (fdp
->csym
* sizeof (SYMR
)),
1139 (ulong
) (fdp
->isymBase
* sizeof (SYMR
) + sym_hdr
.cbSymOffset
));
1141 printf(" %-*s %11lu %11lu %11lu %11lu\n",
1142 width
, "Line numbers",
1143 (ulong
) fdp
->cbLineOffset
,
1145 (ulong
) fdp
->cbLine
,
1146 (ulong
) (fdp
->cbLineOffset
+ sym_hdr
.cbLineOffset
));
1148 printf(" %-*s %11lu %11lu %11lu %11lu\n",
1149 width
, "Optimization symbols",
1150 (ulong
) fdp
->ioptBase
,
1152 (ulong
) (fdp
->copt
* sizeof (OPTR
)),
1153 (ulong
) (fdp
->ioptBase
* sizeof (OPTR
) + sym_hdr
.cbOptOffset
));
1155 printf(" %-*s %11lu %11lu %11lu %11lu\n",
1156 width
, "Procedures",
1157 (ulong
) fdp
->ipdFirst
,
1159 (ulong
) (fdp
->cpd
* sizeof (PDR
)),
1160 (ulong
) (fdp
->ipdFirst
* sizeof (PDR
) + sym_hdr
.cbPdOffset
));
1162 printf(" %-*s %11lu %11lu %11lu %11lu\n",
1163 width
, "Auxiliary symbols",
1164 (ulong
) fdp
->iauxBase
,
1166 (ulong
) (fdp
->caux
* sizeof (AUXU
)),
1167 (ulong
) (fdp
->iauxBase
* sizeof(AUXU
) + sym_hdr
.cbAuxOffset
));
1169 printf(" %-*s %11lu %11lu %11lu %11lu\n",
1170 width
, "Relative Files",
1171 (ulong
) fdp
->rfdBase
,
1173 (ulong
) (fdp
->crfd
* sizeof (ulong
)),
1174 (ulong
) (fdp
->rfdBase
* sizeof(ulong
) + sym_hdr
.cbRfdOffset
));
1177 if (want_scope
&& cur_scope
!= (scope_t
*) 0)
1178 printf ("\n Warning scope does not start at 0!\n");
1181 * print the info about the symbol table.
1183 printf ("\n There are %lu local symbols, starting at %lu\n",
1185 (ulong
) (fdp
->isymBase
+ sym_hdr
.cbSymOffset
));
1187 for(symi
= fdp
->isymBase
; symi
< (fdp
->csym
+ fdp
->isymBase
); symi
++)
1188 print_symbol (&l_symbols
[symi
],
1189 symi
- fdp
->isymBase
,
1195 if (want_scope
&& cur_scope
!= (scope_t
*) 0)
1196 printf ("\n Warning scope does not end at 0!\n");
1199 * print the aux. table if desired.
1202 if (want_aux
&& fdp
->caux
!= 0)
1206 printf ("\n There are %lu auxiliary table entries, starting at %lu.\n\n",
1208 (ulong
) (fdp
->iauxBase
+ sym_hdr
.cbAuxOffset
));
1210 for (auxi
= fdp
->iauxBase
; auxi
< (fdp
->caux
+ fdp
->iauxBase
); auxi
++)
1211 print_aux (aux_base
[auxi
], auxi
, used_base
[auxi
]);
1215 * print the relative file descriptors.
1217 if (want_rfd
&& fdp
->crfd
!= 0)
1221 printf ("\n There are %lu relative file descriptors, starting at %lu.\n",
1223 (ulong
) fdp
->rfdBase
);
1225 rfd_ptr
= rfile_desc
+ fdp
->rfdBase
;
1226 for (i
= 0; i
< (ulong
) fdp
->crfd
; i
++)
1228 printf ("\t#%-5ld %11ld, 0x%08lx\n", i
, *rfd_ptr
, *rfd_ptr
);
1234 * do the procedure descriptors.
1236 printf ("\n There are %lu procedure descriptor entries, ", (ulong
) fdp
->cpd
);
1237 printf ("starting at %lu.\n", (ulong
) fdp
->ipdFirst
);
1239 for (pdi
= fdp
->ipdFirst
; pdi
< (fdp
->cpd
+ fdp
->ipdFirst
); pdi
++)
1241 PDR
*proc_ptr
= &proc_desc
[pdi
];
1242 printf ("\n\tProcedure descriptor %d:\n", (pdi
- fdp
->ipdFirst
));
1245 printf ("\t Name index = %-11ld Name = \"%s\"\n",
1246 (long) l_symbols
[proc_ptr
->isym
+ fdp
->isymBase
].iss
,
1247 l_symbols
[proc_ptr
->isym
+ fdp
->isymBase
].iss
+ str_base
);
1249 printf ("\t .mask 0x%08lx,%-9ld .fmask 0x%08lx,%ld\n",
1250 (long) proc_ptr
->regmask
,
1251 (long) proc_ptr
->regoffset
,
1252 (long) proc_ptr
->fregmask
,
1253 (long) proc_ptr
->fregoffset
);
1255 printf ("\t .frame $%d,%ld,$%d\n",
1256 (int) proc_ptr
->framereg
,
1257 (long) proc_ptr
->frameoffset
,
1258 (int) proc_ptr
->pcreg
);
1260 printf ("\t Opt. start = %-11ld Symbols start = %ld\n",
1261 (long) proc_ptr
->iopt
,
1262 (long) proc_ptr
->isym
);
1264 printf ("\t First line # = %-11ld Last line # = %ld\n",
1265 (long) proc_ptr
->lnLow
,
1266 (long) proc_ptr
->lnHigh
);
1268 printf ("\t Line Offset = %-11ld Address = 0x%08lx\n",
1269 (long) proc_ptr
->cbLineOffset
,
1270 (long) proc_ptr
->adr
);
1273 * print the line number entries.
1276 if (want_line
&& fdp
->cline
!= 0)
1279 long cur_line
= proc_ptr
->lnLow
;
1280 uchar
*line_ptr
= (((uchar
*)lines
) + proc_ptr
->cbLineOffset
1281 + fdp
->cbLineOffset
);
1284 if (pdi
== fdp
->cpd
+ fdp
->ipdFirst
- 1) /* last procedure */
1285 line_end
= ((uchar
*)lines
) + fdp
->cbLine
+ fdp
->cbLineOffset
;
1286 else /* not last proc. */
1287 line_end
= (((uchar
*)lines
) + proc_desc
[pdi
+1].cbLineOffset
1288 + fdp
->cbLineOffset
);
1290 printf ("\n\tThere are %lu bytes holding line numbers, starting at %lu.\n",
1291 (ulong
) (line_end
- line_ptr
),
1292 (ulong
) (fdp
->ilineBase
+ sym_hdr
.cbLineOffset
));
1294 while (line_ptr
< line_end
)
1295 { /* sign extend nibble */
1296 delta
= ((*line_ptr
>> 4) ^ 0x8) - 0x8;
1297 count
= (*line_ptr
& 0xf) + 1;
1302 delta
= (((line_ptr
[1]) & 0xff) << 8) + ((line_ptr
[2]) & 0xff);
1303 delta
= (delta
^ 0x8000) - 0x8000;
1308 printf ("\t Line %11ld, delta %5d, count %2d\n",
1318 /* Read in the portions of the .T file that we will print out. */
1324 off_t sym_hdr_offset
= 0;
1326 read_seek (&magic
, sizeof (magic
), 0, "Magic number");
1329 /* Print out the global header, since this is not a T-file. */
1331 read_seek (&global_hdr
, sizeof (global_hdr
), 0, "Global file header");
1333 print_global_hdr (&global_hdr
);
1335 if (global_hdr
.f_symptr
== 0)
1337 printf ("No symbolic header, Goodbye!\n");
1341 sym_hdr_offset
= global_hdr
.f_symptr
;
1344 read_seek (&sym_hdr
, sizeof (sym_hdr
), sym_hdr_offset
, "Symbolic header");
1346 print_sym_hdr (&sym_hdr
);
1348 lines
= (LINER
*) read_seek (NULL
, sym_hdr
.cbLine
, sym_hdr
.cbLineOffset
,
1351 dense_nums
= (DNR
*) read_seek (NULL
, sym_hdr
.idnMax
* sizeof (DNR
),
1352 sym_hdr
.cbDnOffset
, "Dense numbers");
1354 proc_desc
= (PDR
*) read_seek (NULL
, sym_hdr
.ipdMax
* sizeof (PDR
),
1355 sym_hdr
.cbPdOffset
, "Procedure tables");
1357 l_symbols
= (SYMR
*) read_seek (NULL
, sym_hdr
.isymMax
* sizeof (SYMR
),
1358 sym_hdr
.cbSymOffset
, "Local symbols");
1360 opt_symbols
= (OPTR
*) read_seek (NULL
, sym_hdr
.ioptMax
* sizeof (OPTR
),
1361 sym_hdr
.cbOptOffset
,
1362 "Optimization symbols");
1364 aux_symbols
= (AUXU
*) read_seek (NULL
, sym_hdr
.iauxMax
* sizeof (AUXU
),
1365 sym_hdr
.cbAuxOffset
, "Auxiliary symbols");
1367 if (sym_hdr
.iauxMax
> 0)
1368 aux_used
= (char *) xcalloc (sym_hdr
.iauxMax
, 1);
1370 l_strings
= (char *) read_seek (NULL
, sym_hdr
.issMax
,
1371 sym_hdr
.cbSsOffset
, "Local string table");
1373 e_strings
= (char *) read_seek (NULL
, sym_hdr
.issExtMax
,
1374 sym_hdr
.cbSsExtOffset
,
1375 "External string table");
1377 file_desc
= (FDR
*) read_seek (NULL
, sym_hdr
.ifdMax
* sizeof (FDR
),
1378 sym_hdr
.cbFdOffset
, "File tables");
1380 rfile_desc
= (ulong
*) read_seek (NULL
, sym_hdr
.crfd
* sizeof (ulong
),
1381 sym_hdr
.cbRfdOffset
,
1382 "Relative file tables");
1384 e_symbols
= (EXTR
*) read_seek (NULL
, sym_hdr
.iextMax
* sizeof (EXTR
),
1385 sym_hdr
.cbExtOffset
, "External symbols");
1390 extern int main (int, char **);
1393 main (int argc
, char **argv
)
1400 while ((opt
= getopt_long (argc
, argv
, "alrsvt", options
, NULL
)) != -1)
1403 default: errors
++; break;
1404 case 'a': want_aux
++; break; /* print aux table */
1405 case 'l': want_line
++; break; /* print line numbers */
1406 case 'r': want_rfd
++; break; /* print relative fd's */
1407 case 's': want_scope
++; break; /* print scope info */
1408 case 'v': verbose
++; break; /* print version # */
1409 case 'V': version
++; break; /* print version # */
1410 case 't': tfile
++; break; /* this is a tfile (without header),
1416 printf ("mips-tdump %s%s\n", pkgversion_string
, version_string
);
1417 fputs ("Copyright (C) 2009 Free Software Foundation, Inc.\n", stdout
);
1418 fputs ("This is free software; see the source for copying conditions. There is NO\n\
1419 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n",
1424 if (optind
!= argc
- 1)
1427 if (verbose
|| errors
)
1429 fprintf (stderr
, "mips-tdump (GCC) %s", version_string
);
1430 #ifdef TARGET_VERSION
1433 fputc ('\n', stderr
);
1438 fprintf (stderr
, "Calling Sequence:\n");
1439 fprintf (stderr
, "\t%s [-alrst] <object-or-T-file>\n", argv
[0]);
1440 fprintf (stderr
, "\n");
1441 fprintf (stderr
, "switches:\n");
1442 fprintf (stderr
, "\t-a Print out auxiliary table.\n");
1443 fprintf (stderr
, "\t-l Print out line numbers.\n");
1444 fprintf (stderr
, "\t-r Print out relative file descriptors.\n");
1445 fprintf (stderr
, "\t-s Print out the current scopes for an item.\n");
1446 fprintf (stderr
, "\t-t Assume there is no global header (ie, a T-file).\n");
1447 fprintf (stderr
, "\t-v Print program version.\n");
1452 * Open and process the input file.
1454 tfile_fd
= open (argv
[optind
], O_RDONLY
);
1457 perror (argv
[optind
]);
1464 * Print any global aux words if any.
1468 long last_aux_in_use
;
1470 if (sym_hdr
.ifdMax
!= 0 && file_desc
[0].iauxBase
!= 0)
1472 printf ("\nGlobal auxiliary entries before first file:\n");
1473 for (i
= 0; i
< file_desc
[0].iauxBase
; i
++)
1474 print_aux (aux_symbols
[i
], 0, aux_used
[i
]);
1477 if (sym_hdr
.ifdMax
== 0)
1478 last_aux_in_use
= 0;
1481 = (file_desc
[sym_hdr
.ifdMax
-1].iauxBase
1482 + file_desc
[sym_hdr
.ifdMax
-1].caux
- 1);
1484 if (last_aux_in_use
< sym_hdr
.iauxMax
-1)
1486 printf ("\nGlobal auxiliary entries after last file:\n");
1487 for (i
= last_aux_in_use
; i
< sym_hdr
.iauxMax
; i
++)
1488 print_aux (aux_symbols
[i
], i
- last_aux_in_use
, aux_used
[i
]);
1493 * Print the information for each file.
1495 for (i
= 0; i
< sym_hdr
.ifdMax
; i
++)
1496 print_file_desc (&file_desc
[i
], i
);
1499 * Print the external symbols.
1501 want_scope
= 0; /* scope info is meaning for extern symbols */
1502 printf ("\nThere are %lu external symbols, starting at %lu\n",
1503 (ulong
) sym_hdr
.iextMax
,
1504 (ulong
) sym_hdr
.cbExtOffset
);
1506 for(i
= 0; i
< sym_hdr
.iextMax
; i
++)
1507 print_symbol (&e_symbols
[i
].asym
, i
, e_strings
,
1508 aux_symbols
+ file_desc
[e_symbols
[i
].ifd
].iauxBase
,
1510 &file_desc
[e_symbols
[i
].ifd
]);
1513 * Print unused aux symbols now.
1520 for (i
= 0; i
< sym_hdr
.iauxMax
; i
++)
1526 printf ("\nThe following auxiliary table entries were unused:\n\n");
1530 printf (" #%-5d %11ld 0x%08lx %s\n",
1532 (long) aux_symbols
[i
].isym
,
1533 (long) aux_symbols
[i
].isym
,
1534 type_to_string (aux_symbols
, i
, (FDR
*) 0));