From e506707db06d4be0f30aaddbb27b47f7914aba06 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Thu, 1 Aug 1991 17:26:49 +0000 Subject: [PATCH] Initial revision From-SVN: r31 --- gcc/mips-tfile.c | 4947 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4947 insertions(+) create mode 100644 gcc/mips-tfile.c diff --git a/gcc/mips-tfile.c b/gcc/mips-tfile.c new file mode 100644 index 00000000000..2a23486556b --- /dev/null +++ b/gcc/mips-tfile.c @@ -0,0 +1,4947 @@ +/* Update the symbol table (the .T file) in a MIPS object to + contain debugging information specified by the GNU compiler + in the form of comments (the mips assembler does not support + assembly access to debug information). + Contributed by: Michael Meissner, meissner@osf.org + Copyright (C) 1991 Free Software Foundation, Inc. + +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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Here is a brief description of the MIPS ECOFF symbol table. The + MIPS symbol table has the following pieces: + + Symbolic Header + | + +-- Auxiliary Symbols + | + +-- Dense number table + | + +-- Optimizer Symbols + | + +-- External Strings + | + +-- External Symbols + | + +-- Relative file descriptors + | + +-- File table + | + +-- Procedure table + | + +-- Line number table + | + +-- Local Strings + | + +-- Local Symbols + + The symbolic header points to each of the other tables, and also + contains the number of entries. It also contains a magic number + and MIPS compiler version number, such as 2.0. + + The auxiliary table is a series of 32 bit integers, that are + referenced as needed from the local symbol table. Unlike standard + COFF, the aux. information does not follow the symbol that uses + it, but rather is a separate table. In theory, this would allow + the MIPS compilers to collapse duplicate aux. entries, but I've not + noticed this happening with the 1.31 compiler suite. The different + types of aux. entries are: + + 1) dnLow: Low bound on array dimension. + + 2) dnHigh: High bound on array dimension. + + 3) isym: Index to the local symbol which is the start of the + function for the end of function first aux. entry. + + 4) width: Width of structures and bitfields. + + 5) count: Count of ranges for variant part. + + 6) rndx: A relative index into the symbol table. The relative + index field has two parts: rfd which is a pointer into the + relative file index table or ST_RFDESCAPE which says the next + aux. entry is the file number, and index: which is the pointer + into the local symbol within a given file table. This is for + things like references to types defined in another file. + + 7) Type information: This is like the COFF type bits, except it + is 32 bits instead of 16; they still have room to add new + basic types; and they can handle more than 6 levels of array, + pointer, function, etc. Each type information field contains + the following structure members: + + a) fBitfield: a bit that says this is a bitfield, and the + size in bits follows as the next aux. entry. + + b) continued: a bit that says the next aux. entry is a + continuation of the current type information (in case + there are more than 6 levels of array/ptr/function). + + c) bt: an integer containing the base type before adding + array, pointer, function, etc. qualifiers. The + current base types that I have documentation for are: + + btNil -- undefined + btAdr -- address - integer same size as ptr + btChar -- character + btUChar -- unsigned character + btShort -- short + btUShort -- unsigned short + btInt -- int + btUInt -- unsigned int + btLong -- long + btULong -- unsigned long + btFloat -- float (real) + btDouble -- Double (real) + btStruct -- Structure (Record) + btUnion -- Union (variant) + btEnum -- Enumerated + btTypedef -- defined via a typedef isymRef + btRange -- subrange of int + btSet -- pascal sets + btComplex -- fortran complex + btDComplex -- fortran double complex + btIndirect -- forward or unnamed typedef + btFixedDec -- Fixed Decimal + btFloatDec -- Float Decimal + btString -- Varying Length Character String + btBit -- Aligned Bit String + btPicture -- Picture + btVoid -- Void (MIPS cc revision >= 2.00) + + d) tq0 - tq5: type qualifier fields as needed. The + current type qualifier fields I have documentation for + are: + + tqNil -- no more qualifiers + tqPtr -- pointer + tqProc -- procedure + tqArray -- array + tqFar -- 8086 far pointers + tqVol -- volatile + + + The dense number table is used in the front ends, and disappears by + the time the .o is created. + + With the 1.31 compiler suite, the optimization symbols don't seem + to be used as far as I can tell. + + The linker is the first entity that creates the relative file + descriptor table, and I believe it is used so that the individual + file table pointers don't have to be rewritten when the objects are + merged together into the program file. + + Unlike COFF, the basic symbol & string tables are split into + external and local symbols/strings. The relocation information + only goes off of the external symbol table, and the debug + information only goes off of the internal symbol table. The + external symbols can have links to an appropriate file index and + symbol within the file to give it the appropriate type information. + Because of this, the external symbols are actually larger than the + internal symbols (to contain the link information), and contain the + local symbol structure as a member, though this member is not the + first member of the external symbol structure (!). I suspect this + split is to make strip easier to deal with. + + Each file table has offsets for where the line numbers, local + strings, local symbols, and procedure table starts from within the + global tables, and the indexs are reset to 0 for each of those + tables for the file. + + The procedure table contains the binary equivalents of the .ent + (start of the function address), .frame (what register is the + virtual frame pointer, constant offset from the register to obtain + the VFP, and what register holds the return address), .mask/.fmask + (bitmask of saved registers, and where the first register is stored + relative to the VFP) assembler directives. It also contains the + low and high bounds of the line numbers if debugging is turned on. + + The line number table is a compressed form of the normal COFF line + table. Each line number entry is either 1 or 3 bytes long, and + contains a signed delta from the previous line, and an unsigned + count of the number of instructions this statement takes. + + The local symbol table contains the following fields: + + 1) iss: index to the local string table giving the name of the + symbol. + + 2) value: value of the symbol (address, register number, etc.). + + 3) st: symbol type. The current symbol types are: + + stNil -- Nuthin' special + stGlobal -- external symbol + stStatic -- static + stParam -- procedure argument + stLocal -- local variable + stLabel -- label + stProc -- External Procedure + stBlock -- beginnning of block + stEnd -- end (of anything) + stMember -- member (of anything) + stTypedef -- type definition + stFile -- file name + stRegReloc -- register relocation + stForward -- forwarding address + stStaticProc -- Static procedure + stConstant -- const + + 4) sc: storage class. The current storage classes are: + + scText -- text symbol + scData -- initialized data symbol + scBss -- un-initialized data symbol + scRegister -- value of symbol is register number + scAbs -- value of symbol is absolute + scUndefined -- who knows? + scCdbLocal -- variable's value is IN se->va.?? + scBits -- this is a bit field + scCdbSystem -- value is IN debugger's address space + scRegImage -- register value saved on stack + scInfo -- symbol contains debugger information + scUserStruct -- addr in struct user for current process + scSData -- load time only small data + scSBss -- load time only small common + scRData -- load time only read only data + scVar -- Var parameter (fortranpascal) + scCommon -- common variable + scSCommon -- small common + scVarRegister -- Var parameter in a register + scVariant -- Variant record + scSUndefined -- small undefined(external) data + scInit -- .init section symbol + + 5) index: pointer to a local symbol or aux. entry. + + + + For the following program: + + #include + + main(){ + printf("Hello World!\n"); + return 0; + } + + Mips-tdump produces the following information: + + Global file header: + magic number 0x162 + # sections 2 + timestamp 645311799, Wed Jun 13 17:16:39 1990 + symbolic header offset 284 + symbolic header size 96 + optional header 56 + flags 0x0 + + Symbolic header, magic number = 0x7009, vstamp = 1.31: + + Info Offset Number Bytes + ==== ====== ====== ===== + + Line numbers 380 4 4 [13] + Dense numbers 0 0 0 + Procedures Tables 384 1 52 + Local Symbols 436 16 192 + Optimization Symbols 0 0 0 + Auxilary Symbols 628 39 156 + Local Strings 784 80 80 + External Strings 864 144 144 + File Tables 1008 2 144 + Relative Files 0 0 0 + External Symbols 1152 20 320 + + File #0, "hello2.c" + + Name index = 1 Readin = No + Merge = No Endian = LITTLE + Debug level = G2 Language = C + Adr = 0x00000000 + + Info Start Number Size Offset + ==== ===== ====== ==== ====== + Local strings 0 15 15 784 + Local symbols 0 6 72 436 + Line numbers 0 13 13 380 + Optimization symbols 0 0 0 0 + Procedures 0 1 52 384 + Auxiliary symbols 0 14 56 628 + Relative Files 0 0 0 0 + + There are 6 local symbols, starting at 436 + + Symbol# 0: "hello2.c" + End+1 symbol = 6 + String index = 1 + Storage class = Text Index = 6 + Symbol type = File Value = 0 + + Symbol# 1: "main" + End+1 symbol = 5 + Type = int + String index = 10 + Storage class = Text Index = 12 + Symbol type = Proc Value = 0 + + Symbol# 2: "" + End+1 symbol = 4 + String index = 0 + Storage class = Text Index = 4 + Symbol type = Block Value = 8 + + Symbol# 3: "" + First symbol = 2 + String index = 0 + Storage class = Text Index = 2 + Symbol type = End Value = 28 + + Symbol# 4: "main" + First symbol = 1 + String index = 10 + Storage class = Text Index = 1 + Symbol type = End Value = 52 + + Symbol# 5: "hello2.c" + First symbol = 0 + String index = 1 + Storage class = Text Index = 0 + Symbol type = End Value = 0 + + There are 14 auxiliary table entries, starting at 628. + + * #0 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #1 24, [ 24/ 0], [ 6 0:0 0:0:0:0:0:0] + * #2 8, [ 8/ 0], [ 2 0:0 0:0:0:0:0:0] + * #3 16, [ 16/ 0], [ 4 0:0 0:0:0:0:0:0] + * #4 24, [ 24/ 0], [ 6 0:0 0:0:0:0:0:0] + * #5 32, [ 32/ 0], [ 8 0:0 0:0:0:0:0:0] + * #6 40, [ 40/ 0], [10 0:0 0:0:0:0:0:0] + * #7 44, [ 44/ 0], [11 0:0 0:0:0:0:0:0] + * #8 12, [ 12/ 0], [ 3 0:0 0:0:0:0:0:0] + * #9 20, [ 20/ 0], [ 5 0:0 0:0:0:0:0:0] + * #10 28, [ 28/ 0], [ 7 0:0 0:0:0:0:0:0] + * #11 36, [ 36/ 0], [ 9 0:0 0:0:0:0:0:0] + #12 5, [ 5/ 0], [ 1 1:0 0:0:0:0:0:0] + #13 24, [ 24/ 0], [ 6 0:0 0:0:0:0:0:0] + + There are 1 procedure descriptor entries, starting at 0. + + Procedure descriptor 0: + Name index = 10 Name = "main" + .mask 0x80000000,-4 .fmask 0x00000000,0 + .frame $29,24,$31 + Opt. start = -1 Symbols start = 1 + First line # = 3 Last line # = 6 + Line Offset = 0 Address = 0x00000000 + + There are 4 bytes holding line numbers, starting at 380. + Line 3, delta 0, count 2 + Line 4, delta 1, count 3 + Line 5, delta 1, count 2 + Line 6, delta 1, count 6 + + File #1, "/usr/include/stdio.h" + + Name index = 1 Readin = No + Merge = Yes Endian = LITTLE + Debug level = G2 Language = C + Adr = 0x00000000 + + Info Start Number Size Offset + ==== ===== ====== ==== ====== + Local strings 15 65 65 799 + Local symbols 6 10 120 508 + Line numbers 0 0 0 380 + Optimization symbols 0 0 0 0 + Procedures 1 0 0 436 + Auxiliary symbols 14 25 100 684 + Relative Files 0 0 0 0 + + There are 10 local symbols, starting at 442 + + Symbol# 0: "/usr/include/stdio.h" + End+1 symbol = 10 + String index = 1 + Storage class = Text Index = 10 + Symbol type = File Value = 0 + + Symbol# 1: "_iobuf" + End+1 symbol = 9 + String index = 22 + Storage class = Info Index = 9 + Symbol type = Block Value = 20 + + Symbol# 2: "_cnt" + Type = int + String index = 29 + Storage class = Info Index = 4 + Symbol type = Member Value = 0 + + Symbol# 3: "_ptr" + Type = ptr to char + String index = 34 + Storage class = Info Index = 15 + Symbol type = Member Value = 32 + + Symbol# 4: "_base" + Type = ptr to char + String index = 39 + Storage class = Info Index = 16 + Symbol type = Member Value = 64 + + Symbol# 5: "_bufsiz" + Type = int + String index = 45 + Storage class = Info Index = 4 + Symbol type = Member Value = 96 + + Symbol# 6: "_flag" + Type = short + String index = 53 + Storage class = Info Index = 3 + Symbol type = Member Value = 128 + + Symbol# 7: "_file" + Type = char + String index = 59 + Storage class = Info Index = 2 + Symbol type = Member Value = 144 + + Symbol# 8: "" + First symbol = 1 + String index = 0 + Storage class = Info Index = 1 + Symbol type = End Value = 0 + + Symbol# 9: "/usr/include/stdio.h" + First symbol = 0 + String index = 1 + Storage class = Text Index = 0 + Symbol type = End Value = 0 + + There are 25 auxiliary table entries, starting at 642. + + * #14 -1, [4095/1048575], [63 1:1 f:f:f:f:f:f] + #15 65544, [ 8/ 16], [ 2 0:0 1:0:0:0:0:0] + #16 65544, [ 8/ 16], [ 2 0:0 1:0:0:0:0:0] + * #17 196656, [ 48/ 48], [12 0:0 3:0:0:0:0:0] + * #18 8191, [4095/ 1], [63 1:1 0:0:0:0:f:1] + * #19 1, [ 1/ 0], [ 0 1:0 0:0:0:0:0:0] + * #20 20479, [4095/ 4], [63 1:1 0:0:0:0:f:4] + * #21 1, [ 1/ 0], [ 0 1:0 0:0:0:0:0:0] + * #22 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #23 2, [ 2/ 0], [ 0 0:1 0:0:0:0:0:0] + * #24 160, [ 160/ 0], [40 0:0 0:0:0:0:0:0] + * #25 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #26 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #27 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #28 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #29 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #30 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #31 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #32 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #33 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #34 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #35 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #36 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #37 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #38 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + + There are 0 procedure descriptor entries, starting at 1. + + There are 20 external symbols, starting at 1152 + + Symbol# 0: "_iob" + Type = array [3 {160}] of struct _iobuf { ifd = 1, index = 1 } + String index = 0 Ifd = 1 + Storage class = Nil Index = 17 + Symbol type = Global Value = 60 + + Symbol# 1: "fopen" + String index = 5 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 2: "fdopen" + String index = 11 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 3: "freopen" + String index = 18 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 4: "popen" + String index = 26 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 5: "tmpfile" + String index = 32 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 6: "ftell" + String index = 40 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 7: "rewind" + String index = 46 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 8: "setbuf" + String index = 53 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 9: "setbuffer" + String index = 60 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 10: "setlinebuf" + String index = 70 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 11: "fgets" + String index = 81 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 12: "gets" + String index = 87 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 13: "ctermid" + String index = 92 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 14: "cuserid" + String index = 100 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 15: "tempnam" + String index = 108 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 16: "tmpnam" + String index = 116 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 17: "sprintf" + String index = 123 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 18: "main" + Type = int + String index = 131 Ifd = 0 + Storage class = Text Index = 1 + Symbol type = Proc Value = 0 + + Symbol# 19: "printf" + String index = 136 Ifd = 0 + Storage class = Undefined Index = 1048575 + Symbol type = Proc Value = 0 + + The following auxiliary table entries were unused: + + #0 0 0x00000000 void + #2 8 0x00000008 char + #3 16 0x00000010 short + #4 24 0x00000018 int + #5 32 0x00000020 long + #6 40 0x00000028 float + #7 44 0x0000002c double + #8 12 0x0000000c unsigned char + #9 20 0x00000014 unsigned short + #10 28 0x0000001c unsigned int + #11 36 0x00000024 unsigned long + #14 0 0x00000000 void + #15 24 0x00000018 int + #19 32 0x00000020 long + #20 40 0x00000028 float + #21 44 0x0000002c double + #22 12 0x0000000c unsigned char + #23 20 0x00000014 unsigned short + #24 28 0x0000001c unsigned int + #25 36 0x00000024 unsigned long + #26 48 0x00000030 struct no name { ifd = -1, index = 1048575 } + +*/ + + +#include +#include "gvarargs.h" +#include "config.h" + +#ifndef __SABER__ +#define saber_stop() +#endif + +#ifndef __LINE__ +#define __LINE__ 0 +#endif + +#ifdef __STDC__ +typedef void *PTR_T; +typedef const void *CPTR_T; +#define __proto(x) x +#else + +#ifdef _STDIO_H_ /* Ultrix 4.0 */ +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 + +/* 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. Ultrix 4.0 and Silicon Graphics + have this fixed, but since the following is correct, and + the fact that including stddef.h gets you GCC's version + instead of the standard one it's not worth it to fix it. */ + +#define Size_t unsigned int +#define Ptrdiff_t int + +/* The following might be called from obstack or malloc, + so they can't be static. */ + +extern void pfatal_with_name + __proto((char *)); +extern void fancy_abort __proto((void)); +extern void botch __proto((const char *)); +extern PTR_T xmalloc __proto((Size_t)); +extern PTR_T xcalloc __proto((Size_t, Size_t)); +extern PTR_T xrealloc __proto((PTR_T, Size_t)); +extern void xfree __proto((PTR_T)); + +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)); + +extern void fatal(); /* can't use prototypes here */ +extern void error(); + + +#ifndef MIPS_DEBUGGING_INFO + +static int line_number; +static int cur_line_start; +static int debug; +static int had_errors; +static char *progname; +static char *input_name; + +int +main () +{ + fprintf (stderr, "Mips-tfile should only be run on a MIPS computer!\n"); + exit (1); +} + +#else /* MIPS_DEBUGGING defined */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef errno +extern int errno; /* MIPS errno.h doesn't declare this */ +#endif + +#ifndef MALLOC_CHECK +#ifdef __SABER__ +#define MALLOC_CHECK +#endif +#endif + +#define IS_ASM_IDENT(ch) \ + (isalnum (ch) || (ch) == '_' || (ch) == '.' || (ch) == '$') + + +/* Redefination of of storage classes as an enumeration for better + debugging. */ + +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, /* 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, /* beginnning 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_Constant = stConstant, /* const */ + 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-coersion 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 */ + +#ifdef btVoid + bt_Void = btVoid, /* Void */ +#else +#define bt_Void bt_Nil +#endif + + bt_Max = btMax /* Max basic type+1 */ +} bt_t; + + + +/* Basic COFF storage classes. */ +enum coff_storage { + C_EFCN = -1, + C_NULL = 0, + C_AUTO = 1, + C_EXT = 2, + C_STAT = 3, + C_REG = 4, + C_EXTDEF = 5, + C_LABEL = 6, + C_ULABEL = 7, + C_MOS = 8, + C_ARG = 9, + C_STRTAG = 10, + C_MOU = 11, + C_UNTAG = 12, + C_TPDEF = 13, + C_USTATIC = 14, + C_ENTAG = 15, + C_MOE = 16, + C_REGPARM = 17, + C_FIELD = 18, + C_BLOCK = 100, + C_FCN = 101, + C_EOS = 102, + C_FILE = 103, + C_LINE = 104, + C_ALIAS = 105, + C_HIDDEN = 106, + C_MAX = 107 +} coff_storage_t; + +/* Regular COFF fundamental type. */ +typedef enum coff_type { + T_NULL = 0, + T_ARG = 1, + T_CHAR = 2, + T_SHORT = 3, + T_INT = 4, + T_LONG = 5, + T_FLOAT = 6, + T_DOUBLE = 7, + T_STRUCT = 8, + T_UNION = 9, + T_ENUM = 10, + T_MOE = 11, + T_UCHAR = 12, + T_USHORT = 13, + T_UINT = 14, + T_ULONG = 15, + T_MAX = 16 +} coff_type_t; + +/* Regular COFF derived types. */ +typedef enum coff_dt { + DT_NON = 0, + DT_PTR = 1, + DT_FCN = 2, + DT_ARY = 3, + DT_MAX = 4 +} coff_dt_t; + +#define N_BTMASK 017 /* bitmask to isolate basic type */ +#define N_TMASK 003 /* bitmask to isolate derived type */ +#define N_BT_SHIFT 4 /* # bits to shift past basic type */ +#define N_TQ_SHIFT 2 /* # bits to shift derived types */ +#define N_TQ 6 /* # of type qualifiers */ + +/* States for whether to hash type or not. */ +typedef enum hash_state { + hash_no = 0, /* don't hash type */ + hash_yes = 1, /* ok to hash type, or use previous hash */ + hash_record = 2 /* ok to record hash, but don't use prev. */ +} hash_state_t; + + +#define WORD_ALIGN(x) (((x) + 3) & ~3) +#define DWORD_ALIGN(x) (((x) + 7) & ~7) + + +/* Structures to provide n-number of virtual arrays, each of which can + grow linearly, and which are written in the object file as sequential + pages. On systems with a BSD malloc that define USE_MALLOC, the + MAX_CLUSTER_PAGES should be 1 less than a power of two, since malloc + adds it's overhead, and rounds up to the next power of 2. Pages are + linked together via a linked list. + + If PAGE_SIZE is > 4096, the string length in the shash_t structure + can't be represented (assuming there are strings > 4096 bytes). */ + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 /* size of varray pages */ +#endif + +#define PAGE_USIZE ((Size_t)PAGE_SIZE) + + +#ifndef MAX_CLUSTER_PAGES /* # pages to get from system */ +#ifndef USE_MALLOC /* in one memory request */ +#define MAX_CLUSTER_PAGES 64 +#else +#define MAX_CLUSTER_PAGES 63 +#endif +#endif + + +/* Linked list connecting separate page allocations. */ +typedef struct vlinks { + struct vlinks *prev; /* previous set of pages */ + struct vlinks *next; /* next set of pages */ + union page *datum; /* start of page */ + unsigned long start_index; /* starting index # of page */ +} vlinks_t; + + +/* Virtual array header. */ +typedef struct varray { + vlinks_t *first; /* first page link */ + vlinks_t *last; /* last page link */ + unsigned long num_allocated; /* # objects allocated */ + unsigned short object_size; /* size in bytes of each object */ + unsigned short objects_per_page; /* # objects that can fit on a page */ + unsigned short objects_last_page; /* # objects allocated on last page */ +} varray_t; + +#ifndef MALLOC_CHECK +#define OBJECTS_PER_PAGE(type) (PAGE_SIZE / sizeof (type)) +#else +#define OBJECTS_PER_PAGE(type) ((sizeof (type) > 1) ? 1 : PAGE_SIZE) +#endif + +#define INIT_VARRAY(type) { /* macro to initialize a varray */ \ + (vlinks_t *)0, /* first */ \ + (vlinks_t *)0, /* last */ \ + 0, /* num_allocated */ \ + sizeof (type), /* object_size */ \ + OBJECTS_PER_PAGE (type), /* objects_per_page */ \ + OBJECTS_PER_PAGE (type), /* objects_last_page */ \ +} + +/* Master type for indexes within the symbol table. */ +typedef unsigned long symint_t; + + +/* Linked list support for nested scopes (file, block, structure, etc.). */ +typedef struct scope { + struct scope *prev; /* previous scope level */ + SYMR *lsym; /* pointer to local symbol node */ + symint_t lnumber; /* lsym index */ + st_t type; /* type of the node */ +} scope_t; + + +/* Forward reference list for tags referenced, but not yet defined. */ +typedef struct forward { + struct forward *next; /* next forward reference */ + AUXU *ifd_ptr; /* pointer to store file index */ + AUXU *index_ptr; /* pointer to store symbol index */ + AUXU *type_ptr; /* pointer to munge type info */ +} forward_t; + + +/* Linked list support for tags. The first tag in the list is always + the current tag for that block. */ +typedef struct tag { + struct shash *hash_ptr; /* pointer to the hash table head */ + struct tag *same_name; /* tag with same name in outer scope */ + struct tag *same_block; /* next tag defined in the same block. */ + struct forward *forward_ref; /* list of forward references */ + bt_t basic_type; /* bt_Struct, bt_Union, or bt_Enum */ + symint_t ifd; /* file # tag defined in */ + symint_t index; /* index within file's local symbols */ +} tag_t; + +/* Head of a block's linked list of tags. */ +typedef struct thead { + struct thead *prev; /* previous block */ + struct tag *first_tag; /* first tag in block defined */ +} thead_t; + + +/* String hash table support. The size of the hash table must fit + within a page. */ + + +#ifndef SHASH_SIZE +#define SHASH_SIZE 1009 +#endif + +#define HASH_LEN_MAX ((1 << 12) - 1) /* Max length we can store */ + +typedef struct shash { + struct shash *next; /* next hash value */ + char *string; /* string we are hashing */ + symint_t len; /* string length */ + symint_t index; /* index within string table */ + EXTR *esym_ptr; /* global symbol pointer */ + SYMR *sym_ptr; /* local symbol pointer */ + tag_t *tag_ptr; /* tag pointer */ + PDR *proc_ptr; /* procedure descriptor pointer */ +} shash_t; + + +/* Type hash table support. The size of the hash table must fit + within a page with the other extended file descriptor information. + Because unique types which are hashed are fewer in number than + strings, we use a smaller hash value. */ + +#ifndef THASH_SIZE +#define THASH_SIZE 113 +#endif + +typedef struct thash { + struct thash *next; /* next hash value */ + AUXU type; /* type we are hashing */ + symint_t index; /* index within string table */ +} thash_t; + + +/* Union of various small structures that are allocated and freed + from the same heap. */ + +typedef union word8 { + union word8 *prev; /* previous word8 structure */ + scope_t s; /* scope structure */ + vlinks_t v; /* varray linked list */ + shash_t sh; /* string hash linked list */ + thash_t th; /* type hash linked list */ + tag_t t; /* tag structure */ + forward_t f; /* forward tag references */ + thead_t thead; /* thead strcture */ + long words[8]; /* words to zero out when allocating */ +} word8_t; + + +/* Extended file descriptor that contains all of the support necessary + to add things to each file separately. */ +typedef struct efdr { + FDR fdr; /* File header to be written out */ + FDR *orig_fdr; /* original file header */ + char *name; /* filename */ + int name_len; /* length of the filename */ + symint_t void_type; /* aux. pointer to 'void' type */ + symint_t int_type; /* aux. pointer to 'int' type */ + scope_t *cur_scope; /* current nested scopes */ + symint_t file_index; /* current file number */ + int nested_scopes; /* # nested scopes */ + varray_t strings; /* local strings */ + varray_t symbols; /* local symbols */ + varray_t procs; /* procedures */ + varray_t aux_syms; /* auxiliary symbols */ + + struct efdr *next_file; /* next file descriptor */ + + /* string/type hash tables */ + shash_t **shash_head; /* string hash table */ + thash_t *thash_head[THASH_SIZE]; +} efdr_t; + +/* Pre-initialized extended file structure. */ +static efdr_t init_file = +{ + { /* FDR structure */ + 0, /* adr: memory address of beginning of file */ + 0, /* rss: file name (of source, if known) */ + 0, /* issBase: file's string space */ + 0, /* cbSs: number of bytes in the ss */ + 0, /* isymBase: beginning of symbols */ + 0, /* csym: count file's of symbols */ + 0, /* ilineBase: file's line symbols */ + 0, /* cline: count of file's line symbols */ + 0, /* ioptBase: file's optimization entries */ + 0, /* copt: count of file's optimization entries */ + 0, /* ipdFirst: start of procedures for this file */ + 0, /* cpd: count of procedures for this file */ + 0, /* iauxBase: file's auxiliary entries */ + 0, /* caux: count of file's auxiliary entries */ + 0, /* rfdBase: index into the file indirect table */ + 0, /* crfd: count file indirect entries */ + langC, /* lang: language for this file */ + 1, /* fMerge: whether this file can be merged */ + 0, /* fReadin: true if read in (not just created) */ +#ifdef BYTES_BIG_ENDIAN + 1, /* fBigendian: if 1, compiled on big endian machine */ +#else + 0, /* fBigendian: if 1, compiled on big endian machine */ +#endif + GLEVEL_2, /* glevel: level this file was compiled with */ + 0, /* reserved: reserved for future use */ + 0, /* cbLineOffset: byte offset from header for this file ln's */ + 0, /* cbLine: size of lines for this file */ + }, + + (FDR *)0, /* orig_fdr: original file header pointer */ + (char *)0, /* name: pointer to filename */ + 0, /* name_len: length of filename */ + 0, /* void_type: ptr to aux node for void type */ + 0, /* int_type: ptr to aux node for int type */ + (scope_t *)0, /* cur_scope: current scope being processed */ + 0, /* file_index: current file # */ + 0, /* nested_scopes: # nested scopes */ + INIT_VARRAY (char), /* strings: local string varray */ + INIT_VARRAY (SYMR), /* symbols: local symbols varray */ + INIT_VARRAY (PDR), /* procs: procedure varray */ + INIT_VARRAY (AUXU), /* aux_syms: auxiliary symbols varray */ + + (struct efdr *)0, /* next_file: next file structure */ + + (shash_t **)0, /* shash_head: string hash table */ + { 0 }, /* thash_head: type hash table */ +}; + + +static efdr_t *first_file; /* first file descriptor */ +static efdr_t *last_file; /* last file descriptor */ + + +/* Union of various things that are held in pages. */ +typedef union page { + char byte [ PAGE_SIZE ]; + unsigned char ubyte[ PAGE_SIZE ]; + efdr_t file [ PAGE_SIZE / sizeof (efdr_t) ]; + FDR ofile[ PAGE_SIZE / sizeof (FDR) ]; + PDR proc [ PAGE_SIZE / sizeof (PDR) ]; + SYMR sym [ PAGE_SIZE / sizeof (SYMR) ]; + EXTR esym [ PAGE_SIZE / sizeof (EXTR) ]; + AUXU aux [ PAGE_SIZE / sizeof (AUXU) ]; + DNR dense[ PAGE_SIZE / sizeof (DNR) ]; + word8_t word8[ PAGE_SIZE / sizeof (word8_t) ]; +} page_t; + + +/* Type information collected together. */ +typedef struct type_info { + bt_t basic_type; /* basic type */ + coff_type_t orig_type; /* original COFF-based type */ + int num_tq; /* # type qualifiers */ + int num_dims; /* # dimensions */ + int num_sizes; /* # sizes */ + int extra_sizes; /* # extra sizes not tied with dims */ + tag_t * tag_ptr; /* tag pointer */ + int bitfield; /* symbol is a bitfield */ + int unknown_tag; /* this is an unknown tag */ + tq_t type_qualifiers[N_TQ]; /* type qualifiers (ptr, func, array)*/ + symint_t dimensions [N_TQ]; /* dimensions for each array */ + symint_t sizes [N_TQ+2]; /* sizes of each array slice + size of + struct/union/enum + bitfield size */ +} type_info_t; + +/* Pre-initialized type_info struct. */ +static type_info_t type_info_init = { + bt_Nil, /* basic type */ + T_NULL, /* original COFF-based type */ + 0, /* # type qualifiers */ + 0, /* # dimensions */ + 0, /* # sizes */ + 0, /* sizes not tied with dims */ + NULL, /* ptr to tag */ + 0, /* bitfield */ + 0, /* unknown tag */ + { /* type qualifiers */ + tq_Nil, + tq_Nil, + tq_Nil, + tq_Nil, + tq_Nil, + tq_Nil, + }, + { /* dimensions */ + 0, + 0, + 0, + 0, + 0, + 0 + }, + { /* sizes */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, +}; + + +/* Global virtual arrays & hash table for external strings as well as + for the tags table and global tables for file descriptors, and + dense numbers. */ + +static varray_t file_desc = INIT_VARRAY (efdr_t); +static varray_t dense_num = INIT_VARRAY (DNR); +static varray_t tag_strings = INIT_VARRAY (char); +static varray_t ext_strings = INIT_VARRAY (char); +static varray_t ext_symbols = INIT_VARRAY (EXTR); + +static shash_t *orig_str_hash[SHASH_SIZE]; +static shash_t *ext_str_hash [SHASH_SIZE]; +static shash_t *tag_hash [SHASH_SIZE]; + +/* Static types for int and void. Also, remember the last function's + type (which is set up when we encounter the declaration for the + function, and used when the end block for the function is emitted. */ + +static type_info_t int_type_info; +static type_info_t void_type_info; +static type_info_t last_func_type_info; +static EXTR *last_func_eptr; + + +/* Convert COFF basic type to ECOFF basic type. The T_NULL type + really should use bt_Void, but this causes the current ecoff GDB to + issue unsupported type messages, and the Ultrix 4.00 dbx (aka MIPS + 2.0) doesn't understand it, even though the compiler generates it. + Maybe this will be fixed in 2.10 or 2.20 of the MIPS compiler + suite, but for now go with what works. */ + +static bt_t map_coff_types[ (int)T_MAX ] = { + bt_Nil, /* T_NULL */ + bt_Nil, /* T_ARG */ + bt_Char, /* T_CHAR */ + bt_Short, /* T_SHORT */ + bt_Int, /* T_INT */ + bt_Long, /* T_LONG */ + bt_Float, /* T_FLOAT */ + bt_Double, /* T_DOUBLE */ + bt_Struct, /* T_STRUCT */ + bt_Union, /* T_UNION */ + bt_Enum, /* T_ENUM */ + bt_Enum, /* T_MOE */ + bt_UChar, /* T_UCHAR */ + bt_UShort, /* T_USHORT */ + bt_UInt, /* T_UINT */ + bt_ULong /* T_ULONG */ +}; + +/* Convert COFF storage class to ECOFF storage class. */ +static sc_t map_coff_storage[ (int)C_MAX ] = { + sc_Nil, /* 0: C_NULL */ + sc_Abs, /* 1: C_AUTO auto var */ + sc_Undefined, /* 2: C_EXT external */ + sc_Data, /* 3: C_STAT static */ + sc_Register, /* 4: C_REG register */ + sc_Undefined, /* 5: C_EXTDEF ??? */ + sc_Text, /* 6: C_LABEL label */ + sc_Text, /* 7: C_ULABEL user label */ + sc_Info, /* 8: C_MOS member of struct */ + sc_Abs, /* 9: C_ARG argument */ + sc_Info, /* 10: C_STRTAG struct tag */ + sc_Info, /* 11: C_MOU member of union */ + sc_Info, /* 12: C_UNTAG union tag */ + sc_Info, /* 13: C_TPDEF typedef */ + sc_Data, /* 14: C_USTATIC ??? */ + sc_Info, /* 15: C_ENTAG enum tag */ + sc_Info, /* 16: C_MOE member of enum */ + sc_Register, /* 17: C_REGPARM register parameter */ + sc_Bits, /* 18; C_FIELD bitfield */ + sc_Nil, /* 19 */ + sc_Nil, /* 20 */ + sc_Nil, /* 21 */ + sc_Nil, /* 22 */ + sc_Nil, /* 23 */ + sc_Nil, /* 24 */ + sc_Nil, /* 25 */ + sc_Nil, /* 26 */ + sc_Nil, /* 27 */ + sc_Nil, /* 28 */ + sc_Nil, /* 29 */ + sc_Nil, /* 30 */ + sc_Nil, /* 31 */ + sc_Nil, /* 32 */ + sc_Nil, /* 33 */ + sc_Nil, /* 34 */ + sc_Nil, /* 35 */ + sc_Nil, /* 36 */ + sc_Nil, /* 37 */ + sc_Nil, /* 38 */ + sc_Nil, /* 39 */ + sc_Nil, /* 40 */ + sc_Nil, /* 41 */ + sc_Nil, /* 42 */ + sc_Nil, /* 43 */ + sc_Nil, /* 44 */ + sc_Nil, /* 45 */ + sc_Nil, /* 46 */ + sc_Nil, /* 47 */ + sc_Nil, /* 48 */ + sc_Nil, /* 49 */ + sc_Nil, /* 50 */ + sc_Nil, /* 51 */ + sc_Nil, /* 52 */ + sc_Nil, /* 53 */ + sc_Nil, /* 54 */ + sc_Nil, /* 55 */ + sc_Nil, /* 56 */ + sc_Nil, /* 57 */ + sc_Nil, /* 58 */ + sc_Nil, /* 59 */ + sc_Nil, /* 60 */ + sc_Nil, /* 61 */ + sc_Nil, /* 62 */ + sc_Nil, /* 63 */ + sc_Nil, /* 64 */ + sc_Nil, /* 65 */ + sc_Nil, /* 66 */ + sc_Nil, /* 67 */ + sc_Nil, /* 68 */ + sc_Nil, /* 69 */ + sc_Nil, /* 70 */ + sc_Nil, /* 71 */ + sc_Nil, /* 72 */ + sc_Nil, /* 73 */ + sc_Nil, /* 74 */ + sc_Nil, /* 75 */ + sc_Nil, /* 76 */ + sc_Nil, /* 77 */ + sc_Nil, /* 78 */ + sc_Nil, /* 79 */ + sc_Nil, /* 80 */ + sc_Nil, /* 81 */ + sc_Nil, /* 82 */ + sc_Nil, /* 83 */ + sc_Nil, /* 84 */ + sc_Nil, /* 85 */ + sc_Nil, /* 86 */ + sc_Nil, /* 87 */ + sc_Nil, /* 88 */ + sc_Nil, /* 89 */ + sc_Nil, /* 90 */ + sc_Nil, /* 91 */ + sc_Nil, /* 92 */ + sc_Nil, /* 93 */ + sc_Nil, /* 94 */ + sc_Nil, /* 95 */ + sc_Nil, /* 96 */ + sc_Nil, /* 97 */ + sc_Nil, /* 98 */ + sc_Nil, /* 99 */ + sc_Text, /* 100: C_BLOCK block start/end */ + sc_Text, /* 101: C_FCN function start/end */ + sc_Info, /* 102: C_EOS end of struct/union/enum */ + sc_Nil, /* 103: C_FILE file start */ + sc_Nil, /* 104: C_LINE line number */ + sc_Nil, /* 105: C_ALIAS combined type info */ + sc_Nil, /* 106: C_HIDDEN ??? */ +}; + +/* Convert COFF storage class to ECOFF symbol type. */ +static st_t map_coff_sym_type[ (int)C_MAX ] = { + st_Nil, /* 0: C_NULL */ + st_Local, /* 1: C_AUTO auto var */ + st_Global, /* 2: C_EXT external */ + st_Static, /* 3: C_STAT static */ + st_Local, /* 4: C_REG register */ + st_Global, /* 5: C_EXTDEF ??? */ + st_Label, /* 6: C_LABEL label */ + st_Label, /* 7: C_ULABEL user label */ + st_Member, /* 8: C_MOS member of struct */ + st_Param, /* 9: C_ARG argument */ + st_Block, /* 10: C_STRTAG struct tag */ + st_Member, /* 11: C_MOU member of union */ + st_Block, /* 12: C_UNTAG union tag */ + st_Typedef, /* 13: C_TPDEF typedef */ + st_Static, /* 14: C_USTATIC ??? */ + st_Block, /* 15: C_ENTAG enum tag */ + st_Member, /* 16: C_MOE member of enum */ + st_Param, /* 17: C_REGPARM register parameter */ + st_Member, /* 18; C_FIELD bitfield */ + st_Nil, /* 19 */ + st_Nil, /* 20 */ + st_Nil, /* 21 */ + st_Nil, /* 22 */ + st_Nil, /* 23 */ + st_Nil, /* 24 */ + st_Nil, /* 25 */ + st_Nil, /* 26 */ + st_Nil, /* 27 */ + st_Nil, /* 28 */ + st_Nil, /* 29 */ + st_Nil, /* 30 */ + st_Nil, /* 31 */ + st_Nil, /* 32 */ + st_Nil, /* 33 */ + st_Nil, /* 34 */ + st_Nil, /* 35 */ + st_Nil, /* 36 */ + st_Nil, /* 37 */ + st_Nil, /* 38 */ + st_Nil, /* 39 */ + st_Nil, /* 40 */ + st_Nil, /* 41 */ + st_Nil, /* 42 */ + st_Nil, /* 43 */ + st_Nil, /* 44 */ + st_Nil, /* 45 */ + st_Nil, /* 46 */ + st_Nil, /* 47 */ + st_Nil, /* 48 */ + st_Nil, /* 49 */ + st_Nil, /* 50 */ + st_Nil, /* 51 */ + st_Nil, /* 52 */ + st_Nil, /* 53 */ + st_Nil, /* 54 */ + st_Nil, /* 55 */ + st_Nil, /* 56 */ + st_Nil, /* 57 */ + st_Nil, /* 58 */ + st_Nil, /* 59 */ + st_Nil, /* 60 */ + st_Nil, /* 61 */ + st_Nil, /* 62 */ + st_Nil, /* 63 */ + st_Nil, /* 64 */ + st_Nil, /* 65 */ + st_Nil, /* 66 */ + st_Nil, /* 67 */ + st_Nil, /* 68 */ + st_Nil, /* 69 */ + st_Nil, /* 70 */ + st_Nil, /* 71 */ + st_Nil, /* 72 */ + st_Nil, /* 73 */ + st_Nil, /* 74 */ + st_Nil, /* 75 */ + st_Nil, /* 76 */ + st_Nil, /* 77 */ + st_Nil, /* 78 */ + st_Nil, /* 79 */ + st_Nil, /* 80 */ + st_Nil, /* 81 */ + st_Nil, /* 82 */ + st_Nil, /* 83 */ + st_Nil, /* 84 */ + st_Nil, /* 85 */ + st_Nil, /* 86 */ + st_Nil, /* 87 */ + st_Nil, /* 88 */ + st_Nil, /* 89 */ + st_Nil, /* 90 */ + st_Nil, /* 91 */ + st_Nil, /* 92 */ + st_Nil, /* 93 */ + st_Nil, /* 94 */ + st_Nil, /* 95 */ + st_Nil, /* 96 */ + st_Nil, /* 97 */ + st_Nil, /* 98 */ + st_Nil, /* 99 */ + st_Block, /* 100: C_BLOCK block start/end */ + st_Proc, /* 101: C_FCN function start/end */ + st_End, /* 102: C_EOS end of struct/union/enum */ + st_File, /* 103: C_FILE file start */ + st_Nil, /* 104: C_LINE line number */ + st_Nil, /* 105: C_ALIAS combined type info */ + st_Nil, /* 106: C_HIDDEN ??? */ +}; + +/* Map COFF derived types to ECOFF type qualifiers. */ +static tq_t map_coff_derived_type[ (int)DT_MAX ] = { + tq_Nil, /* 0: DT_NON no more qualifiers */ + tq_Ptr, /* 1: DT_PTR pointer */ + tq_Proc, /* 2: DT_FCN function */ + tq_Array, /* 3: DT_ARY array */ +}; + + + +/* Pointers and such to the original symbol table that is read in. */ +static struct filehdr orig_file_header; /* global object file header */ + +static HDRR orig_sym_hdr; /* symbolic header on input */ +static char *orig_linenum; /* line numbers */ +static DNR *orig_dense; /* dense numbers */ +static PDR *orig_procs; /* procedures */ +static SYMR *orig_local_syms; /* local symbols */ +static OPTR *orig_opt_syms; /* optimization symbols */ +static AUXU *orig_aux_syms; /* auxiliary symbols */ +static char *orig_local_strs; /* local strings */ +static char *orig_ext_strs; /* external strings */ +static FDR *orig_files; /* file descriptors */ +static symint_t *orig_rfds; /* relative file desc's */ +static EXTR *orig_ext_syms; /* external symbols */ + +/* Macros to convert an index into a given object within the original + symbol table. */ +#define CHECK(num,max,str) \ + (((unsigned long)num > (unsigned long)max) ? out_of_bounds (num, max, str, __LINE__) : 0) + +#define ORIG_LINENUM(index) (CHECK ((index), orig_sym_hdr.cbLine, "line#"), (index) + orig_linenum) +#define ORIG_DENSE(index) (CHECK ((index), orig_sym_hdr.idnMax, "dense"), (index) + orig_dense) +#define ORIG_PROCS(index) (CHECK ((index), orig_sym_hdr.ipdMax, "procs"), (index) + orig_procs) +#define ORIG_FILES(index) (CHECK ((index), orig_sym_hdr.ifdMax, "funcs"), (index) + orig_files) +#define ORIG_LSYMS(index) (CHECK ((index), orig_sym_hdr.isymMax, "lsyms"), (index) + orig_local_syms) +#define ORIG_LSTRS(index) (CHECK ((index), orig_sym_hdr.issMax, "lstrs"), (index) + orig_local_strs) +#define ORIG_ESYMS(index) (CHECK ((index), orig_sym_hdr.iextMax, "esyms"), (index) + orig_ext_syms) +#define ORIG_ESTRS(index) (CHECK ((index), orig_sym_hdr.issExtMax, "estrs"), (index) + orig_ext_strs) +#define ORIG_OPT(index) (CHECK ((index), orig_sym_hdr.ioptMax, "opt"), (index) + orig_opt_syms) +#define ORIG_AUX(index) (CHECK ((index), orig_sym_hdr.iauxMax, "aux"), (index) + orig_aux_syms) +#define ORIG_RFDS(index) (CHECK ((index), orig_sym_hdr.crfd, "rfds"), (index) + orig_rfds) + +/* Various other statics. */ +static HDRR symbolic_header; /* symbolic header */ +static efdr_t *cur_file_ptr = (efdr_t *) 0; /* current file desc. header */ +static PDR *cur_proc_ptr = (PDR *) 0; /* current procedure header */ +static PDR *cur_oproc_ptr = (PDR *) 0; /* current original procedure*/ +static thead_t *cur_tag_head = (thead_t *)0; /* current tag head */ +static long file_offset = 0; /* current file offset */ +static long max_file_offset = 0; /* maximum file offset */ +static FILE *object_stream = (FILE *)0; /* file desc. to output .o */ +static FILE *obj_in_stream = (FILE *)0; /* file desc. to input .o */ +static char *progname = (char *)0; /* program name for errors */ +static char *input_name = "stdin"; /* name of input file */ +static char *object_name = (char *)0; /* tmp. name of object file */ +static char *obj_in_name = (char *)0; /* name of input object file */ +static char *cur_line_start = (char *)0; /* current line read in */ +static char *cur_line_ptr = (char *)0; /* ptr within current line */ +static unsigned cur_line_nbytes = 0; /* # bytes for current line */ +static unsigned cur_line_alloc = 0; /* # bytes total in buffer */ +static long line_number = 0; /* current input line number */ +static int debug = 0; /* trace functions */ +static int version = 0; /* print version # */ +static int had_errors = 0; /* != 0 if errors were found */ +static int rename_output = 0; /* != 0 if rename output file*/ +static int delete_input = 0; /* != 0 if delete input after done */ + + +/* Forward reference for functions. See the definition for more details. */ + +#ifndef STATIC +#define STATIC static +#endif + +STATIC int out_of_bounds __proto((symint_t, symint_t, const char *, int)); + +STATIC shash_t *hash_string __proto((const char *, + Ptrdiff_t, + shash_t **, + symint_t *)); + +STATIC symint_t add_string __proto((varray_t *, + shash_t **, + const char *, + const char *, + shash_t **)); + +STATIC symint_t add_local_symbol + __proto((const char *, + const char *, + st_t, + sc_t, + symint_t, + symint_t)); + +STATIC symint_t add_ext_symbol __proto((const char *, + const char *, + st_t, + sc_t, + long, + symint_t, + int)); + +STATIC symint_t add_aux_sym_symint + __proto((symint_t)); + +STATIC symint_t add_aux_sym_rndx + __proto((int, symint_t)); + +STATIC symint_t add_aux_sym_tir __proto((type_info_t *, + hash_state_t, + thash_t **)); + +STATIC tag_t * get_tag __proto((const char *, + const char *, + symint_t, + bt_t)); + +STATIC void add_unknown_tag __proto((tag_t *)); + +STATIC void add_procedure __proto((const char *, + const char *)); + +STATIC void add_file __proto((const char *, + const char *)); + +STATIC void add_bytes __proto((varray_t *, + char *, + Size_t)); + +STATIC void add_varray_page __proto((varray_t *)); + +STATIC void update_headers __proto((void)); + +STATIC void write_varray __proto((varray_t *, off_t, const char *)); +STATIC void write_object __proto((void)); +STATIC char *st_to_string __proto((st_t)); +STATIC char *sc_to_string __proto((sc_t)); +STATIC char *read_line __proto((void)); +STATIC void parse_input __proto((void)); +STATIC void parse_begin __proto((const char *)); +STATIC void parse_bend __proto((const char *)); +STATIC void parse_def __proto((const char *)); +STATIC void parse_end __proto((const char *)); +STATIC void parse_ent __proto((const char *)); +STATIC void parse_file __proto((const char *)); +STATIC page_t *read_seek __proto((Size_t, off_t, const char *)); +STATIC void copy_object __proto((void)); + +STATIC void catch_signal __proto((int)); +STATIC page_t *allocate_page __proto((void)); + +STATIC page_t *allocate_multiple_pages + __proto((Size_t)); + +STATIC void free_multiple_pages + __proto((page_t *, Size_t)); + +#ifndef MALLOC_CHECK +STATIC page_t *allocate_cluster + __proto((Size_t)); +#endif + +STATIC word8_t *allocate_word8 __proto((void)); +STATIC void free_word8 __proto((word8_t *)); + + +/* Prototypes for library functions used. */ +#if !defined(NO_LIB_PROTOTYPE) && !defined(_OSF_SOURCE) && !defined(_STDIO_H_) +extern char *strchr __proto((const char *, int)); +extern char *strrchr __proto((const char *, int)); +extern int strcmp __proto((const char *, const char *)); +extern long strtol __proto((const char *, char **, int)); +extern int memcmp __proto((CPTR_T, CPTR_T, Size_t)); +extern time_t time __proto((time_t *)); +extern int fputc __proto((int, FILE *)); +extern int vprintf __proto((const char *, va_list)); +extern int vfprintf __proto((FILE *, const char *, va_list)); +extern int vsprintf __proto((char *, const char *, va_list)); +extern int fclose __proto((FILE *)); +extern int fseek __proto((FILE *, long, int)); +extern long ftell __proto((FILE *)); +extern FILE *fopen __proto((const char *, const char *)); +extern FILE *freopen __proto((const char *, const char *, FILE *)); +extern int fflush __proto((FILE *)); +extern void perror __proto((const char *)); +extern void exit __proto((int)); +extern int open __proto((const char *, int, ...)); +extern int rename __proto((const char *, const char *)); + +#ifndef sgi +extern int setvbuf __proto((FILE *, char *, int, int)); +extern int fputs __proto((char *, FILE *)); +#endif + +#ifndef NO_LIB_INTERNALS +extern int _filbuf __proto((FILE *)); +extern int _flsbuf __proto((int, FILE *)); +#endif +#endif + +extern char *sbrk __proto((int)); +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)); +extern int close __proto((int)); +extern int write __proto((int, CPTR_T, Size_t)); +extern int read __proto((int, PTR_T, Size_t)); +extern long lseek __proto((int, long, int)); +extern int ftruncate __proto((int, long)); +extern int getopt __proto((int, char **, const char *)); +extern int fstat __proto((int, struct stat *)); +extern char *mktemp __proto((char *)); + +extern char *optarg; +extern int optind; +extern int opterr; + +#ifndef SEEK_SET /* Symbolic constants for the "fseek" function: */ +#define SEEK_SET 0 /* Set file pointer to offset */ +#define SEEK_CUR 1 /* Set file pointer to its current value plus offset */ +#define SEEK_END 2 /* Set file pointer to the size of the file plus offset */ +#endif + + +/* List of assembler pseudo ops and beginning sequences that need + special actions. Someday, this should be a hash table, and such, + but for now a linear list of names and calls to memcmp will + do...... */ + +typedef struct _pseudo_ops { + const char *name; /* pseduo-op in ascii */ + int len; /* length of name to compare */ + void (*func) __proto((const char *)); /* function to handle line */ +} pseudo_ops_t; + +static pseudo_ops_t pseudo_ops[] = { + { "#.def", sizeof("#.def")-1, parse_def }, + { "#.begin", sizeof("#.begin")-1, parse_begin }, + { "#.bend", sizeof("#.bend")-1, parse_bend }, + { ".end", sizeof(".end")-1, parse_end }, + { ".ent", sizeof(".ent")-1, parse_ent }, + { ".file", sizeof(".file")-1, parse_file }, +}; + + +/* Add a page to a varray object. */ + +STATIC void +add_varray_page (vp) + varray_t *vp; /* varray to add page to */ +{ + vlinks_t *new_links = (vlinks_t *) allocate_word8 (); + +#ifdef MALLOC_CHECK + if (vp->object_size > 1) + new_links->datum = (page_t *) xcalloc (1, vp->object_size); + else +#endif + new_links->datum = allocate_page (); + + new_links->start_index = vp->num_allocated; + vp->objects_last_page = 0; + + if (vp->first == (vlinks_t *)0) /* first allocation? */ + vp->first = vp->last = new_links; + else + { /* 2nd or greater allocation */ + new_links->prev = vp->last; + vp->last->next = new_links; + vp->last = new_links; + } +} + + +/* Compute hash code (from tree.c) */ + +#define HASHBITS 30 + +STATIC shash_t * +hash_string (text, hash_len, hash_tbl, ret_hash_index) + const char *text; /* ptr to text to hash */ + Ptrdiff_t hash_len; /* length of the text */ + shash_t **hash_tbl; /* hash table */ + symint_t *ret_hash_index; /* ptr to store hash index */ +{ + register unsigned long hi; + register Ptrdiff_t i; + register shash_t *ptr; + register int first_ch = *text; + + hi = hash_len; + for (i = 0; i < hash_len; i++) + hi = ((hi & 0x003fffff) * 613) + (text[i] & 0xff); + + hi &= (1 << HASHBITS) - 1; + hi %= SHASH_SIZE; + + if (ret_hash_index != (symint_t *)0) + *ret_hash_index = hi; + + for (ptr = hash_tbl[hi]; ptr != (shash_t *)0; ptr = ptr->next) + if (hash_len == ptr->len + && first_ch == ptr->string[0] + && memcmp ((CPTR_T) text, (CPTR_T) ptr->string, hash_len) == 0) + break; + + return ptr; +} + + +/* Add a string (and null pad) to one of the string tables. A + consequence of hashing strings, is that we don't let strings + cross page boundaries. The extra nulls will be ignored. */ + +STATIC symint_t +add_string (vp, hash_tbl, start, end_p1, ret_hash) + varray_t *vp; /* string virtual array */ + shash_t **hash_tbl; /* ptr to hash table */ + const char *start; /* 1st byte in string */ + const char *end_p1; /* 1st byte after string */ + shash_t **ret_hash; /* return hash pointer */ +{ + register Ptrdiff_t len = end_p1 - start; + register shash_t *hash_ptr; + symint_t hi; + + if (len >= PAGE_USIZE) + fatal ("String too big (%ld bytes)", (long) len); + + hash_ptr = hash_string (start, len, hash_tbl, &hi); + if (hash_ptr == (shash_t *)0) + { + register char *p; + + if (vp->objects_last_page + len >= PAGE_USIZE) + { + vp->num_allocated = + ((vp->num_allocated + PAGE_USIZE - 1) / PAGE_USIZE) * PAGE_USIZE; + add_varray_page (vp); + } + + hash_ptr = (shash_t *) allocate_word8 (); + hash_ptr->next = hash_tbl[hi]; + hash_tbl[hi] = hash_ptr; + + hash_ptr->len = len; + hash_ptr->index = vp->num_allocated; + hash_ptr->string = p = + & vp->last->datum->byte[ vp->objects_last_page ]; + + vp->objects_last_page += len+1; + vp->num_allocated += len+1; + + while (len-- > 0) + *p++ = *start++; + + *p = '\0'; + } + + if (ret_hash != (shash_t **)0) + *ret_hash = hash_ptr; + + return hash_ptr->index; +} + + +/* Add a local symbol. */ + +STATIC symint_t +add_local_symbol (str_start, str_end_p1, type, storage, value, indx) + const char *str_start; /* first byte in string */ + const char *str_end_p1; /* first byte after string */ + st_t type; /* symbol type */ + sc_t storage; /* storage class */ + symint_t value; /* value of symbol */ + symint_t indx; /* index to local/aux. syms */ +{ + register symint_t ret; + register SYMR *psym; + register scope_t *pscope; + register thead_t *ptag_head; + register tag_t *ptag; + register tag_t *ptag_next; + register varray_t *vp = &cur_file_ptr->symbols; + register int scope_delta = 0; + shash_t *hash_ptr = (shash_t *)0; + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + psym = &vp->last->datum->sym[ vp->objects_last_page++ ]; + + psym->value = value; + psym->st = (unsigned) type; + psym->sc = (unsigned) storage; + psym->index = indx; + psym->iss = (str_start == (const char *)0) + ? 0 + : add_string (&cur_file_ptr->strings, + &cur_file_ptr->shash_head[0], + str_start, + str_end_p1, + &hash_ptr); + + ret = vp->num_allocated++; + + /* Save the symbol within the hash table if this is a static + item. */ + if (type == st_Global || type == st_Static || type == st_Label + || type == st_Proc || type == st_StaticProc) + hash_ptr->sym_ptr = psym; + + /* push or pop a scope if appropriate. */ + switch (type) + { + default: + break; + + case st_File: /* beginning of file */ + case st_Proc: /* procedure */ + case st_StaticProc: /* static procedure */ + case st_Block: /* begin scope */ + pscope = (scope_t *) allocate_word8 (); + pscope->prev = cur_file_ptr->cur_scope; + pscope->lsym = psym; + pscope->lnumber = ret; + pscope->type = type; + cur_file_ptr->cur_scope = pscope; + + if (type != st_File) + scope_delta = 1; + + /* For every block type except file, struct, union, or + enumeration blocks, push a level on the tag stack. We omit + file types, so that tags can span file boundaries. */ + if (type != st_File && storage != sc_Info) + { + ptag_head = (thead_t *) allocate_word8 (); + ptag_head->first_tag = 0; + ptag_head->prev = cur_tag_head; + cur_tag_head = ptag_head; + } + break; + + case st_End: + pscope = cur_file_ptr->cur_scope; + if (pscope == (scope_t *)0) + error ("internal error, too many st_End's"); + + else + { + st_t begin_type = (st_t) pscope->lsym->st; + + if (begin_type != st_File) + scope_delta = -1; + + /* Except for file, structure, union, or enumeration end + blocks remove all tags created within this scope. */ + if (begin_type != st_File && storage != sc_Info) + { + ptag_head = cur_tag_head; + cur_tag_head = ptag_head->prev; + + for (ptag = ptag_head->first_tag; + ptag != (tag_t *)0; + ptag = ptag_next) + { + if (ptag->forward_ref != (forward_t *)0) + add_unknown_tag (ptag); + + ptag_next = ptag->same_block; + ptag->hash_ptr->tag_ptr = ptag->same_name; + free_word8 ((word8_t *) ptag); + } + + free_word8 ((word8_t *) ptag_head); + } + + cur_file_ptr->cur_scope = pscope->prev; + psym->index = pscope->lnumber; /* blk end gets begin sym # */ + + if (storage != sc_Info) + psym->iss = pscope->lsym->iss; /* blk end gets same name */ + + if (begin_type == st_File || begin_type == st_Block) + pscope->lsym->index = ret+1; /* block begin gets next sym # */ + + /* Functions push two or more aux words as follows: + 1st word: index+1 of the end symbol + 2nd word: type of the function (plus any aux words needed). + Also, tie the external pointer back to the function begin symbol. */ + else + { + symint_t type; + pscope->lsym->index = add_aux_sym_symint (ret+1); + type = add_aux_sym_tir (&last_func_type_info, + hash_no, + &cur_file_ptr->thash_head[0]); + if (last_func_eptr) + { + last_func_eptr->ifd = cur_file_ptr->file_index; + last_func_eptr->asym.index = type; + } + } + + free_word8 ((word8_t *) pscope); + } + } + + cur_file_ptr->nested_scopes += scope_delta; + + if (debug && type != st_File + && (debug > 2 || type == st_Block || type == st_End + || type == st_Proc || type == st_StaticProc)) + { + char *sc_str = sc_to_string (storage); + char *st_str = st_to_string (type); + int depth = cur_file_ptr->nested_scopes + (scope_delta < 0); + + fprintf (stderr, + "\tlsym\tv= %10ld, depth= %2d, sc= %-12s", + value, depth, sc_str); + + if (str_start && str_end_p1 - str_start > 0) + fprintf (stderr, " st= %-11s name= %.*s\n", st_str, str_end_p1 - str_start, str_start); + else + { + Size_t len = strlen (st_str); + fprintf (stderr, " st= %.*s\n", len-1, st_str); + } + } + + return ret; +} + + +/* Add an external symbol. */ + +STATIC symint_t +add_ext_symbol (str_start, str_end_p1, type, storage, value, indx, ifd) + const char *str_start; /* first byte in string */ + const char *str_end_p1; /* first byte after string */ + st_t type; /* symbol type */ + sc_t storage; /* storage class */ + long value; /* value of symbol */ + symint_t indx; /* index to local/aux. syms */ + int ifd; /* file index */ +{ + register EXTR *psym; + register varray_t *vp = &ext_symbols; + shash_t *hash_ptr = (shash_t *)0; + + if (debug > 1) + { + char *sc_str = sc_to_string (storage); + char *st_str = st_to_string (type); + + fprintf (stderr, + "\tesym\tv= %10ld, ifd= %2d, sc= %-12s", + value, ifd, sc_str); + + if (str_start && str_end_p1 - str_start > 0) + fprintf (stderr, " st= %-11s name= %.*s\n", st_str, str_end_p1 - str_start, str_start); + else + fprintf (stderr, " st= %s\n", st_str); + } + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + psym = &vp->last->datum->esym[ vp->objects_last_page++ ]; + + psym->ifd = ifd; + psym->asym.value = value; + psym->asym.st = (unsigned) type; + psym->asym.sc = (unsigned) storage; + psym->asym.index = indx; + psym->asym.iss = (str_start == (const char *)0) + ? 0 + : add_string (&ext_strings, + &ext_str_hash[0], + str_start, + str_end_p1, + &hash_ptr); + + hash_ptr->esym_ptr = psym; + return vp->num_allocated++; +} + + +/* Add an auxiliary symbol (passing a symint). */ + +STATIC symint_t +add_aux_sym_symint (aux_word) + symint_t aux_word; /* auxilary information word */ +{ + register AUXU *aux_ptr; + register efdr_t *file_ptr = cur_file_ptr; + register varray_t *vp = &file_ptr->aux_syms; + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + aux_ptr = &vp->last->datum->aux[ vp->objects_last_page++ ]; + aux_ptr->isym = aux_word; + + return vp->num_allocated++; +} + + +/* Add an auxiliary symbol (passing a file/symbol index combo). */ + +STATIC symint_t +add_aux_sym_rndx (file_index, sym_index) + int file_index; + symint_t sym_index; +{ + register AUXU *aux_ptr; + register efdr_t *file_ptr = cur_file_ptr; + register varray_t *vp = &file_ptr->aux_syms; + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + aux_ptr = &vp->last->datum->aux[ vp->objects_last_page++ ]; + aux_ptr->rndx.rfd = file_index; + aux_ptr->rndx.index = sym_index; + + return vp->num_allocated++; +} + + +/* Add an auxiliary symbol (passing the basic type and possibly + type qualifiers). */ + +STATIC symint_t +add_aux_sym_tir (t, state, hash_tbl) + type_info_t *t; /* current type information */ + hash_state_t state; /* whether to hash type or not */ + thash_t **hash_tbl; /* pointer to hash table to use */ +{ + register AUXU *aux_ptr; + register efdr_t *file_ptr = cur_file_ptr; + register varray_t *vp = &file_ptr->aux_syms; + static AUXU init_aux; + symint_t ret; + int i; + AUXU aux; + + aux = init_aux; + aux.ti.bt = (int) t->basic_type; + aux.ti.continued = 0; + aux.ti.fBitfield = t->bitfield; + + aux.ti.tq0 = (int) t->type_qualifiers[0]; + aux.ti.tq1 = (int) t->type_qualifiers[1]; + aux.ti.tq2 = (int) t->type_qualifiers[2]; + aux.ti.tq3 = (int) t->type_qualifiers[3]; + aux.ti.tq4 = (int) t->type_qualifiers[4]; + aux.ti.tq5 = (int) t->type_qualifiers[5]; + + + /* For anything that adds additional information, we must not hash, + so check here, and reset our state. */ + + if (state != hash_no + && (t->type_qualifiers[0] == tq_Array + || t->type_qualifiers[1] == tq_Array + || t->type_qualifiers[2] == tq_Array + || t->type_qualifiers[3] == tq_Array + || t->type_qualifiers[4] == tq_Array + || t->type_qualifiers[5] == tq_Array + || t->basic_type == bt_Struct + || t->basic_type == bt_Union + || t->basic_type == bt_Enum + || t->bitfield + || t->num_dims > 0)) + state = hash_no; + + /* See if we can hash this type, and save some space, but some types + can't be hashed (because they contain arrays or continuations), + and others can be put into the hash list, but cannot use existing + types because other aux entries precede this one. */ + + if (state != hash_no) + { + register thash_t *hash_ptr; + register symint_t hi; + + hi = aux.isym & ((1 << HASHBITS) - 1); + hi %= THASH_SIZE; + + for (hash_ptr = hash_tbl[hi]; + hash_ptr != (thash_t *)0; + hash_ptr = hash_ptr->next) + { + if (aux.isym == hash_ptr->type.isym) + break; + } + + if (hash_ptr != (thash_t *)0 && state == hash_yes) + return hash_ptr->index; + + if (hash_ptr == (thash_t *)0) + { + hash_ptr = (thash_t *) allocate_word8 (); + hash_ptr->next = hash_tbl[hi]; + hash_ptr->type = aux; + hash_ptr->index = vp->num_allocated; + hash_tbl[hi] = hash_ptr; + } + } + + /* Everything is set up, add the aux symbol. */ + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + aux_ptr = &vp->last->datum->aux[ vp->objects_last_page++ ]; + *aux_ptr = aux; + + ret = vp->num_allocated++; + + /* Add tag information if needed. Structure, union, and enum + references add 2 aux symbols: a [file index, symbol index] + pointer to the structure type, and the current file index. */ + + if (t->basic_type == bt_Struct + || t->basic_type == bt_Union + || t->basic_type == bt_Enum) + { + register symint_t file_index = t->tag_ptr->ifd; + register symint_t sym_index = t->tag_ptr->index; + + if (t->unknown_tag) + { + (void) add_aux_sym_rndx (ST_RFDESCAPE, sym_index); + (void) add_aux_sym_symint ((symint_t)-1); + } + else if (sym_index != indexNil) + { + (void) add_aux_sym_rndx (ST_RFDESCAPE, sym_index); + (void) add_aux_sym_symint (file_index); + } + else + { + register forward_t *forward_ref = (forward_t *) allocate_word8 (); + + forward_ref->type_ptr = aux_ptr; + forward_ref->next = t->tag_ptr->forward_ref; + t->tag_ptr->forward_ref = forward_ref; + + (void) add_aux_sym_rndx (ST_RFDESCAPE, sym_index); + forward_ref->index_ptr + = &vp->last->datum->aux[ vp->objects_last_page - 1]; + + (void) add_aux_sym_symint (file_index); + forward_ref->ifd_ptr + = &vp->last->datum->aux[ vp->objects_last_page - 1]; + } + } + + /* Add bitfield length if it exists. */ + if (t->bitfield) + (void) add_aux_sym_symint ((symint_t)t->sizes[0]); + + + /* Add information about array bounds if they exist. */ + for (i = 0; i < t->num_dims; i++) + { + (void) add_aux_sym_rndx (ST_RFDESCAPE, + cur_file_ptr->int_type); + + (void) add_aux_sym_symint (cur_file_ptr->file_index); /* file index*/ + (void) add_aux_sym_symint ((symint_t)0); /* low bound */ + (void) add_aux_sym_symint (t->dimensions[i] - 1); /* high bound*/ + (void) add_aux_sym_symint ((t->dimensions[i] == 0) /* stride */ + ? 0 + : (t->sizes[i] * 8) / t->dimensions[i]); + }; + + return ret; +} + + +/* Add a tag to the tag table (unless it already exists). */ + +STATIC tag_t * +get_tag (tag_start, tag_end_p1, index, basic_type) + const char *tag_start; /* 1st byte of tag name */ + const char *tag_end_p1; /* 1st byte after tag name */ + symint_t index; /* index of tag start block */ + bt_t basic_type; /* bt_Struct, bt_Union, or bt_Enum */ +{ + shash_t *hash_ptr; + tag_t *tag_ptr; + hash_ptr = hash_string (tag_start, + tag_end_p1 - tag_start, + &tag_hash[0], + (symint_t *)0); + + if (hash_ptr != (shash_t *)0 + && hash_ptr->tag_ptr != (tag_t *)0) + { + tag_ptr = hash_ptr->tag_ptr; + if (index != indexNil) + { + tag_ptr->basic_type = basic_type; + tag_ptr->ifd = cur_file_ptr->file_index; + tag_ptr->index = index; + } + return tag_ptr; + } + + (void) add_string (&tag_strings, + &tag_hash[0], + tag_start, + tag_end_p1, + &hash_ptr); + + tag_ptr = (tag_t *) allocate_word8 (); + tag_ptr->forward_ref = (forward_t *) 0; + tag_ptr->hash_ptr = hash_ptr; + tag_ptr->same_name = hash_ptr->tag_ptr; + tag_ptr->basic_type = basic_type; + tag_ptr->index = index; + tag_ptr->ifd = (index == indexNil) ? -1 : cur_file_ptr->file_index; + tag_ptr->same_block = cur_tag_head->first_tag; + + cur_tag_head->first_tag = tag_ptr; + hash_ptr->tag_ptr = tag_ptr; + + return tag_ptr; +} + + +/* Add an unknown {struct, union, enum} tag. */ + +STATIC void +add_unknown_tag (ptag) + tag_t *ptag; /* pointer to tag information */ +{ + shash_t *hash_ptr = ptag->hash_ptr; + char *name_start = hash_ptr->string; + char *name_end_p1 = name_start + hash_ptr->len; + forward_t *f_next = ptag->forward_ref; + forward_t *f_cur; + int sym_index; + int file_index = cur_file_ptr->file_index; + + if (debug > 1) + { + char *agg_type = "{unknown aggregate type}"; + switch (ptag->basic_type) + { + case bt_Struct: agg_type = "struct"; break; + case bt_Union: agg_type = "union"; break; + case bt_Enum: agg_type = "enum"; break; + default: break; + } + + fprintf (stderr, "unknown %s %.*s found\n", agg_type, + hash_ptr->len, name_start); + } + + sym_index = add_local_symbol (name_start, + name_end_p1, + st_Block, + sc_Info, + (symint_t)0, + (symint_t)0); + + (void) add_local_symbol (name_start, + name_end_p1, + st_End, + sc_Info, + (symint_t)0, + (symint_t)0); + + while (f_next != (forward_t *)0) + { + f_cur = f_next; + f_next = f_next->next; + + f_cur->ifd_ptr->isym = file_index; + f_cur->index_ptr->rndx.index = sym_index; + + free_word8 ((word8_t *) f_cur); + } + + return; +} + + +/* Add a procedure to the current file's list of procedures, and record + this is the current procedure. If the assembler created a PDR for + this procedure, use that to initialize the current PDR. */ + +STATIC void +add_procedure (func_start, func_end_p1) + const char *func_start; /* 1st byte of func name */ + const char *func_end_p1; /* 1st byte after func name */ +{ + register PDR *new_proc_ptr; + register efdr_t *file_ptr = cur_file_ptr; + register varray_t *vp = &file_ptr->procs; + register symint_t value = 0; + register st_t proc_type = st_Proc; + register shash_t *shash_ptr = hash_string (func_start, + func_end_p1 - func_start, + &orig_str_hash[0], + (symint_t *)0); + + if (debug) + fputc ('\n', stderr); + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + cur_proc_ptr = new_proc_ptr = &vp->last->datum->proc[ vp->objects_last_page++ ]; + + vp->num_allocated++; + + + /* Did the assembler create this procedure? If so, get the PDR information. */ + cur_oproc_ptr = (PDR *)0; + if (shash_ptr != (shash_t *)0) + { + register PDR *old_proc_ptr = shash_ptr->proc_ptr; + register SYMR *sym_ptr = shash_ptr->sym_ptr; + + if (old_proc_ptr != (PDR *)0 + && sym_ptr != (SYMR *)0 + && ((st_t)sym_ptr->st == st_Proc || (st_t)sym_ptr->st == st_StaticProc)) + { + cur_oproc_ptr = old_proc_ptr; + value = sym_ptr->value; + proc_type = (st_t)sym_ptr->st; + *new_proc_ptr = *old_proc_ptr; /* initialize */ + } + } + + if (cur_oproc_ptr == (PDR *)0) + error ("Did not find a PDR block for %.*s", func_end_p1 - func_start, func_start); + + /* Determine the start of symbols. */ + new_proc_ptr->isym = file_ptr->symbols.num_allocated; + + /* Push the start of the function. */ + (void) add_local_symbol (func_start, + func_end_p1, + proc_type, + sc_Text, + value, + (symint_t)0); +} + + +/* Add a new filename, and set up all of the file relative + virtual arrays (strings, symbols, aux syms, etc.). Record + where the current file structure lives. */ + +STATIC void +add_file (file_start, file_end_p1) + const char *file_start; /* first byte in string */ + const char *file_end_p1; /* first byte after string */ +{ + static char zero_bytes[2] = { '\0', '\0' }; + + register Ptrdiff_t len = file_end_p1 - file_start; + register int first_ch = *file_start; + register efdr_t *file_ptr; + + if (debug) + fprintf (stderr, "\tfile\t%.*s\n", len, file_start); + + /* See if the file has already been created. */ + for (file_ptr = first_file; + file_ptr != (efdr_t *)0; + file_ptr = file_ptr->next_file) + { + if (first_ch == file_ptr->name[0] + && file_ptr->name[len] == '\0' + && memcmp ((CPTR_T) file_start, (CPTR_T) file_ptr->name, len) == 0) + { + cur_file_ptr = file_ptr; + break; + } + } + + /* If this is a new file, create it. */ + if (file_ptr == (efdr_t *)0) + { + if (file_desc.objects_last_page == file_desc.objects_per_page) + add_varray_page (&file_desc); + + file_ptr = cur_file_ptr = + &file_desc.last->datum->file[ file_desc.objects_last_page++ ]; + *file_ptr = init_file; + + file_ptr->file_index = file_desc.num_allocated++; + + /* Allocate the string hash table. */ + file_ptr->shash_head = (shash_t **) allocate_page (); + + /* Make sure 0 byte in string table is null */ + add_string (&file_ptr->strings, + &file_ptr->shash_head[0], + &zero_bytes[0], + &zero_bytes[0], + (shash_t **)0); + + if (file_end_p1 - file_start > PAGE_USIZE-2) + fatal ("Filename goes over one page boundary."); + + /* Push the start of the filename. We assume that the filename + will be stored at string offset 1. */ + (void) add_local_symbol (file_start, file_end_p1, st_File, sc_Text, + (symint_t)0, (symint_t)0); + file_ptr->fdr.rss = 1; + file_ptr->name = &file_ptr->strings.last->datum->byte[1]; + file_ptr->name_len = file_end_p1 - file_start; + + /* Update the linked list of file descriptors. */ + if (first_file == (efdr_t *)0) + first_file = file_ptr; + else + last_file->next_file = file_ptr; + + last_file = file_ptr; + + /* Add void & int types to the file (void should be first to catch + errant 0's within the index fields). */ + file_ptr->void_type = add_aux_sym_tir (&void_type_info, + hash_yes, + &cur_file_ptr->thash_head[0]); + + file_ptr->int_type = add_aux_sym_tir (&int_type_info, + hash_yes, + &cur_file_ptr->thash_head[0]); + } +} + + +/* Add a stream of random bytes to a varray. */ + +STATIC void +add_bytes (vp, input_ptr, nitems) + varray_t *vp; /* virtual array to add too */ + char *input_ptr; /* start of the bytes */ + Size_t nitems; /* # items to move */ +{ + register Size_t move_items; + register Size_t move_bytes; + register char *ptr; + + while (nitems > 0) + { + if (vp->objects_last_page >= vp->objects_per_page) + add_varray_page (vp); + + ptr = &vp->last->datum->byte[ vp->objects_last_page * vp->object_size ]; + move_items = vp->objects_per_page - vp->objects_last_page; + if (move_items > nitems) + move_items = nitems; + + move_bytes = move_items * vp->object_size; + nitems -= move_items; + + if (move_bytes >= 32) + { + (void) memcpy ((PTR_T) ptr, (CPTR_T) input_ptr, move_bytes); + input_ptr += move_bytes; + } + else + { + while (move_bytes-- > 0) + *ptr++ = *input_ptr++; + } + } +} + + +/* Convert storage class to string. */ + +STATIC 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. */ + +STATIC 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_Str: return "String,"; + case st_Number: return "Number,"; + case st_Expr: return "Expr,"; + case st_Type: return "Type,"; + case st_Max: return "Max,"; + } + + return "???,"; +} + + +/* Read a line from standard input, and return the start of the + buffer (which is grows if the line is too big). */ + +STATIC char * +read_line __proto((void)) +{ + register int ch; + register char *ptr; + + if (cur_line_start == (char *)0) + { /* allocate initial page */ + cur_line_start = (char *) allocate_page (); + cur_line_alloc = PAGE_SIZE; + } + + cur_line_nbytes = 0; + line_number++; + + for (ptr = cur_line_start; (ch = getchar ()) != EOF; *ptr++ = ch) + { + if (++cur_line_nbytes >= cur_line_alloc-1) + { + register int num_pages = cur_line_alloc / PAGE_SIZE; + register char *old_buffer = cur_line_start; + + cur_line_alloc += PAGE_SIZE; + cur_line_start = (char *) allocate_multiple_pages (num_pages+1); + memcpy (cur_line_start, old_buffer, num_pages * PAGE_SIZE); + + ptr = cur_line_start + cur_line_nbytes - 1; + } + + if (ch == '\n') + { + *ptr++ = '\n'; + *ptr = '\0'; + cur_line_ptr = cur_line_start; + return cur_line_ptr; + } + } + + if (ferror (stdin)) + pfatal_with_name (input_name); + + cur_line_ptr = (char *)0; + return (char *)0; +} + + +/* Parse #.begin directives which have a label as the first argument + which gives the location of the start of the block. */ + +STATIC void +parse_begin (start) + const char *start; /* start of directive */ +{ + const char *end_p1; /* end of label */ + int ch; + shash_t *hash_ptr; /* hash pointer to lookup label */ + + if (cur_file_ptr == (efdr_t *)0) + { + error ("#.begin directive without a preceeding .file directive"); + return; + } + + if (cur_proc_ptr == (PDR *)0) + { + error ("#.begin directive without a preceeding .ent directive"); + return; + } + + for (end_p1 = start; (ch = *end_p1) != '\0' && !isspace (ch); end_p1++) + ; + + hash_ptr = hash_string (start, + end_p1 - start, + &orig_str_hash[0], + (symint_t *)0); + + if (hash_ptr == (shash_t *)0) + { + error ("Label %.*s not found for #.begin", end_p1 - start, start); + return; + } + + (void) add_local_symbol ((const char *)0, + (const char *)0, + st_Block, + sc_Text, + (symint_t)hash_ptr->sym_ptr->value, + (symint_t)0); +} + + +/* Parse #.bend directives which have a label as the first argument + which gives the location of the end of the block. */ + +STATIC void +parse_bend (start) + const char *start; /* start of directive */ +{ + const char *end_p1; /* end of label */ + int ch; + shash_t *hash_ptr; /* hash pointer to lookup label */ + + if (cur_file_ptr == (efdr_t *)0) + { + error ("#.begin directive without a preceeding .file directive"); + return; + } + + if (cur_proc_ptr == (PDR *)0) + { + error ("#.begin directive without a preceeding .ent directive"); + return; + } + + for (end_p1 = start; (ch = *end_p1) != '\0' && !isspace (ch); end_p1++) + ; + + hash_ptr = hash_string (start, + end_p1 - start, + &orig_str_hash[0], + (symint_t *)0); + + if (hash_ptr == (shash_t *)0) + { + error ("Label %.*s not found for #.begin", end_p1 - start, start); + return; + } + + (void) add_local_symbol ((const char *)0, + (const char *)0, + st_End, + sc_Text, + (symint_t)hash_ptr->sym_ptr->value, + (symint_t)0); +} + + +/* Parse #.def directives, which are contain standard COFF subdirectives + to describe the debugging format. These subdirectives include: + + .scl specify storage class + .val specify a value + .endef specify end of COFF directives + .type specify the type + .size specify the size of an array + .dim specify an array dimension + .tag specify a tag for a struct, union, or enum. */ + +STATIC void +parse_def (name_start) + const char *name_start; /* start of directive */ +{ + const char *dir_start; /* start of current directive*/ + const char *dir_end_p1; /* end+1 of current directive*/ + const char *arg_start; /* start of current argument */ + const char *arg_end_p1; /* end+1 of current argument */ + const char *name_end_p1; /* end+1 of label */ + const char *tag_start = (const char *)0; /* start of tag name */ + const char *tag_end_p1 = (const char *)0; /* end+1 of tag name */ + sc_t storage_class = sc_Nil; + st_t symbol_type = st_Nil; + type_info_t t; + EXTR *eptr = (EXTR *)0; /* ext. sym equivalent to def*/ + int is_function = 0; /* != 0 if function */ + symint_t value = 0; + symint_t index = cur_file_ptr->void_type; + int error_line = 0; + symint_t arg_number; + symint_t temp_array[ N_TQ ]; + int arg_was_number; + int ch, i; + Ptrdiff_t len; + + static int inside_enumeration = 0; /* is this an enumeration? */ + + + /* Initialize the type information. */ + t = type_info_init; + + + /* Search for the end of the name being defined. */ + for (name_end_p1 = name_start; (ch = *name_end_p1) != ';'; name_end_p1++) + { + if (ch == '\0' || isspace (ch)) + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + } + + /* Parse the remaining subdirectives now. */ + dir_start = name_end_p1+1; + for (;;) + { + while ((ch = *dir_start) == ' ' || ch == '\t') + ++dir_start; + + if (ch != '.') + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + + /* Are we done? */ + if (dir_start[1] == 'e' + && memcmp (dir_start, ".endef", sizeof (".endef")-1) == 0) + break; + + /* Pick up the subdirective now */ + for (dir_end_p1 = dir_start+1; + (ch = *dir_end_p1) != ' ' && ch != '\t'; + dir_end_p1++) + { + if (ch == '\0' || isspace (ch)) + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + } + + /* Pick up the subdirective argument now. */ + arg_was_number = arg_number = 0; + arg_end_p1 = (const char *)0; + arg_start = dir_end_p1+1; + ch = *arg_start; + while (ch == ' ' || ch == '\t') + ch = *++arg_start; + + if (isdigit (ch) || ch == '-' || ch == '+') + { + int ch2; + arg_number = strtol (arg_start, (char **) &arg_end_p1, 0); + if (arg_end_p1 != arg_start || (ch2 = *arg_end_p1 != ';') || ch2 != ',') + arg_was_number++; + } + + else if (ch == '\0' || isspace (ch)) + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + + if (!arg_was_number) + for (arg_end_p1 = arg_start+1; (ch = *arg_end_p1) != ';'; arg_end_p1++) + { + if (ch == '\0' || isspace (ch)) + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + } + + + /* Classify the directives now. */ + len = dir_end_p1 - dir_start; + switch (dir_start[1]) + { + default: + error_line = __LINE__; + saber_stop (); + goto bomb_out; + + case 'd': + if (len == sizeof (".dim")-1 + && memcmp (dir_start, ".dim", sizeof (".dim")-1) == 0 + && arg_was_number) + { + symint_t *t_ptr = &temp_array[ N_TQ-1 ]; + + *t_ptr = arg_number; + while (*arg_end_p1 == ',' && arg_was_number) + { + arg_start = arg_end_p1+1; + ch = *arg_start; + while (ch == ' ' || ch == '\t') + ch = *++arg_start; + + arg_was_number = 0; + if (isdigit (ch) || ch == '-' || ch == '+') + { + int ch2; + arg_number = strtol (arg_start, (char **) &arg_end_p1, 0); + if (arg_end_p1 != arg_start || (ch2 = *arg_end_p1 != ';') || ch2 != ',') + arg_was_number++; + + if (t_ptr == &temp_array[0]) + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + + *--t_ptr = arg_number; + } + } + + /* Reverse order of dimensions. */ + while (t_ptr <= &temp_array[ N_TQ-1 ]) + { + if (t.num_dims >= N_TQ-1) + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + + t.dimensions[ t.num_dims++ ] = *t_ptr++; + } + break; + } + else + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + + + case 's': + if (len == sizeof (".scl")-1 + && memcmp (dir_start, ".scl", sizeof (".scl")-1) == 0 + && arg_was_number + && arg_number < ((symint_t) C_MAX)) + { + /* If the symbol is a static or external, we have + already gotten the appropriate type and class, so + make sure we don't override those values. This is + needed because there are some type and classes that + are not in COFF, such as short data, etc. */ + if (symbol_type == st_Nil) + { + symbol_type = map_coff_sym_type[arg_number]; + storage_class = map_coff_storage [arg_number]; + } + break; + } + + else if (len == sizeof (".size")-1 + && memcmp (dir_start, ".size", sizeof (".size")-1) == 0 + && arg_was_number) + { + symint_t *t_ptr = &temp_array[ N_TQ-1 ]; + + *t_ptr = arg_number; + while (*arg_end_p1 == ',' && arg_was_number) + { + arg_start = arg_end_p1+1; + ch = *arg_start; + while (ch == ' ' || ch == '\t') + ch = *++arg_start; + + arg_was_number = 0; + if (isdigit (ch) || ch == '-' || ch == '+') + { + int ch2; + arg_number = strtol (arg_start, (char **) &arg_end_p1, 0); + if (arg_end_p1 != arg_start || (ch2 = *arg_end_p1 != ';') || ch2 != ',') + arg_was_number++; + + if (t_ptr == &temp_array[0]) + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + + *--t_ptr = arg_number; + } + } + + /* Reverse order of sizes. */ + while (t_ptr <= &temp_array[ N_TQ-1 ]) + { + if (t.num_sizes >= N_TQ-1) + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + + t.sizes[ t.num_sizes++ ] = *t_ptr++; + } + break; + } + + else + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + + + case 't': + if (len == sizeof (".type")-1 + && memcmp (dir_start, ".type", sizeof (".type")-1) == 0 + && arg_was_number) + { + tq_t *tq_ptr = &t.type_qualifiers[0]; + + t.orig_type = (coff_type_t) (arg_number & N_BTMASK); + t.basic_type = map_coff_types [(int)t.orig_type]; + for (i = N_TQ-1; i >= 0; i--) + { + int dt = (arg_number >> ((i * N_TQ_SHIFT) + N_BT_SHIFT) + & N_TMASK); + + if (dt != (int)DT_NON) + *tq_ptr++ = map_coff_derived_type [dt]; + } + + /* If this is a function, ignore it, so that we don't get + two entries (one from the .ent, and one for the .def + that preceedes it). Save the type information so that + the end block can properly add it after the begin block + index. For MIPS knows what reason, we must strip off + the function type at this point. */ + if (tq_ptr != &t.type_qualifiers[0] && tq_ptr[-1] == tq_Proc) + { + is_function = 1; + tq_ptr[-1] = tq_Nil; + } + + break; + } + + else if (len == sizeof (".tag")-1 + && memcmp (dir_start, ".tag", sizeof (".tag")-1) == 0) + { + tag_start = arg_start; + tag_end_p1 = arg_end_p1; + break; + } + + else + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + + + case 'v': + if (len == sizeof (".val")-1 + && memcmp (dir_start, ".val", sizeof (".val")-1) == 0) + { + if (arg_was_number) + value = arg_number; + + /* If the value is not an integer value, it must be the + name of a static or global item. Look up the name in + the orignal symbol table to pick up the storage + class, symbol type, etc. */ + else + { + shash_t *orig_hash_ptr; /* hash within orig sym table*/ + shash_t *ext_hash_ptr; /* hash within ext. sym table*/ + + ext_hash_ptr = hash_string (arg_start, + arg_end_p1 - arg_start, + &ext_str_hash[0], + (symint_t *)0); + + if (ext_hash_ptr != (shash_t *)0 + && ext_hash_ptr->esym_ptr != (EXTR *)0) + eptr = ext_hash_ptr->esym_ptr; + + orig_hash_ptr = hash_string (arg_start, + arg_end_p1 - arg_start, + &orig_str_hash[0], + (symint_t *)0); + + if ((orig_hash_ptr == (shash_t *)0 + || orig_hash_ptr->sym_ptr == (SYMR *)0) + && eptr == (EXTR *)0) + error ("internal error, %.*s not found in original or external symbol tables", + arg_end_p1 - arg_start, + arg_start); + else + { + SYMR *ptr = (orig_hash_ptr != (shash_t *)0 + && orig_hash_ptr->sym_ptr != (SYMR *)0) + ? orig_hash_ptr->sym_ptr + : &eptr->asym; + + symbol_type = (st_t) ptr->st; + storage_class = (sc_t) ptr->sc; + value = ptr->value; + } + } + break; + } + else + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + } + + /* Set up to find next directive. */ + dir_start = arg_end_p1 + 1; + } + + + t.extra_sizes = (tag_start != (char *)0); + if (t.num_dims > 0) + { + int diff = t.num_dims - t.num_sizes; + int i = t.num_dims - 1; + int j; + + if (t.num_sizes != 1 || diff < 0) + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + + /* If this is an array, make sure the same number of dimensions + and sizes were passed, creating extra sizes for multiply + dimensioned arrays if not passed. */ + + t.extra_sizes = 0; + if (diff) + { + for (j = (sizeof (t.sizes) / sizeof (t.sizes[0])) - 1; j >= 0; j--) + t.sizes[ j ] = ((j-diff) >= 0) ? t.sizes[ j-diff ] : 0; + + t.num_sizes = i + 1; + for ( i--; i >= 0; i-- ) + t.sizes[ i ] = t.sizes[ i+1 ] / t.dimensions[ i+1 ]; + } + } + + else if (symbol_type == st_Member && t.num_sizes - t.extra_sizes == 1) + { /* Is this a bitfield? This is indicated by a structure memeber + having a size field that isn't an array. */ + + t.bitfield = 1; + } + + + /* Except for enumeration members & begin/ending of scopes, put the + type word in the aux. symbol table. */ + + if (symbol_type == st_Block || symbol_type == st_End) + index = 0; + + else if (inside_enumeration) + index = cur_file_ptr->void_type; + + else + { + if (t.basic_type == bt_Struct + || t.basic_type == bt_Union + || t.basic_type == bt_Enum) + { + if (tag_start == (char *)0) + { + error ("No tag specified for %.*s", + name_end_p1 - name_start, + name_start); + return; + } + + t.tag_ptr = get_tag (tag_start, tag_end_p1, (symint_t)indexNil, + t.basic_type); + } + + if (is_function) + { + last_func_type_info = t; + last_func_eptr = eptr; + return; + } + + index = add_aux_sym_tir (&t, + hash_yes, + &cur_file_ptr->thash_head[0]); + } + + + /* If this is an external or static symbol, update the appropriate + external symbol. */ + + if (eptr != (EXTR *)0 + && (eptr->asym.index == indexNil || cur_proc_ptr == (PDR *)0)) + { + eptr->ifd = cur_file_ptr->file_index; + eptr->asym.index = index; + } + + + /* Do any last minute adjustments that are necessary. */ + switch (symbol_type) + { + default: + break; + + + /* For the beginning of structs, unions, and enumerations, the + size info needs to be passed in the value field. */ + + case st_Block: + if (t.num_sizes - t.num_dims - t.extra_sizes != 1) + { + error_line = __LINE__; + saber_stop (); + goto bomb_out; + } + + else + value = t.sizes[0]; + + inside_enumeration = (t.orig_type == T_ENUM); + break; + + + /* For the end of structs, unions, and enumerations, omit the + name which is always ".eos". This needs to be done last, so + that any error reporting above gives the correct name. */ + + case st_End: + name_start = name_end_p1 = (const char *)0; + value = inside_enumeration = 0; + break; + + + /* Members of structures and unions that aren't bitfields, need + to adjust the value from a byte offset to a bit offset. + Members of enumerations do not have the value adjusted, and + can be distinquished by index == indexNil. For enumerations, + update the maximum enumeration value. */ + + case st_Member: + if (!t.bitfield && !inside_enumeration) + value *= 8; + + break; + } + + + /* Add the symbol, except for global symbols outside of functions, + for which the external symbol table is fine enough. */ + + if (eptr == (EXTR *)0 + || eptr->asym.st == (int)st_Nil + || cur_proc_ptr != (PDR *)0) + { + symint_t isym = add_local_symbol (name_start, + name_end_p1, + symbol_type, + storage_class, + value, + index); + + /* deal with struct, union, and enum tags. */ + if (symbol_type == st_Block) + { + /* Create or update the tag information. */ + tag_t *tag_ptr = get_tag (name_start, + name_end_p1, + isym, + t.basic_type); + + /* If there are any forward references, fill in the appropriate + file and symbol indexes. */ + + symint_t file_index = cur_file_ptr->file_index; + forward_t *f_next = tag_ptr->forward_ref; + forward_t *f_cur; + + while (f_next != (forward_t *)0) + { + f_cur = f_next; + f_next = f_next->next; + + f_cur->ifd_ptr->isym = file_index; + f_cur->index_ptr->rndx.index = isym; + + free_word8 ((word8_t *) f_cur); + } + + tag_ptr->forward_ref = (forward_t *)0; + } + } + + /* Normal return */ + return; + + /* Error return, issue message. */ +bomb_out: + if (error_line) + error ("compiler error, badly formed #.def (internal line # = %d)", error_line); + else + error ("compiler error, badly formed #.def"); + + return; +} + + +/* Parse .end directives. */ + +STATIC void +parse_end (start) + const char *start; /* start of directive */ +{ + register const char *start_func, *end_func_p1; + register int ch; + register symint_t value; + register FDR *orig_fdr; + + if (cur_file_ptr == (efdr_t *)0) + { + error (".end directive without a preceeding .file directive"); + return; + } + + if (cur_proc_ptr == (PDR *)0) + { + error (".end directive without a preceeding .ent directive"); + return; + } + + /* Get the function name, skipping whitespace. */ + for (start_func = start; isspace (*start_func); start_func++) + ; + + ch = *start_func; + if (!IS_ASM_IDENT (ch)) + { + error (".end directive has no name"); + return; + } + + for (end_func_p1 = start_func; IS_ASM_IDENT (ch); ch = *++end_func_p1) + ; + + + /* Get the value field for creating the end from the original object + file (which we find by locating the procedure start, and using the + pointer to the end+1 block and backing up. The index points to a + two word aux. symbol, whose first word is the index of the end + symbol, and the second word is the type of the function return + value. */ + + orig_fdr = cur_file_ptr->orig_fdr; + value = 0; + if (orig_fdr != (FDR *)0 && cur_oproc_ptr != (PDR *)0) + { + register SYMR *sym_ptr = ORIG_LSYMS (orig_fdr->isymBase + cur_oproc_ptr->isym); + + if ((st_t)sym_ptr->st == st_Proc + || (st_t)sym_ptr->st == st_StaticProc) + { + AUXU *aptr = ORIG_AUX (orig_fdr->iauxBase + sym_ptr->index); + symint_t end_index = aptr->isym; + value = (ORIG_LSYMS (orig_fdr->isymBase + end_index - 1))->value; + } + } + + (void) add_local_symbol (start_func, + end_func_p1, + st_End, + sc_Text, + value, + (symint_t)0); + + cur_proc_ptr = cur_oproc_ptr = (PDR *)0; +} + + +/* Parse .ent directives. */ + +STATIC void +parse_ent (start) + const char *start; /* start of directive */ +{ + register const char *start_func, *end_func_p1; + register int ch; + + if (cur_file_ptr == (efdr_t *)0) + { + error (".ent directive without a preceeding .file directive"); + return; + } + + if (cur_proc_ptr != (PDR *)0) + { + error ("second .ent directive found before .end directive"); + return; + } + + for (start_func = start; isspace (*start_func); start_func++) + ; + + ch = *start_func; + if (!IS_ASM_IDENT (ch)) + { + error (".ent directive has no name"); + return; + } + + for (end_func_p1 = start_func; IS_ASM_IDENT (ch); ch = *++end_func_p1) + ; + + (void) add_procedure (start_func, end_func_p1); +} + + +/* Parse .file directives. */ + +STATIC void +parse_file (start) + const char *start; /* start of directive */ +{ + char *p; + register char *start_name, *end_name_p1; + + (void) strtol (start, &p, 0); + if (start == p + || (start_name = strchr (p, '"')) == (char *)0 + || (end_name_p1 = strrchr (++start_name, '"')) == (char *)0) + { + error ("Illegal .file directive"); + return; + } + + if (cur_proc_ptr != (PDR *)0) + { + error ("No way to handle .file within .ent/.end section"); + return; + } + + add_file (start_name, end_name_p1); +} + + +/* Parse the input file, and write the lines to the output file + if needed. */ + +STATIC void +parse_input __proto((void)) +{ + register char *p; + register int i; + register thead_t *ptag_head; + register tag_t *ptag; + register tag_t *ptag_next; + + if (debug) + fprintf (stderr, "\tinput\n"); + + /* Add a dummy scope block around the entire compilation unit for + structures defined outside of blocks. */ + ptag_head = (thead_t *) allocate_word8 (); + ptag_head->first_tag = 0; + ptag_head->prev = cur_tag_head; + cur_tag_head = ptag_head; + + while ((p = read_line ()) != (char *)0) + { + /* Skip leading blanks */ + while (isspace (*p)) + p++; + + /* See if it's a directive we handle. If so, dispatch handler. */ + for (i = 0; i < sizeof (pseudo_ops) / sizeof (pseudo_ops[0]); i++) + if (memcmp (p, pseudo_ops[i].name, pseudo_ops[i].len) == 0 + && isspace (p[pseudo_ops[i].len])) + { + p += pseudo_ops[i].len; /* skip to first argument */ + while (isspace (*p)) + p++; + + (*pseudo_ops[i].func)( p ); + break; + } + } + + /* Process any tags at global level. */ + ptag_head = cur_tag_head; + cur_tag_head = ptag_head->prev; + + for (ptag = ptag_head->first_tag; + ptag != (tag_t *)0; + ptag = ptag_next) + { + if (ptag->forward_ref != (forward_t *)0) + add_unknown_tag (ptag); + + ptag_next = ptag->same_block; + ptag->hash_ptr->tag_ptr = ptag->same_name; + free_word8 ((word8_t *) ptag); + } + + free_word8 ((word8_t *) ptag_head); + +} + + +/* Update the global headers with the final offsets in preparation + to write out the .T file. */ + +STATIC void +update_headers __proto((void)) +{ + register symint_t i; + register efdr_t *file_ptr; + + /* Set up the symbolic header. */ + file_offset = sizeof (symbolic_header) + orig_file_header.f_symptr; + symbolic_header.magic = orig_sym_hdr.magic; + symbolic_header.vstamp = orig_sym_hdr.vstamp; + + /* Set up global counts. */ + symbolic_header.issExtMax = ext_strings.num_allocated; + symbolic_header.idnMax = dense_num.num_allocated; + symbolic_header.ifdMax = file_desc.num_allocated; + symbolic_header.iextMax = ext_symbols.num_allocated; + symbolic_header.ilineMax = orig_sym_hdr.ilineMax; + symbolic_header.ioptMax = orig_sym_hdr.ioptMax; + symbolic_header.cbLine = orig_sym_hdr.cbLine; + symbolic_header.crfd = orig_sym_hdr.crfd; + + + /* Loop through each file, figuring out how many local syms, + line numbers, etc. there are. Also, put out end symbol + for the filename. */ + + for (file_ptr = first_file; + file_ptr != (efdr_t *)0; + file_ptr = file_ptr->next_file) + { + cur_file_ptr = file_ptr; + (void) add_local_symbol ((const char *)0, + (const char *)0, + st_End, + sc_Text, + (symint_t)0, + (symint_t)0); + + file_ptr->fdr.cpd = file_ptr->procs.num_allocated; + file_ptr->fdr.ipdFirst = symbolic_header.ipdMax; + symbolic_header.ipdMax += file_ptr->fdr.cpd; + + file_ptr->fdr.csym = file_ptr->symbols.num_allocated; + file_ptr->fdr.isymBase = symbolic_header.isymMax; + symbolic_header.isymMax += file_ptr->fdr.csym; + + file_ptr->fdr.caux = file_ptr->aux_syms.num_allocated; + file_ptr->fdr.iauxBase = symbolic_header.iauxMax; + symbolic_header.iauxMax += file_ptr->fdr.caux; + + file_ptr->fdr.cbSs = file_ptr->strings.num_allocated; + file_ptr->fdr.issBase = symbolic_header.issMax; + symbolic_header.issMax += file_ptr->fdr.cbSs; + } + + + i = WORD_ALIGN (symbolic_header.cbLine); /* line numbers */ + if (i > 0) + { + symbolic_header.cbLineOffset = file_offset; + file_offset += i; + } + + i = symbolic_header.ioptMax; /* optimization symbols */ + if (((long) i) > 0) + { + symbolic_header.cbOptOffset = file_offset; + file_offset += i * sizeof (OPTR); + } + + i = symbolic_header.idnMax; /* dense numbers */ + if (i > 0) + { + symbolic_header.cbDnOffset = file_offset; + file_offset += i * sizeof (DNR); + } + + i = symbolic_header.ipdMax; /* procedure tables */ + if (i > 0) + { + symbolic_header.cbPdOffset = file_offset; + file_offset += i * sizeof (PDR); + } + + i = symbolic_header.isymMax; /* local symbols */ + if (i > 0) + { + symbolic_header.cbSymOffset = file_offset; + file_offset += i * sizeof (SYMR); + } + + i = symbolic_header.iauxMax; /* aux syms. */ + if (i > 0) + { + symbolic_header.cbAuxOffset = file_offset; + file_offset += i * sizeof (TIR); + } + + i = WORD_ALIGN (symbolic_header.issMax); /* local strings */ + if (i > 0) + { + symbolic_header.cbSsOffset = file_offset; + file_offset += i; + } + + i = WORD_ALIGN (symbolic_header.issExtMax); /* external strings */ + if (i > 0) + { + symbolic_header.cbSsExtOffset = file_offset; + file_offset += i; + } + + i = symbolic_header.ifdMax; /* file tables */ + if (i > 0) + { + symbolic_header.cbFdOffset = file_offset; + file_offset += i * sizeof (FDR); + } + + i = symbolic_header.crfd; /* relative file descriptors */ + if (i > 0) + { + symbolic_header.cbRfdOffset = file_offset; + file_offset += i * sizeof (symint_t); + } + + i = symbolic_header.iextMax; /* external symbols */ + if (i > 0) + { + symbolic_header.cbExtOffset = file_offset; + file_offset += i * sizeof (EXTR); + } +} + + +/* Write out a varray at a given location. */ + +STATIC void +write_varray (vp, offset, str) + varray_t *vp; /* virtual array */ + off_t offset; /* offset to write varray to */ + const char *str; /* string to print out when tracing */ +{ + int num_write, sys_write; + vlinks_t *ptr; + + if (vp->num_allocated == 0) + return; + + if (debug) + fprintf (stderr, "\twarray\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n", + vp, offset, vp->num_allocated * vp->object_size, str); + + if (file_offset != offset + && fseek (object_stream, (long)offset, SEEK_SET) < 0) + pfatal_with_name (object_name); + + for (ptr = vp->first; ptr != (vlinks_t *)0; ptr = ptr->next) + { + num_write = (ptr->next == (vlinks_t *)0) + ? vp->objects_last_page * vp->object_size + : vp->objects_per_page * vp->object_size; + + sys_write = fwrite ((PTR_T) ptr->datum, 1, num_write, object_stream); + if (sys_write <= 0) + pfatal_with_name (object_name); + + else if (sys_write != num_write) + fatal ("Wrote %d bytes to %s, system returned %d", + num_write, + object_name, + sys_write); + + file_offset += num_write; + } +} + + +/* Write out the symbol table in the object file. */ + +STATIC void +write_object __proto((void)) +{ + int sys_write; + efdr_t *file_ptr; + off_t offset; + + if (debug) + fprintf (stderr, "\n\twrite\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n", + (PTR_T *) &symbolic_header, 0, sizeof (symbolic_header), + "symbolic header"); + + sys_write = fwrite ((PTR_T) &symbolic_header, + 1, + sizeof (symbolic_header), + object_stream); + + if (sys_write < 0) + pfatal_with_name (object_name); + + else if (sys_write != sizeof (symbolic_header)) + fatal ("Wrote %d bytes to %s, system returned %d", + sizeof (symbolic_header), + object_name, + sys_write); + + + file_offset = sizeof (symbolic_header) + orig_file_header.f_symptr; + + if (symbolic_header.cbLine > 0) /* line numbers */ + { + long sys_write; + + if (file_offset != symbolic_header.cbLineOffset + && fseek (object_stream, symbolic_header.cbLineOffset, SEEK_SET) != 0) + pfatal_with_name (object_name); + + if (debug) + fprintf (stderr, "\twrite\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n", + (PTR_T *) &orig_linenum, symbolic_header.cbLineOffset, + symbolic_header.cbLine, "Line numbers"); + + sys_write = fwrite ((PTR_T) orig_linenum, + 1, + symbolic_header.cbLine, + object_stream); + + if (sys_write <= 0) + pfatal_with_name (object_name); + + else if (sys_write != symbolic_header.cbLine) + fatal ("Wrote %d bytes to %s, system returned %d", + symbolic_header.cbLine, + object_name, + sys_write); + + file_offset = symbolic_header.cbLineOffset + symbolic_header.cbLine; + } + + if (symbolic_header.ioptMax > 0) /* optimization symbols */ + { + long sys_write; + long num_write = symbolic_header.ioptMax * sizeof (OPTR); + + if (file_offset != symbolic_header.cbOptOffset + && fseek (object_stream, symbolic_header.cbOptOffset, SEEK_SET) != 0) + pfatal_with_name (object_name); + + if (debug) + fprintf (stderr, "\twrite\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n", + (PTR_T *) &orig_opt_syms, symbolic_header.cbOptOffset, + num_write, "Optimizer symbols"); + + sys_write = fwrite ((PTR_T) orig_opt_syms, + 1, + num_write, + object_stream); + + if (sys_write <= 0) + pfatal_with_name (object_name); + + else if (sys_write != num_write) + fatal ("Wrote %d bytes to %s, system returned %d", + num_write, + object_name, + sys_write); + + file_offset = symbolic_header.cbOptOffset + num_write; + } + + if (symbolic_header.idnMax > 0) /* dense numbers */ + write_varray (&dense_num, (off_t)symbolic_header.cbDnOffset, "Dense numbers"); + + if (symbolic_header.ipdMax > 0) /* procedure tables */ + { + offset = symbolic_header.cbPdOffset; + for (file_ptr = first_file; + file_ptr != (efdr_t *)0; + file_ptr = file_ptr->next_file) + { + write_varray (&file_ptr->procs, offset, "Procedure tables"); + offset = file_offset; + } + } + + if (symbolic_header.isymMax > 0) /* local symbols */ + { + offset = symbolic_header.cbSymOffset; + for (file_ptr = first_file; + file_ptr != (efdr_t *)0; + file_ptr = file_ptr->next_file) + { + write_varray (&file_ptr->symbols, offset, "Local symbols"); + offset = file_offset; + } + } + + if (symbolic_header.iauxMax > 0) /* aux symbols */ + { + offset = symbolic_header.cbAuxOffset; + for (file_ptr = first_file; + file_ptr != (efdr_t *)0; + file_ptr = file_ptr->next_file) + { + write_varray (&file_ptr->aux_syms, offset, "Aux. symbols"); + offset = file_offset; + } + } + + if (symbolic_header.issMax > 0) /* local strings */ + { + offset = symbolic_header.cbSsOffset; + for (file_ptr = first_file; + file_ptr != (efdr_t *)0; + file_ptr = file_ptr->next_file) + { + write_varray (&file_ptr->strings, offset, "Local strings"); + offset = file_offset; + } + } + + if (symbolic_header.issExtMax > 0) /* external strings */ + write_varray (&ext_strings, symbolic_header.cbSsExtOffset, "External strings"); + + if (symbolic_header.ifdMax > 0) /* file tables */ + { + offset = symbolic_header.cbFdOffset; + if (file_offset != offset + && fseek (object_stream, (long)offset, SEEK_SET) < 0) + pfatal_with_name (object_name); + + file_offset = offset; + for (file_ptr = first_file; + file_ptr != (efdr_t *)0; + file_ptr = file_ptr->next_file) + { + if (debug) + fprintf (stderr, "\twrite\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n", + (PTR_T *) &file_ptr->fdr, file_offset, sizeof (FDR), "File header"); + + sys_write = fwrite (&file_ptr->fdr, + 1, + sizeof (FDR), + object_stream); + + if (sys_write < 0) + pfatal_with_name (object_name); + + else if (sys_write != sizeof (FDR)) + fatal ("Wrote %d bytes to %s, system returned %d", + sizeof (FDR), + object_name, + sys_write); + + file_offset = offset += sizeof (FDR); + } + } + + if (symbolic_header.crfd > 0) /* relative file descriptors */ + { + long sys_write; + symint_t num_write = symbolic_header.crfd * sizeof (symint_t); + + if (file_offset != symbolic_header.cbRfdOffset + && fseek (object_stream, symbolic_header.cbRfdOffset, SEEK_SET) != 0) + pfatal_with_name (object_name); + + if (debug) + fprintf (stderr, "\twrite\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n", + (PTR_T *) &orig_rfds, symbolic_header.cbRfdOffset, + num_write, "Relative file descriptors"); + + sys_write = fwrite (orig_rfds, + 1, + num_write, + object_stream); + + if (sys_write <= 0) + pfatal_with_name (object_name); + + else if (sys_write != num_write) + fatal ("Wrote %d bytes to %s, system returned %d", + num_write, + object_name, + sys_write); + + file_offset = symbolic_header.cbRfdOffset + num_write; + } + + if (symbolic_header.issExtMax > 0) /* external symbols */ + write_varray (&ext_symbols, (off_t)symbolic_header.cbExtOffset, "External symbols"); + + if (fclose (object_stream) != 0) + pfatal_with_name (object_name); +} + + +/* Read some bytes at a specified location, and return a pointer. */ + +STATIC page_t * +read_seek (size, offset, str) + Size_t size; /* # bytes to read */ + off_t offset; /* offset to read at */ + const char *str; /* name for tracing */ +{ + page_t *ptr; + long sys_read = 0; + + if (size == 0) /* nothing to read */ + return (page_t *)0; + + if (debug) + fprintf (stderr, "\trseek\tsize = %7u, offset = %7u, currently at %7u, %s\n", + size, offset, file_offset, str); + +#ifndef MALLOC_CHECK + ptr = allocate_multiple_pages ((size + PAGE_USIZE - 1) / PAGE_USIZE); +#else + ptr = (page_t *) xcalloc (1, size); +#endif + + /* If we need to seek, and the distance is nearby, just do some reads, + to speed things up. */ + if (file_offset != offset) + { + symint_t difference = offset - file_offset; + + if (difference < 8) + { + char small_buffer[8]; + + sys_read = fread (small_buffer, 1, difference, obj_in_stream); + if (sys_read <= 0) + pfatal_with_name (obj_in_name); + + if (sys_read != difference) + fatal ("Wanted to read %d bytes from %s, system returned %d", + size, + sys_read, + obj_in_name); + } + else if (fseek (obj_in_stream, offset, SEEK_SET) < 0) + pfatal_with_name (obj_in_name); + } + + sys_read = fread ((PTR_T)ptr, 1, size, obj_in_stream); + if (sys_read <= 0) + pfatal_with_name (obj_in_name); + + if (sys_read != size) + fatal ("Wanted to read %d bytes from %s, system returned %d", + size, + sys_read, + obj_in_name); + + file_offset = offset + size; + + if (file_offset > max_file_offset) + max_file_offset = file_offset; + + return ptr; +} + + +/* Read the existing object file (and copy to the output object file + if it is different from the input object file), and remove the old + symbol table. */ + +STATIC void +copy_object __proto((void)) +{ + char buffer[ PAGE_SIZE ]; + register int sys_read; + register int remaining; + register int num_write; + register int sys_write; + register int fd, es; + register int delete_ifd = 0; + struct stat stat_buf; + + if (debug) + fprintf (stderr, "\tcopy\n"); + + if (fstat (fileno (obj_in_stream), &stat_buf) != 0 + || fseek (obj_in_stream, 0L, SEEK_SET) != 0) + pfatal_with_name (obj_in_name); + + sys_read = fread ((PTR_T) &orig_file_header, + 1, + sizeof (struct filehdr), + obj_in_stream); + + if (sys_read < 0) + pfatal_with_name (obj_in_name); + + else if (sys_read == 0 && feof (obj_in_stream)) + return; /* create a .T file sans file header */ + + else if (sys_read < sizeof (struct filehdr)) + fatal ("Wanted to read %d bytes from %s, system returned %d", + sizeof (struct filehdr), + obj_in_name, + sys_read); + + + if (orig_file_header.f_flags != 0) + fatal ("Non-zero flags encountered in %s filehdr", input_name); + + if (orig_file_header.f_nsyms != sizeof (HDRR)) + fatal ("%s symbolic header wrong size (%d bytes, should be %d)", + input_name, orig_file_header.f_nsyms, sizeof (HDRR)); + + + /* Read in the current symbolic header. */ + if (fseek (obj_in_stream, (long) orig_file_header.f_symptr, SEEK_SET) != 0) + pfatal_with_name (input_name); + + sys_read = fread ((PTR_T) &orig_sym_hdr, + 1, + sizeof (orig_sym_hdr), + obj_in_stream); + + if (sys_read < 0) + pfatal_with_name (object_name); + + else if (sys_read < sizeof (struct filehdr)) + fatal ("Wanted to read %d bytes from %s, system returned %d", + sizeof (struct filehdr), + obj_in_name, + sys_read); + + + /* Read in each of the sections if they exist in the object file. + We read things in in the order the mips assembler creates the + sections, so in theory no extra seeks are done. + + For simplicity sake, round each read up to a page boundary, + we may want to revisit this later.... */ + + file_offset = orig_file_header.f_symptr + sizeof (struct filehdr); + + if (orig_sym_hdr.cbLine > 0) /* line numbers */ + orig_linenum = (char *) read_seek ((Size_t)orig_sym_hdr.cbLine, + orig_sym_hdr.cbLineOffset, + "Line numbers"); + + if (orig_sym_hdr.ipdMax > 0) /* procedure tables */ + orig_procs = (PDR *) read_seek ((Size_t)orig_sym_hdr.ipdMax * sizeof (PDR), + orig_sym_hdr.cbPdOffset, + "Procedure tables"); + + if (orig_sym_hdr.isymMax > 0) /* local symbols */ + orig_local_syms = (SYMR *) read_seek ((Size_t)orig_sym_hdr.isymMax * sizeof (SYMR), + orig_sym_hdr.cbSymOffset, + "Local symbols"); + + if (orig_sym_hdr.iauxMax > 0) /* aux symbols */ + orig_aux_syms = (AUXU *) read_seek ((Size_t)orig_sym_hdr.iauxMax * sizeof (AUXU), + orig_sym_hdr.cbAuxOffset, + "Aux. symbols"); + + if (orig_sym_hdr.issMax > 0) /* local strings */ + orig_local_strs = (char *) read_seek ((Size_t)orig_sym_hdr.issMax, + orig_sym_hdr.cbSsOffset, + "Local strings"); + + if (orig_sym_hdr.issExtMax > 0) /* external strings */ + orig_ext_strs = (char *) read_seek ((Size_t)orig_sym_hdr.issExtMax, + orig_sym_hdr.cbSsExtOffset, + "External strings"); + + if (orig_sym_hdr.ifdMax > 0) /* file tables */ + orig_files = (FDR *) read_seek ((Size_t)orig_sym_hdr.ifdMax * sizeof (FDR), + orig_sym_hdr.cbFdOffset, + "File tables"); + + if (orig_sym_hdr.crfd > 0) /* relative file descriptors */ + orig_rfds = (symint_t *) read_seek ((Size_t)orig_sym_hdr.crfd * sizeof (symint_t), + orig_sym_hdr.cbRfdOffset, + "Relative file descriptors"); + + if (orig_sym_hdr.issExtMax > 0) /* external symbols */ + orig_ext_syms = (EXTR *) read_seek ((Size_t)orig_sym_hdr.iextMax * sizeof (EXTR), + orig_sym_hdr.cbExtOffset, + "External symbols"); + + if (orig_sym_hdr.idnMax > 0) /* dense numbers */ + { + orig_dense = (DNR *) read_seek ((Size_t)orig_sym_hdr.idnMax * sizeof (DNR), + orig_sym_hdr.cbDnOffset, + "Dense numbers"); + + add_bytes (&dense_num, (char *) orig_dense, (Size_t)orig_sym_hdr.idnMax); + } + + if (orig_sym_hdr.ioptMax > 0) /* opt symbols */ + orig_opt_syms = (OPTR *) read_seek ((Size_t)orig_sym_hdr.ioptMax * sizeof (OPTR), + orig_sym_hdr.cbOptOffset, + "Optimizer symbols"); + + + + /* Abort if the symbol table is not last. */ + if (max_file_offset != stat_buf.st_size) + fatal ("Symbol table is not last (symbol table ends at %ld, .o ends at %ld", + max_file_offset, + stat_buf.st_size); + + + /* If the first original file descriptor is a dummy which the assembler + put out, but there are no symbols in it, skip it now. */ + if (orig_sym_hdr.ifdMax > 1 + && orig_files->csym == 2 + && orig_files->caux == 0) + { + char *filename = orig_local_strs + (orig_files->issBase + orig_files->rss); + char *suffix = strrchr (filename, '.'); + + if (suffix != (char *)0 && strcmp (suffix, ".s") == 0) + delete_ifd = 1; + } + + + /* Loop, adding each of the external symbols. These must be in + order or otherwise we would have to change the relocation + entries. We don't just call add_bytes, because we need to have + the names put into the external hash table. We set the type to + 'void' for now, and parse_def will fill in the correct type if it + is in the symbol table. */ + + if (debug) + fprintf (stderr, "\tehash\n"); + + for (es = 0; es < orig_sym_hdr.iextMax; es++) + { + register EXTR *eptr = orig_ext_syms + es; + register char *ename = ORIG_ESTRS (eptr->asym.iss); + + (void) add_ext_symbol (ename, + ename + strlen (ename), + (st_t) eptr->asym.st, + (sc_t) eptr->asym.sc, + eptr->asym.value, + (symint_t)((eptr->asym.index == indexNil) ? indexNil : 0), + eptr->ifd - delete_ifd); + } + + + /* For each of the files in the object file, copy the symbols, and such + into the varrays for the new object file. */ + + for (fd = delete_ifd; fd < orig_sym_hdr.ifdMax; fd++) + { + register FDR *fd_ptr = ORIG_FILES (fd); + register char *filename = ORIG_LSTRS (fd_ptr->issBase + fd_ptr->rss); + register SYMR *sym_start; + register SYMR *sym; + register SYMR *sym_end_p1; + register PDR *proc_start; + register PDR *proc; + register PDR *proc_end_p1; + + /* file support itself. */ + add_file (filename, filename + strlen (filename)); + cur_file_ptr->orig_fdr = fd_ptr; + + /* Copy stuff that's just passed through (such as line #'s) */ + cur_file_ptr->fdr.adr = fd_ptr->adr; + cur_file_ptr->fdr.ilineBase = fd_ptr->ilineBase; + cur_file_ptr->fdr.cline = fd_ptr->cline; + cur_file_ptr->fdr.rfdBase = fd_ptr->rfdBase; + cur_file_ptr->fdr.crfd = fd_ptr->crfd; + cur_file_ptr->fdr.cbLineOffset = fd_ptr->cbLineOffset; + cur_file_ptr->fdr.cbLine = fd_ptr->cbLine; + cur_file_ptr->fdr.fMerge = fd_ptr->fMerge; + cur_file_ptr->fdr.fReadin = fd_ptr->fReadin; + cur_file_ptr->fdr.glevel = fd_ptr->glevel; + + if (debug) + fprintf (stderr, "\thash\tstart, filename %s\n", filename); + + /* For each of the static and global symbols defined, add them + to the hash table of original symbols, so we can look up + their values. */ + + sym_start = ORIG_LSYMS (fd_ptr->isymBase); + sym_end_p1 = sym_start + fd_ptr->csym; + for (sym = sym_start; sym < sym_end_p1; sym++) + { + switch ((st_t) sym->st) + { + default: + break; + + case st_Global: + case st_Static: + case st_Label: + case st_Proc: + case st_StaticProc: + { + auto symint_t hash_index; + register char *str = ORIG_LSTRS (fd_ptr->issBase + sym->iss); + register Size_t len = strlen (str); + register shash_t *shash_ptr = hash_string (str, + (Ptrdiff_t)len, + &orig_str_hash[0], + &hash_index); + + if (shash_ptr != (shash_t *)0) + error ("internal error, %s is already in original symbol table", str); + + else + { + shash_ptr = (shash_t *) allocate_word8 (); + shash_ptr->next = orig_str_hash[hash_index]; + orig_str_hash[hash_index] = shash_ptr; + + shash_ptr->len = len; + shash_ptr->index = indexNil; + shash_ptr->string = str; + shash_ptr->sym_ptr = sym; + } + } + } + } + + if (debug) + { + fprintf (stderr, "\thash\tdone, filename %s\n", filename); + fprintf (stderr, "\tproc\tstart, filename %s\n", filename); + } + + /* Go through each of the procedures in this file, and add the + procedure pointer to the hash entry for the given name. */ + + proc_start = ORIG_PROCS (fd_ptr->ipdFirst); + proc_end_p1 = proc_start + fd_ptr->cpd; + for (proc = proc_start; proc < proc_end_p1; proc++) + { + register SYMR *proc_sym = ORIG_LSYMS (fd_ptr->isymBase + proc->isym); + register char *str = ORIG_LSTRS (fd_ptr->issBase + proc_sym->iss); + register Size_t len = strlen (str); + register shash_t *shash_ptr = hash_string (str, + (Ptrdiff_t)len, + &orig_str_hash[0], + (symint_t *)0); + + if (shash_ptr == (shash_t *)0) + error ("internal error, function %s is not in original symbol table", str); + + else + shash_ptr->proc_ptr = proc; + } + + if (debug) + fprintf (stderr, "\tproc\tdone, filename %s\n", filename); + + } + cur_file_ptr = first_file; + + + /* Copy all of the object file up to the symbol table. Originally + we were going to use ftruncate, but that doesn't seem to work + on Ultrix 3.1.... */ + + if (fseek (obj_in_stream, (long)0, SEEK_SET) != 0) + pfatal_with_name (obj_in_name); + + if (fseek (object_stream, (long)0, SEEK_SET) != 0) + pfatal_with_name (object_name); + + for (remaining = orig_file_header.f_symptr; + remaining > 0; + remaining -= num_write) + { + num_write = (remaining <= sizeof (buffer)) ? remaining : sizeof (buffer); + sys_read = fread ((PTR_T) buffer, 1, num_write, obj_in_stream); + if (sys_read <= 0) + pfatal_with_name (obj_in_name); + + else if (sys_read != num_write) + fatal ("Wanted to read %d bytes from %s, system returned %d", + num_write, + obj_in_name, + sys_read); + + sys_write = fwrite (buffer, 1, num_write, object_stream); + if (sys_write <= 0) + pfatal_with_name (object_name); + + else if (sys_write != num_write) + fatal ("Wrote %d bytes to %s, system returned %d", + num_write, + object_name, + sys_write); + } +} + + +/* Ye olde main program. */ + +int +main (argc, argv) + int argc; + char *argv[]; +{ + int iflag = 0; + char *p = strrchr (argv[0], '/'); + char *num_end; + int option; + + progname = (p != 0) ? p+1 : argv[0]; + + (void) signal (SIGSEGV, catch_signal); + (void) signal (SIGBUS, catch_signal); + (void) signal (SIGABRT, catch_signal); + +#if !defined(__SABER__) && !defined(lint) + if (sizeof (efdr_t) > PAGE_USIZE) + fatal ("Efdr_t has a sizeof %d bytes, when it should be less than %d", + sizeof (efdr_t), + PAGE_USIZE); + + if (sizeof (page_t) != PAGE_USIZE) + fatal ("Page_t has a sizeof %d bytes, when it should be %d", + sizeof (page_t), + PAGE_USIZE); + + if (sizeof (word8_t) != 8 * sizeof (symint_t)) + fatal ("Word8_t has a sizeof %d bytes, when it should be %d", + sizeof (word8_t), + 8 * sizeof (symint_t)); +#endif + + int_type_info = type_info_init; + int_type_info.basic_type = bt_Int; + + void_type_info = type_info_init; + void_type_info.basic_type = bt_Void; + + while ((option = getopt (argc, argv, "d:i:I:o:v")) != EOF) + switch (option) + { + default: + had_errors++; + break; + + case 'd': + debug = strtol (optarg, &num_end, 0); + if ((unsigned)debug > 4 || num_end == optarg) + had_errors++; + + break; + + case 'I': + if (rename_output || obj_in_name != (char *)0) + had_errors++; + else + rename_output = 1; + + /* fall through to 'i' case. */ + + case 'i': + if (obj_in_name == (char *)0) + { + obj_in_name = optarg; + iflag++; + } + else + had_errors++; + break; + + case 'o': + if (object_name == (char *)0) + object_name = optarg; + else + had_errors++; + break; + + case 'v': + version++; + break; + } + + if (obj_in_name == (char *)0 && optind <= argc - 2) + obj_in_name = argv[--argc]; + + if (object_name == (char *)0 && optind <= argc - 2) + object_name = argv[--argc]; + + /* If there is an output name, but no input name use + the same file for both, deleting the name between + opening it for input and opening it for output. */ + if (obj_in_name == (char *)0 && object_name != (char *)0) + { + obj_in_name = object_name; + delete_input = 1; + } + + if (object_name == (char *)0 || had_errors || optind != argc - 1) + { + fprintf (stderr, "Calling Sequence:\n"); + fprintf (stderr, "\tmips-tfile [-d ] [-v] [-i ] -o (or)\n"); + fprintf (stderr, "\tmips-tfile [-d ] [-v] [-I ] -o (or)\n"); + fprintf (stderr, "\tmips-tfile [-d ] [-v] \n"); + fprintf (stderr, "\n"); + fprintf (stderr, "Debug levels are:\n"); + fprintf (stderr, " 1\tGeneral debug + trace functions/blocks.\n"); + fprintf (stderr, " 2\tDebug level 1 + trace externals.\n"); + fprintf (stderr, " 3\tDebug level 2 + trace all symbols.\n"); + fprintf (stderr, " 4\tDebug level 3 + trace memory allocations.\n"); + return 1; + } + + + if (version) + { + extern char *version_string; + fprintf (stderr, "mips-tfile version %s", version_string); +#ifdef TARGET_VERSION + TARGET_VERSION; +#endif + fputc ('\n', stderr); + } + + if (obj_in_name == (char *)0) + obj_in_name = object_name; + + if (rename_output && rename (object_name, obj_in_name) != 0) + { + char *buffer = (char *) allocate_multiple_pages (4); + int len; + int len2; + int in_fd; + int out_fd; + + /* Rename failed, copy input file */ + in_fd = open (object_name, O_RDONLY, 0666); + if (in_fd < 0) + pfatal_with_name (object_name); + + out_fd = open (obj_in_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (out_fd < 0) + pfatal_with_name (obj_in_name); + + while ((len = read (in_fd, buffer, 4*PAGE_SIZE)) > 0) + { + len2 = write (out_fd, buffer, len); + if (len2 < 0) + pfatal_with_name (object_name); + + if (len != len2) + fatal ("wrote %d bytes to %s, expected to write %d", len2, obj_in_name, len); + } + + free_multiple_pages (buffer, 4); + + if (len < 0) + pfatal_with_name (object_name); + + if (close (in_fd) < 0) + pfatal_with_name (object_name); + + if (close (out_fd) < 0) + pfatal_with_name (obj_in_name); + } + + /* Must open input before output, since the output may be the same file, and + we need to get the input handle before truncating it. */ + obj_in_stream = fopen (obj_in_name, "r"); + if (obj_in_stream == (FILE *)0) + pfatal_with_name (obj_in_name); + + if (delete_input && unlink (obj_in_name) != 0) + pfatal_with_name (obj_in_name); + + object_stream = fopen (object_name, "w"); + if (object_stream == (FILE *)0) + pfatal_with_name (object_name); + + if (strcmp (argv[optind], "-") != 0) + { + input_name = argv[optind]; + if (freopen (argv[optind], "r", stdin) != stdin) + pfatal_with_name (argv[optind]); + } + + +#ifdef _IOFBF + /* Try to prevent stdio from malloc'ing memory for the buffers. At the + same time, increase the size of mips' stdio buffers. */ + + setvbuf (object_stream, (char *) allocate_multiple_pages (2), _IOFBF, 2*PAGE_SIZE); + setvbuf (obj_in_stream, (char *) allocate_multiple_pages (2), _IOFBF, 2*PAGE_SIZE); + setvbuf (stdin, (char *) allocate_multiple_pages (2), _IOFBF, 2*PAGE_SIZE); + setvbuf (stdout, (char *) allocate_multiple_pages (2), _IOFBF, 2*PAGE_SIZE); + setvbuf (stderr, (char *) allocate_multiple_pages (2), _IOLBF, 2*PAGE_SIZE); +#endif + + copy_object (); /* scan & copy object file */ + parse_input (); /* scan all of input */ + + update_headers (); /* write out tfile */ + write_object (); + + return (had_errors) ? 1 : 0; +} + + +/* Catch a signal and exit without dumping core. */ + +STATIC void +catch_signal (signum) + int signum; +{ + extern char *sys_siglist[NSIG + 1]; + + (void) signal (signum, SIG_DFL); /* just in case... */ + fatal (sys_siglist[signum]); +} + +/* Print a fatal error message. NAME is the text. + Also include a system error message based on `errno'. */ + +void +pfatal_with_name (msg) + char *msg; +{ + int save_errno = errno; /* just in case.... */ + if (line_number > 0) + fprintf (stderr, "%s, %s:%ld ", progname, input_name, line_number); + else + fprintf (stderr, "%s:", progname); + + errno = save_errno; + if (errno == 0) + fprintf (stderr, "[errno = 0] %s\n", msg); + else + perror (msg); + + exit (1); +} + + +/* Procedure to abort with an out of bounds error message. It has + type int, so it can be used with an ?: expression within the + ORIG_xxx macros, but the function never returns. */ + +static int +out_of_bounds (index, max, str, prog_line) + symint_t index; /* index that is out of bounds */ + symint_t max; /* maximum index */ + const char *str; /* string to print out */ + int prog_line; /* line number within mips-tfile.c */ +{ + if (index < max) /* just in case */ + return 0; + + fprintf (stderr, "%s, %s:%ld index %u is out of bounds for %s, max is %u, mips-tfile.c line# %d\n", + progname, input_name, line_number, index, str, max, prog_line); + + exit (1); + return 0; /* turn off warning messages */ +} + + +/* Allocate a cluster of pages. USE_MALLOC says that malloc does not + like sbrk's behind it's back (or sbrk isn't available). If we use + sbrk, we assume it gives us zeroed pages. */ + +#ifndef MALLOC_CHECK +#ifdef USE_MALLOC + +STATIC page_t * +allocate_cluster (npages) + Size_t npages; +{ + register page_t *value = (page_t *) calloc (npages, PAGE_USIZE); + + if (value == 0) + fatal ("Virtual memory exhausted."); + + if (debug > 3) + fprintf (stderr, "\talloc\tnpages = %d, value = 0x%.8x\n", npages, value); + + return value; +} + +#else /* USE_MALLOC */ + +STATIC page_t * +allocate_cluster (npages) + Size_t npages; +{ + register page_t *ptr = (page_t *) sbrk (0); /* current sbreak */ + unsigned long offset = ((unsigned long) ptr) & (PAGE_SIZE - 1); + + if (offset != 0) /* align to a page boundary */ + { + if (sbrk (PAGE_USIZE - offset) == (char *)-1) + pfatal_with_name ("allocate_cluster"); + + ptr = (page_t *) (((char *)ptr) + PAGE_SIZE - offset); + } + + if (sbrk (npages * PAGE_USIZE) == (char *)-1) + pfatal_with_name ("allocate_cluster"); + + if (debug > 3) + fprintf (stderr, "\talloc\tnpages = %d, value = 0x%.8x\n", npages, ptr); + + return ptr; +} + +#endif /* USE_MALLOC */ + + +static page_t *cluster_ptr = NULL; +static unsigned pages_left = 0; + +#endif /* MALLOC_CHECK */ + + +/* Allocate some pages (which is initialized to 0). */ + +STATIC page_t * +allocate_multiple_pages (npages) + Size_t npages; +{ +#ifndef MALLOC_CHECK + if (pages_left == 0 && npages < MAX_CLUSTER_PAGES) + { + pages_left = MAX_CLUSTER_PAGES; + cluster_ptr = allocate_cluster (MAX_CLUSTER_PAGES); + } + + if (npages <= pages_left) + { + page_t *ptr = cluster_ptr; + cluster_ptr += npages; + pages_left -= npages; + return ptr; + } + + return allocate_cluster (npages); + +#else /* MALLOC_CHECK */ + return (page_t *) xcalloc (npages, PAGE_SIZE); + +#endif /* MALLOC_CHECK */ +} + + +/* Release some pages. */ + +STATIC void +free_multiple_pages (page_ptr, npages) + page_t *page_ptr; + Size_t npages; +{ +#ifndef MALLOC_CHECK + if (pages_left == 0) + { + cluster_ptr = page_ptr; + pages_left = npages; + } + + else if ((page_ptr + npages) == cluster_ptr) + { + cluster_ptr -= npages; + pages_left += npages; + } + + /* otherwise the page is not freed. If more than call is + done, we probably should worry about it, but at present, + the free pages is done right after an allocate. */ + +#else /* MALLOC_CHECK */ + free ((char *) page_ptr); + +#endif /* MALLOC_CHECK */ +} + + +/* Allocate one page (which is initialized to 0). */ + +STATIC page_t * +allocate_page __proto((void)) +{ +#ifndef MALLOC_CHECK + if (pages_left == 0) + { + pages_left = MAX_CLUSTER_PAGES; + cluster_ptr = allocate_cluster (MAX_CLUSTER_PAGES); + } + + pages_left--; + return cluster_ptr++; + +#else /* MALLOC_CHECK */ + return (page_t *) xcalloc (1, PAGE_SIZE); + +#endif /* MALLOC_CHECK */ +} + + +/* Allocate and release 4 word quanities. */ + +#ifndef MALLOC_CHECK +static word8_t *word8_free_list = (word8_t *)0; +#endif + +STATIC word8_t * +allocate_word8 __proto((void)) +{ +#ifndef MALLOC_CHECK + register word8_t *ptr = word8_free_list; + if (ptr != (word8_t *)0) + word8_free_list = ptr->prev; + else + { + register int i; + register page_t *page_ptr; + + page_ptr = allocate_page (); + ptr = &page_ptr->word8[0]; + for (i = 0; i < (PAGE_SIZE / sizeof (word8_t)) - 1; i++) + { + ptr->prev = word8_free_list; + word8_free_list = ptr; + ptr++; + } + } + + ptr->words[0] = 0; + ptr->words[1] = 0; + ptr->words[2] = 0; + ptr->words[3] = 0; + ptr->words[4] = 0; + ptr->words[5] = 0; + ptr->words[6] = 0; + ptr->words[7] = 0; + return ptr; + +#else /* MALLOC_CHECK */ + return (word8_t *) xcalloc (1, sizeof (word8_t)); + +#endif /* MALLOC_CHECK */ +} + +STATIC void +free_word8 (ptr) + word8_t *ptr; +{ +#ifndef MALLOC_CHECK + ptr->prev = word8_free_list; + word8_free_list = ptr; + +#else /* MALLOC_CHECK */ + xfree ((PTR_T)ptr); + +#endif /* MALLOC_CHECK */ +} + +#endif /* MIPS_DEBUGGING defined */ + + +/* Output an error message and exit */ + +/*VARARGS*/ +void +fatal (va_alist) + va_dcl +{ + va_list ap; + char *format; + + if (line_number > 0) + fprintf (stderr, "%s, %s:%ld ", progname, input_name, line_number); + else + fprintf (stderr, "%s:", progname); + + va_start(ap); + format = va_arg (ap, char *); + vfprintf (stderr, format, ap); + va_end (ap); + fprintf (stderr, "\n"); + if (line_number > 0) + fprintf (stderr, "line:\t%s\n", cur_line_start); + + saber_stop (); + exit (1); +} + +/*VARARGS*/ +void +error (va_alist) + va_dcl +{ + va_list ap; + char *format; + + if (line_number > 0) + fprintf (stderr, "%s, %s:%ld ", progname, input_name, line_number); + else + fprintf (stderr, "%s:", progname); + + va_start(ap); + format = va_arg (ap, char *); + vfprintf (stderr, format, ap); + fprintf (stderr, "\n"); + if (line_number > 0) + fprintf (stderr, "line:\t%s\n", cur_line_start); + + had_errors++; + va_end (ap); + + saber_stop (); +} + +/* More 'friendly' abort that prints the line and file. + config.h can #define abort fancy_abort if you like that sort of thing. */ + +void +fancy_abort () +{ + fatal ("Internal abort."); +} + + +/* When `malloc.c' is compiled with `rcheck' defined, + it calls this function to report clobberage. */ + +void +botch (s) + const char *s; +{ + fatal (s); +} + +/* Same as `malloc' but report error if no memory available. */ + +PTR_T +xmalloc (size) + Size_t size; +{ + register PTR_T value = malloc (size); + if (value == 0) + fatal ("Virtual memory exhausted."); + + if (debug > 3) + fprintf (stderr, "\tmalloc\tptr = 0x%.8x, size = %10u\n", value, size); + + return value; +} + +/* Same as `calloc' but report error if no memory available. */ + +PTR_T +xcalloc (size1, size2) + Size_t size1, size2; +{ + register PTR_T value = calloc (size1, size2); + if (value == 0) + fatal ("Virtual memory exhausted."); + + if (debug > 3) + fprintf (stderr, "\tcalloc\tptr = 0x%.8x, size1 = %10u, size2 = %10u [%u]\n", + value, size1, size2, size1+size2); + + return value; +} + +/* Same as `realloc' but report error if no memory available. */ + +PTR_T +xrealloc (ptr, size) + PTR_T ptr; + Size_t size; +{ + register PTR_T result = realloc (ptr, size); + if (!result) + fatal ("Virtual memory exhausted."); + + if (debug > 3) + fprintf (stderr, "\trealloc\tptr = 0x%.8x, size = %10u, orig = 0x%.8x\n", + result, size, ptr); + + return result; +} + +void +xfree (ptr) + PTR_T ptr; +{ + if (debug > 3) + fprintf (stderr, "\tfree\tptr = 0x%.8x\n", ptr); + + free (ptr); +}