|  | /* ECOFF debugging support. | 
|  | Copyright (C) 1993-2023 Free Software Foundation, Inc. | 
|  | Contributed by Cygnus Support. | 
|  | This file was put together by Ian Lance Taylor <ian@cygnus.com>.  A | 
|  | good deal of it comes directly from mips-tfile.c, by Michael | 
|  | Meissner <meissner@osf.org>. | 
|  |  | 
|  | This file is part of GAS. | 
|  |  | 
|  | GAS 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 3, or (at your option) | 
|  | any later version. | 
|  |  | 
|  | GAS 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 GAS; see the file COPYING.  If not, write to the Free | 
|  | Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA | 
|  | 02110-1301, USA.  */ | 
|  |  | 
|  | #include "as.h" | 
|  |  | 
|  | /* This file is compiled conditionally for those targets which use | 
|  | ECOFF debugging information (e.g., MIPS ELF, Alpha ECOFF).  */ | 
|  |  | 
|  | #include "ecoff.h" | 
|  |  | 
|  | #ifdef ECOFF_DEBUGGING | 
|  |  | 
|  | #include "coff/internal.h" | 
|  | #include "coff/symconst.h" | 
|  | #include "aout/stab_gnu.h" | 
|  | #include "filenames.h" | 
|  | #include "safe-ctype.h" | 
|  |  | 
|  | /* Why isn't this in coff/sym.h?  */ | 
|  | #define ST_RFDESCAPE 0xfff | 
|  |  | 
|  | /* This file constructs the information used by the ECOFF debugging | 
|  | format.  It just builds a large block of data. | 
|  |  | 
|  | We support both ECOFF style debugging and stabs debugging (the | 
|  | stabs symbols are encapsulated in ECOFF symbols).  This should let | 
|  | us handle anything the compiler might throw at us.  */ | 
|  |  | 
|  | /* Here is a brief description of the MIPS ECOFF symbol table, by | 
|  | Michael Meissner.  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 indices 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	  -- beginning 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 <stdio.h> | 
|  |  | 
|  | 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 | 
|  | Auxiliary 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 } | 
|  | */ | 
|  |  | 
|  | /* Redefinition 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,	/* beginning of block */ | 
|  | st_End	= stEnd,	/* end (of anything) */ | 
|  | st_Member	= stMember,	/* member (of anything	- struct/union/enum */ | 
|  | st_Typedef	= stTypedef,	/* type definition */ | 
|  | st_File	= stFile,	/* file name */ | 
|  | st_RegReloc	= stRegReloc,	/* register relocation */ | 
|  | st_Forward	= stForward,	/* forwarding address */ | 
|  | st_StaticProc	= stStaticProc,	/* load time only static procs */ | 
|  | st_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-coercion SER */ | 
|  | st_Max	= stMax		/* max type+1 */ | 
|  | } st_t; | 
|  |  | 
|  | /* Redefinition of type qualifiers.  */ | 
|  |  | 
|  | typedef enum tq { | 
|  | tq_Nil	= tqNil,	/* bt is what you see */ | 
|  | tq_Ptr	= tqPtr,	/* pointer */ | 
|  | tq_Proc	= tqProc,	/* procedure */ | 
|  | tq_Array	= tqArray,	/* duh */ | 
|  | tq_Far	= tqFar,	/* longer addressing - 8086/8 land */ | 
|  | tq_Vol	= tqVol,	/* volatile */ | 
|  | tq_Max	= tqMax		/* Max type qualifier+1 */ | 
|  | } tq_t; | 
|  |  | 
|  | /* Redefinition of basic types.  */ | 
|  |  | 
|  | typedef enum bt { | 
|  | bt_Nil	= btNil,	/* undefined */ | 
|  | bt_Adr	= btAdr,	/* address - integer same size as pointer */ | 
|  | bt_Char	= btChar,	/* character */ | 
|  | bt_UChar	= btUChar,	/* unsigned character */ | 
|  | bt_Short	= btShort,	/* short */ | 
|  | bt_UShort	= btUShort,	/* unsigned short */ | 
|  | bt_Int	= btInt,	/* int */ | 
|  | bt_UInt	= btUInt,	/* unsigned int */ | 
|  | bt_Long	= btLong,	/* long */ | 
|  | bt_ULong	= btULong,	/* unsigned long */ | 
|  | bt_Float	= btFloat,	/* float (real) */ | 
|  | bt_Double	= btDouble,	/* Double (real) */ | 
|  | bt_Struct	= btStruct,	/* Structure (Record) */ | 
|  | bt_Union	= btUnion,	/* Union (variant) */ | 
|  | bt_Enum	= btEnum,	/* Enumerated */ | 
|  | bt_Typedef	= btTypedef,	/* defined via a typedef, isymRef points */ | 
|  | bt_Range	= btRange,	/* subrange of int */ | 
|  | bt_Set	= btSet,	/* pascal sets */ | 
|  | bt_Complex	= btComplex,	/* fortran complex */ | 
|  | bt_DComplex	= btDComplex,	/* fortran double complex */ | 
|  | bt_Indirect	= btIndirect,	/* forward or unnamed typedef */ | 
|  | bt_FixedDec	= btFixedDec,	/* Fixed Decimal */ | 
|  | bt_FloatDec	= btFloatDec,	/* Float Decimal */ | 
|  | bt_String	= btString,	/* Varying Length Character String */ | 
|  | bt_Bit	= btBit,	/* Aligned Bit String */ | 
|  | bt_Picture	= btPicture,	/* Picture */ | 
|  | bt_Void	= btVoid,	/* Void */ | 
|  | bt_Max	= btMax		/* Max basic type+1 */ | 
|  | } bt_t; | 
|  |  | 
|  | #define N_TQ itqMax | 
|  |  | 
|  | /* 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; | 
|  |  | 
|  | /* Types of different sized allocation requests.  */ | 
|  | enum alloc_type { | 
|  | alloc_type_none,		/* dummy value */ | 
|  | alloc_type_scope,		/* nested scopes linked list */ | 
|  | alloc_type_vlinks,		/* glue linking pages in varray */ | 
|  | alloc_type_shash,		/* string hash element */ | 
|  | alloc_type_thash,		/* type hash element */ | 
|  | alloc_type_tag,		/* struct/union/tag element */ | 
|  | alloc_type_forward,		/* element to hold unknown tag */ | 
|  | alloc_type_thead,		/* head of type hash list */ | 
|  | alloc_type_varray,		/* general varray allocation */ | 
|  | alloc_type_lineno,		/* line number list */ | 
|  | alloc_type_last		/* last+1 element for array bounds */ | 
|  | }; | 
|  |  | 
|  | /* Types of auxiliary type information.  */ | 
|  | enum aux_type { | 
|  | aux_tir,			/* TIR type information */ | 
|  | aux_rndx,			/* relative index into symbol table */ | 
|  | aux_dnLow,			/* low dimension */ | 
|  | aux_dnHigh,			/* high dimension */ | 
|  | aux_isym,			/* symbol table index (end of proc) */ | 
|  | aux_iss,			/* index into string space (not used) */ | 
|  | aux_width,			/* width for non-default sized struc fields */ | 
|  | aux_count			/* count of ranges for variant arm */ | 
|  | }; | 
|  |  | 
|  | /* 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, 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).  */ | 
|  |  | 
|  | /* FIXME: Yes, there can be such strings while emitting C++ class debug | 
|  | info.  Templates are the offender here, the test case in question | 
|  | having a mangled class name of | 
|  |  | 
|  | t7rb_tree4Z4xkeyZt4pair2ZC4xkeyZt7xsocket1Z4UserZt9select1st2Zt4pair\ | 
|  | 2ZC4xkeyZt7xsocket1Z4UserZ4xkeyZt4less1Z4xkey | 
|  |  | 
|  | Repeat that a couple dozen times while listing the class members and | 
|  | you've got strings over 4k.  Hack around this for now by increasing | 
|  | the page size.  A proper solution would abandon this structure scheme | 
|  | certainly for very large strings, and possibly entirely.  */ | 
|  |  | 
|  | #ifndef PAGE_SIZE | 
|  | #define PAGE_SIZE (8*1024)	/* size of varray pages */ | 
|  | #endif | 
|  |  | 
|  | #define PAGE_USIZE ((unsigned long) PAGE_SIZE) | 
|  |  | 
|  | #ifndef MAX_CLUSTER_PAGES	/* # pages to get from system */ | 
|  | #define MAX_CLUSTER_PAGES 63 | 
|  | #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 */ | 
|  | struct scope	*free;		/* free list pointer */ | 
|  | struct localsym *lsym;	/* pointer to local symbol node */ | 
|  | st_t		 type;		/* type of the node */ | 
|  | } scope_t; | 
|  |  | 
|  | /* For a local symbol we store a gas symbol as well as the debugging | 
|  | information we generate.  The gas symbol will be NULL if this is | 
|  | only a debugging symbol.  */ | 
|  | typedef struct localsym { | 
|  | const char *name;		/* symbol name */ | 
|  | symbolS *as_sym;		/* symbol as seen by gas */ | 
|  | bfd_vma addend;		/* addend to as_sym value */ | 
|  | struct efdr *file_ptr;	/* file pointer */ | 
|  | struct ecoff_proc *proc_ptr;	/* proc pointer */ | 
|  | struct localsym *begin_ptr;	/* symbol at start of block */ | 
|  | struct ecoff_aux *index_ptr;	/* index value to be filled in */ | 
|  | struct forward *forward_ref;	/* forward references to this symbol */ | 
|  | long sym_index;		/* final symbol index */ | 
|  | EXTR ecoff_sym;		/* ECOFF debugging symbol */ | 
|  | } localsym_t; | 
|  |  | 
|  | /* For aux information we keep the type and the data.  */ | 
|  | typedef struct ecoff_aux { | 
|  | enum aux_type type;		/* aux type */ | 
|  | AUXU data;			/* aux data */ | 
|  | } aux_t; | 
|  |  | 
|  | /* For a procedure we store the gas symbol as well as the PDR | 
|  | debugging information.  */ | 
|  | typedef struct ecoff_proc { | 
|  | localsym_t *sym;		/* associated symbol */ | 
|  | PDR pdr;			/* ECOFF debugging info */ | 
|  | } proc_t; | 
|  |  | 
|  | /* Number of proc_t structures allocated.  */ | 
|  | static unsigned long proc_cnt; | 
|  |  | 
|  | /* Forward reference list for tags referenced, but not yet defined.  */ | 
|  | typedef struct forward { | 
|  | struct forward *next;		/* next forward reference */ | 
|  | struct forward *free;		/* free list pointer */ | 
|  | aux_t		 *ifd_ptr;	/* pointer to store file index */ | 
|  | aux_t		 *index_ptr;	/* pointer to store symbol index */ | 
|  | } 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 tag	 *free;		/* free list pointer */ | 
|  | 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 */ | 
|  | localsym_t	 *sym;		/* file's local symbols */ | 
|  | } tag_t; | 
|  |  | 
|  | /* Head of a block's linked list of tags.  */ | 
|  | typedef struct thead { | 
|  | struct thead	*prev;		/* previous block */ | 
|  | struct thead	*free;		/* free list pointer */ | 
|  | struct tag	*first_tag;	/* first tag in block defined */ | 
|  | } thead_t; | 
|  |  | 
|  | /* Union containing pointers to each the small structures which are freed up.  */ | 
|  | typedef union small_free { | 
|  | scope_t	*f_scope;	/* scope structure */ | 
|  | thead_t	*f_thead;	/* tag head structure */ | 
|  | tag_t		*f_tag;		/* tag element structure */ | 
|  | forward_t	*f_forward;	/* forward tag reference */ | 
|  | } small_free_t; | 
|  |  | 
|  | /* String hash table entry.  */ | 
|  |  | 
|  | typedef struct shash { | 
|  | char		*string;	/* string we are hashing */ | 
|  | symint_t	 indx;		/* index within string table */ | 
|  | EXTR		*esym_ptr;	/* global symbol pointer */ | 
|  | localsym_t	*sym_ptr;	/* local symbol pointer */ | 
|  | localsym_t	*end_ptr;	/* symbol pointer to end block */ | 
|  | tag_t		*tag_ptr;	/* tag pointer */ | 
|  | proc_t	*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.  */ | 
|  |  | 
|  | #define HASHBITS 30 | 
|  |  | 
|  | #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	 indx;		/* index within string table */ | 
|  | } thash_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		 fake;		/* whether this is faked .file */ | 
|  | 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 */ | 
|  | htab_t	str_hash;	/* string hash table */ | 
|  | thash_t	*thash_head[THASH_SIZE]; | 
|  | } efdr_t; | 
|  |  | 
|  | /* Pre-initialized extended file structure.  */ | 
|  | static const 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) */ | 
|  | TARGET_BYTES_BIG_ENDIAN,  /* fBigendian:	if 1, compiled on big endian machine */ | 
|  | 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,			/* fake:	whether this is a faked .file */ | 
|  | 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 (localsym_t),	/* symbols:	local symbols varray */ | 
|  | INIT_VARRAY (proc_t),	/* procs:	procedure varray */ | 
|  | INIT_VARRAY (aux_t),	/* aux_syms:	auxiliary symbols varray */ | 
|  |  | 
|  | (struct efdr *)0,	/* next_file:	next file structure */ | 
|  |  | 
|  | (htab_t)0,		/* str_hash:	string hash table */ | 
|  | { 0 },		/* thash_head:	type hash table */ | 
|  | }; | 
|  |  | 
|  | static efdr_t *first_file;			/* first file descriptor */ | 
|  | static efdr_t **last_file_ptr = &first_file;	/* file descriptor tail */ | 
|  |  | 
|  | /* Line number information is kept in a list until the assembly is | 
|  | finished.  */ | 
|  | typedef struct lineno_list { | 
|  | struct lineno_list *next;	/* next element in list */ | 
|  | efdr_t *file;			/* file this line is in */ | 
|  | proc_t *proc;			/* procedure this line is in */ | 
|  | fragS *frag;			/* fragment this line number is in */ | 
|  | unsigned long paddr;		/* offset within fragment */ | 
|  | long lineno;			/* actual line number */ | 
|  | } lineno_list_t; | 
|  |  | 
|  | static lineno_list_t *first_lineno; | 
|  | static lineno_list_t *last_lineno; | 
|  | static lineno_list_t **last_lineno_ptr = &first_lineno; | 
|  |  | 
|  | /* Sometimes there will be some .loc statements before a .ent.  We | 
|  | keep them in this list so that we can fill in the procedure pointer | 
|  | after we see the .ent.  */ | 
|  | static lineno_list_t *noproc_lineno; | 
|  |  | 
|  | /* 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)	     ]; | 
|  | proc_t	proc	[ PAGE_SIZE / sizeof (proc_t)	     ]; | 
|  | localsym_t	sym	[ PAGE_SIZE / sizeof (localsym_t)    ]; | 
|  | aux_t		aux	[ PAGE_SIZE / sizeof (aux_t)	     ]; | 
|  | DNR		dense	[ PAGE_SIZE / sizeof (DNR)	     ]; | 
|  | scope_t	scope	[ PAGE_SIZE / sizeof (scope_t)	     ]; | 
|  | vlinks_t	vlinks	[ PAGE_SIZE / sizeof (vlinks_t)	     ]; | 
|  | shash_t	shash	[ PAGE_SIZE / sizeof (shash_t)	     ]; | 
|  | thash_t	thash	[ PAGE_SIZE / sizeof (thash_t)	     ]; | 
|  | tag_t		tag	[ PAGE_SIZE / sizeof (tag_t)	     ]; | 
|  | forward_t	forward	[ PAGE_SIZE / sizeof (forward_t)     ]; | 
|  | thead_t	thead	[ PAGE_SIZE / sizeof (thead_t)	     ]; | 
|  | lineno_list_t	lineno	[ PAGE_SIZE / sizeof (lineno_list_t) ]; | 
|  | } page_type; | 
|  |  | 
|  | /* Structure holding allocation information for small sized structures.  */ | 
|  | typedef struct alloc_info { | 
|  | char		*alloc_name;	/* name of this allocation type (must be first) */ | 
|  | page_type	*cur_page;	/* current page being allocated from */ | 
|  | small_free_t	 free_list;	/* current free list if any */ | 
|  | int		 unallocated;	/* number of elements unallocated on page */ | 
|  | int		 total_alloc;	/* total number of allocations */ | 
|  | int		 total_free;	/* total number of frees */ | 
|  | int		 total_pages;	/* total number of pages allocated */ | 
|  | } alloc_info_t; | 
|  |  | 
|  | /* Type information collected together.  */ | 
|  | typedef struct type_info { | 
|  | bt_t	      basic_type;		/* basic type */ | 
|  | int	      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 */ | 
|  | 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 const 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 */ | 
|  | {					/* 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 hash table for the tags table and global table for file | 
|  | descriptors.  */ | 
|  |  | 
|  | static varray_t file_desc = INIT_VARRAY (efdr_t); | 
|  |  | 
|  | static htab_t tag_hash; | 
|  |  | 
|  | /* 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 symbolS *last_func_sym_value; | 
|  |  | 
|  | /* 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. | 
|  |  | 
|  | It would make sense for the .type and .scl directives to use the | 
|  | ECOFF numbers directly, rather than using the COFF numbers and | 
|  | mapping them.  Unfortunately, this is historically what mips-tfile | 
|  | expects, and changing gcc now would be a considerable pain (the | 
|  | native compiler generates debugging information internally, rather | 
|  | than via the assembler, so it will never use .type or .scl).  */ | 
|  |  | 
|  | static const bt_t map_coff_types[] = { | 
|  | 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 const sc_t map_coff_storage[] = { | 
|  | 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 const st_t map_coff_sym_type[] = { | 
|  | 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 ??? */ | 
|  | }; | 
|  |  | 
|  | /* Keep track of different sized allocation requests.  */ | 
|  | static alloc_info_t alloc_counts[(int) alloc_type_last]; | 
|  |  | 
|  | /* Record whether we have seen any debugging information.  */ | 
|  | int ecoff_debugging_seen = 0; | 
|  |  | 
|  | /* Various statics.  */ | 
|  | static efdr_t  *cur_file_ptr	= (efdr_t *) 0;	/* current file desc. header */ | 
|  | static proc_t  *cur_proc_ptr	= (proc_t *) 0;	/* current procedure header */ | 
|  | static proc_t  *first_proc_ptr  = (proc_t *) 0; /* first procedure header */ | 
|  | static thead_t *top_tag_head	= (thead_t *) 0; /* top level tag head */ | 
|  | static thead_t *cur_tag_head	= (thead_t *) 0; /* current tag head */ | 
|  | #ifdef ECOFF_DEBUG | 
|  | static int	debug		= 0; 		/* trace functions */ | 
|  | #endif | 
|  | static int	stabs_seen	= 0;		/* != 0 if stabs have been seen */ | 
|  |  | 
|  | static int current_file_idx; | 
|  | static const char *current_stabs_filename; | 
|  |  | 
|  | /* Pseudo symbol to use when putting stabs into the symbol table.  */ | 
|  | #ifndef STABS_SYMBOL | 
|  | #define STABS_SYMBOL "@stabs" | 
|  | #endif | 
|  |  | 
|  | static char stabs_symbol[] = STABS_SYMBOL; | 
|  |  | 
|  | /* Prototypes for functions defined in this file.  */ | 
|  |  | 
|  | static void add_varray_page (varray_t *vp); | 
|  | static symint_t add_string (varray_t *vp, | 
|  | htab_t hash_tbl, | 
|  | const char *str, | 
|  | shash_t **ret_hash); | 
|  | static localsym_t *add_ecoff_symbol (const char *str, st_t type, | 
|  | sc_t storage, symbolS *sym, | 
|  | bfd_vma addend, symint_t value, | 
|  | symint_t indx); | 
|  | static symint_t add_aux_sym_symint (symint_t aux_word); | 
|  | static symint_t add_aux_sym_rndx (int file_index, symint_t sym_index); | 
|  | static symint_t add_aux_sym_tir (type_info_t *t, | 
|  | hash_state_t state, | 
|  | thash_t **hash_tbl); | 
|  | static tag_t *get_tag (const char *tag, localsym_t *sym, bt_t basic_type); | 
|  | static void add_unknown_tag (tag_t *ptag); | 
|  | static void add_procedure (char *func, int aent); | 
|  | static void add_file (const char *file_name, int indx, int fake); | 
|  | #ifdef ECOFF_DEBUG | 
|  | static char *sc_to_string (sc_t storage_class); | 
|  | static char *st_to_string (st_t symbol_type); | 
|  | #endif | 
|  | static void mark_stabs (int); | 
|  | static char *ecoff_add_bytes (char **buf, char **bufend, | 
|  | char *bufptr, unsigned long need); | 
|  | static unsigned long ecoff_padding_adjust | 
|  | (const struct ecoff_debug_swap *backend, char **buf, char **bufend, | 
|  | unsigned long offset, char **bufptrptr); | 
|  | static unsigned long ecoff_build_lineno | 
|  | (const struct ecoff_debug_swap *backend, char **buf, char **bufend, | 
|  | unsigned long offset, long *linecntptr); | 
|  | static unsigned long ecoff_build_symbols | 
|  | (const struct ecoff_debug_swap *backend, char **buf, char **bufend, | 
|  | unsigned long offset); | 
|  | static unsigned long ecoff_build_procs | 
|  | (const struct ecoff_debug_swap *backend, char **buf, char **bufend, | 
|  | unsigned long offset); | 
|  | static unsigned long ecoff_build_aux | 
|  | (const struct ecoff_debug_swap *backend, char **buf, char **bufend, | 
|  | unsigned long offset); | 
|  | static unsigned long ecoff_build_strings (char **buf, char **bufend, | 
|  | unsigned long offset, | 
|  | varray_t *vp); | 
|  | static unsigned long ecoff_build_ss | 
|  | (const struct ecoff_debug_swap *backend, char **buf, char **bufend, | 
|  | unsigned long offset); | 
|  | static unsigned long ecoff_build_fdr | 
|  | (const struct ecoff_debug_swap *backend, char **buf, char **bufend, | 
|  | unsigned long offset); | 
|  | static void ecoff_setup_ext (void); | 
|  | static page_type *allocate_cluster (unsigned long npages); | 
|  | static page_type *allocate_page (void); | 
|  | static scope_t *allocate_scope (void); | 
|  | static void free_scope (scope_t *ptr); | 
|  | static vlinks_t *allocate_vlinks (void); | 
|  | static shash_t *allocate_shash (void); | 
|  | static thash_t *allocate_thash (void); | 
|  | static tag_t *allocate_tag (void); | 
|  | static void free_tag (tag_t *ptr); | 
|  | static forward_t *allocate_forward (void); | 
|  | static thead_t *allocate_thead (void); | 
|  | static void free_thead (thead_t *ptr); | 
|  | static lineno_list_t *allocate_lineno_list (void); | 
|  |  | 
|  | /* This function should be called when the assembler starts up.  */ | 
|  |  | 
|  | void | 
|  | ecoff_read_begin_hook (void) | 
|  | { | 
|  | tag_hash = str_htab_create (); | 
|  | top_tag_head = allocate_thead (); | 
|  | top_tag_head->first_tag = (tag_t *) NULL; | 
|  | top_tag_head->free = (thead_t *) NULL; | 
|  | top_tag_head->prev = cur_tag_head; | 
|  | cur_tag_head = top_tag_head; | 
|  | } | 
|  |  | 
|  | /* This function should be called when a symbol is created.  */ | 
|  |  | 
|  | void | 
|  | ecoff_symbol_new_hook (symbolS *symbolP) | 
|  | { | 
|  | OBJ_SYMFIELD_TYPE *obj; | 
|  |  | 
|  | /* Make sure that we have a file pointer, but only if we have seen a | 
|  | file.  If we haven't seen a file, then this is a probably special | 
|  | symbol created by md_begin which may required special handling at | 
|  | some point.  Creating a dummy file with a dummy name is certainly | 
|  | wrong.  */ | 
|  | if (cur_file_ptr == (efdr_t *) NULL | 
|  | && seen_at_least_1_file ()) | 
|  | add_file ((const char *) NULL, 0, 1); | 
|  | obj = symbol_get_obj (symbolP); | 
|  | obj->ecoff_file = cur_file_ptr; | 
|  | obj->ecoff_symbol = NULL; | 
|  | obj->ecoff_extern_size = 0; | 
|  | } | 
|  |  | 
|  | void | 
|  | ecoff_symbol_clone_hook (symbolS *newsymP, symbolS *orgsymP) | 
|  | { | 
|  | OBJ_SYMFIELD_TYPE *n, *o; | 
|  |  | 
|  | n = symbol_get_obj (newsymP); | 
|  | o = symbol_get_obj (orgsymP); | 
|  | memcpy (n, o, sizeof *n); | 
|  | } | 
|  |  | 
|  | /* Add a page to a varray object.  */ | 
|  |  | 
|  | static void | 
|  | add_varray_page (varray_t *vp /* varray to add page to */) | 
|  | { | 
|  | vlinks_t *new_links = allocate_vlinks (); | 
|  |  | 
|  | #ifdef MALLOC_CHECK | 
|  | if (vp->object_size > 1) | 
|  | new_links->datum = (page_type *) xcalloc (1, vp->object_size); | 
|  | else | 
|  | #endif | 
|  | new_links->datum = allocate_page (); | 
|  |  | 
|  | alloc_counts[(int) alloc_type_varray].total_alloc++; | 
|  | alloc_counts[(int) alloc_type_varray].total_pages++; | 
|  |  | 
|  | new_links->start_index = vp->num_allocated; | 
|  | vp->objects_last_page = 0; | 
|  |  | 
|  | if (vp->first == (vlinks_t *) NULL)		/* 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Add a string (and null pad) to one of the string tables.  */ | 
|  |  | 
|  | static symint_t | 
|  | add_string (varray_t *vp,			/* string obstack */ | 
|  | htab_t hash_tbl,			/* ptr to hash table */ | 
|  | const char *str,			/* string */ | 
|  | shash_t **ret_hash			/* return hash pointer */) | 
|  | { | 
|  | unsigned long len = strlen (str); | 
|  | shash_t *hash_ptr; | 
|  |  | 
|  | if (len >= PAGE_USIZE) | 
|  | as_fatal (_("string too big (%lu bytes)"), len); | 
|  |  | 
|  | hash_ptr = (shash_t *) str_hash_find (hash_tbl, str); | 
|  | if (hash_ptr == (shash_t *) NULL) | 
|  | { | 
|  | 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 = allocate_shash (); | 
|  | hash_ptr->indx = vp->num_allocated; | 
|  |  | 
|  | hash_ptr->string = &vp->last->datum->byte[vp->objects_last_page]; | 
|  |  | 
|  | vp->objects_last_page += len + 1; | 
|  | vp->num_allocated += len + 1; | 
|  |  | 
|  | strcpy (hash_ptr->string, str); | 
|  |  | 
|  | if (str_hash_insert (hash_tbl, str, hash_ptr, 0) != NULL) | 
|  | as_fatal (_("duplicate %s"), str); | 
|  | } | 
|  |  | 
|  | if (ret_hash != (shash_t **) NULL) | 
|  | *ret_hash = hash_ptr; | 
|  |  | 
|  | return hash_ptr->indx; | 
|  | } | 
|  |  | 
|  | /* Add debugging information for a symbol.  */ | 
|  |  | 
|  | static localsym_t * | 
|  | add_ecoff_symbol (const char *str,	/* symbol name */ | 
|  | st_t type,		/* symbol type */ | 
|  | sc_t storage,		/* storage class */ | 
|  | symbolS *sym_value,	/* associated symbol.  */ | 
|  | bfd_vma addend,	/* addend to sym_value.  */ | 
|  | symint_t value,	/* value of symbol */ | 
|  | symint_t indx		/* index to local/aux. syms */) | 
|  | { | 
|  | localsym_t *psym; | 
|  | scope_t *pscope; | 
|  | thead_t *ptag_head; | 
|  | tag_t *ptag; | 
|  | tag_t *ptag_next; | 
|  | varray_t *vp; | 
|  | int scope_delta = 0; | 
|  | shash_t *hash_ptr = (shash_t *) NULL; | 
|  |  | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | as_fatal (_("no current file pointer")); | 
|  |  | 
|  | vp = &cur_file_ptr->symbols; | 
|  |  | 
|  | if (vp->objects_last_page == vp->objects_per_page) | 
|  | add_varray_page (vp); | 
|  |  | 
|  | psym = &vp->last->datum->sym[vp->objects_last_page++]; | 
|  |  | 
|  | if (str == (const char *) NULL && sym_value != (symbolS *) NULL) | 
|  | psym->name = S_GET_NAME (sym_value); | 
|  | else | 
|  | psym->name = str; | 
|  | psym->as_sym = sym_value; | 
|  | if (sym_value != (symbolS *) NULL) | 
|  | symbol_get_obj (sym_value)->ecoff_symbol = psym; | 
|  | psym->addend = addend; | 
|  | psym->file_ptr = cur_file_ptr; | 
|  | psym->proc_ptr = cur_proc_ptr; | 
|  | psym->begin_ptr = (localsym_t *) NULL; | 
|  | psym->index_ptr = (aux_t *) NULL; | 
|  | psym->forward_ref = (forward_t *) NULL; | 
|  | psym->sym_index = -1; | 
|  | memset (&psym->ecoff_sym, 0, sizeof (EXTR)); | 
|  | psym->ecoff_sym.asym.value = value; | 
|  | psym->ecoff_sym.asym.st = (unsigned) type; | 
|  | psym->ecoff_sym.asym.sc = (unsigned) storage; | 
|  | psym->ecoff_sym.asym.index = indx; | 
|  |  | 
|  | /* If there is an associated symbol, we wait until the end of the | 
|  | assembly before deciding where to put the name (it may be just an | 
|  | external symbol).  Otherwise, this is just a debugging symbol and | 
|  | the name should go with the current file.  */ | 
|  | if (sym_value == (symbolS *) NULL) | 
|  | psym->ecoff_sym.asym.iss = ((str == (const char *) NULL) | 
|  | ? 0 | 
|  | : add_string (&cur_file_ptr->strings, | 
|  | cur_file_ptr->str_hash, | 
|  | str, | 
|  | &hash_ptr)); | 
|  |  | 
|  | ++vp->num_allocated; | 
|  |  | 
|  | if (ECOFF_IS_STAB (&psym->ecoff_sym.asym)) | 
|  | return psym; | 
|  |  | 
|  | /* Save the symbol within the hash table if this is a static | 
|  | item, and it has a name.  */ | 
|  | if (hash_ptr != (shash_t *) NULL | 
|  | && (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 = allocate_scope (); | 
|  | pscope->prev = cur_file_ptr->cur_scope; | 
|  | pscope->lsym = psym; | 
|  | 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 = allocate_thead (); | 
|  | 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 *) NULL) | 
|  | as_fatal (_("too many st_End's")); | 
|  | else | 
|  | { | 
|  | st_t begin_type = (st_t) pscope->lsym->ecoff_sym.asym.st; | 
|  |  | 
|  | psym->begin_ptr = pscope->lsym; | 
|  |  | 
|  | 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 *) NULL; | 
|  | ptag = ptag_next) | 
|  | { | 
|  | if (ptag->forward_ref != (forward_t *) NULL) | 
|  | add_unknown_tag (ptag); | 
|  |  | 
|  | ptag_next = ptag->same_block; | 
|  | ptag->hash_ptr->tag_ptr = ptag->same_name; | 
|  | free_tag (ptag); | 
|  | } | 
|  |  | 
|  | free_thead (ptag_head); | 
|  | } | 
|  |  | 
|  | cur_file_ptr->cur_scope = pscope->prev; | 
|  |  | 
|  | /* block begin gets next sym #.  This is set when we know | 
|  | the symbol index value.  */ | 
|  |  | 
|  | /* Functions push two or more aux words as follows: | 
|  | 1st word: index+1 of the end symbol (filled in later). | 
|  | 2nd word: type of the function (plus any aux words needed). | 
|  | Also, tie the external pointer back to the function begin symbol.  */ | 
|  | if (begin_type != st_File && begin_type != st_Block) | 
|  | { | 
|  | symint_t ty; | 
|  | varray_t *svp = &cur_file_ptr->aux_syms; | 
|  |  | 
|  | pscope->lsym->ecoff_sym.asym.index = add_aux_sym_symint (0); | 
|  | pscope->lsym->index_ptr = | 
|  | &svp->last->datum->aux[svp->objects_last_page - 1]; | 
|  | ty = add_aux_sym_tir (&last_func_type_info, | 
|  | hash_no, | 
|  | &cur_file_ptr->thash_head[0]); | 
|  | (void) ty; | 
|  | /* This seems to be unnecessary.  I'm not even sure what it is | 
|  | * intended to do.  It's from mips-tfile. | 
|  | *	      if (last_func_sym_value != (symbolS *) NULL) | 
|  | *		{ | 
|  | *		  last_func_sym_value->ifd = cur_file_ptr->file_index; | 
|  | *		  last_func_sym_value->index = ty; | 
|  | *		} | 
|  | */ | 
|  | } | 
|  |  | 
|  | free_scope (pscope); | 
|  | } | 
|  | } | 
|  |  | 
|  | cur_file_ptr->nested_scopes += scope_delta; | 
|  |  | 
|  | #ifdef ECOFF_DEBUG | 
|  | 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 | 
|  | { | 
|  | unsigned long len = strlen (st_str); | 
|  | fprintf (stderr, " st= %.*s\n", len - 1, st_str); | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  | 
|  | return psym; | 
|  | } | 
|  |  | 
|  | /* Add an auxiliary symbol (passing a symint).  This is actually used | 
|  | for integral aux types, not just symints.  */ | 
|  |  | 
|  | static symint_t | 
|  | add_aux_sym_symint (symint_t aux_word /* auxiliary information word */) | 
|  | { | 
|  | varray_t *vp; | 
|  | aux_t *aux_ptr; | 
|  |  | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | as_fatal (_("no current file pointer")); | 
|  |  | 
|  | vp = &cur_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->type = aux_isym; | 
|  | aux_ptr->data.isym = aux_word; | 
|  |  | 
|  | return vp->num_allocated++; | 
|  | } | 
|  |  | 
|  | /* Add an auxiliary symbol (passing a file/symbol index combo).  */ | 
|  |  | 
|  | static symint_t | 
|  | add_aux_sym_rndx (int file_index, symint_t sym_index) | 
|  | { | 
|  | varray_t *vp; | 
|  | aux_t *aux_ptr; | 
|  |  | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | as_fatal (_("no current file pointer")); | 
|  |  | 
|  | vp = &cur_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->type = aux_rndx; | 
|  | aux_ptr->data.rndx.rfd   = file_index; | 
|  | aux_ptr->data.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 (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 */) | 
|  | { | 
|  | varray_t *vp; | 
|  | aux_t *aux_ptr; | 
|  | symint_t ret; | 
|  | int i; | 
|  | AUXU aux; | 
|  |  | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | as_fatal (_("no current file pointer")); | 
|  |  | 
|  | vp = &cur_file_ptr->aux_syms; | 
|  |  | 
|  | memset (&aux, 0, sizeof (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) | 
|  | { | 
|  | thash_t *hash_ptr; | 
|  | 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 *) NULL && state == hash_yes) | 
|  | return hash_ptr->indx; | 
|  |  | 
|  | if (hash_ptr == (thash_t *) NULL) | 
|  | { | 
|  | hash_ptr = allocate_thash (); | 
|  | hash_ptr->next = hash_tbl[hi]; | 
|  | hash_ptr->type = aux; | 
|  | hash_ptr->indx = 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->type = aux_tir; | 
|  | aux_ptr->data = aux; | 
|  |  | 
|  | ret = vp->num_allocated++; | 
|  |  | 
|  | /* Add bitfield length if it exists. | 
|  |  | 
|  | NOTE:  Mips documentation claims bitfield goes at the end of the | 
|  | AUX record, but the DECstation compiler emits it here. | 
|  | (This would only make a difference for enum bitfields.) | 
|  |  | 
|  | Also note:  We use the last size given since gcc may emit 2 | 
|  | for an enum bitfield.  */ | 
|  |  | 
|  | if (t->bitfield) | 
|  | (void) add_aux_sym_symint ((symint_t) t->sizes[t->num_sizes - 1]); | 
|  |  | 
|  | /* 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) | 
|  | { | 
|  | symint_t file_index = t->tag_ptr->ifd; | 
|  | localsym_t *sym = t->tag_ptr->sym; | 
|  | forward_t *forward_ref = allocate_forward (); | 
|  |  | 
|  | if (sym != (localsym_t *) NULL) | 
|  | { | 
|  | forward_ref->next = sym->forward_ref; | 
|  | sym->forward_ref = forward_ref; | 
|  | } | 
|  | else | 
|  | { | 
|  | forward_ref->next = t->tag_ptr->forward_ref; | 
|  | t->tag_ptr->forward_ref = forward_ref; | 
|  | } | 
|  |  | 
|  | (void) add_aux_sym_rndx (ST_RFDESCAPE, indexNil); | 
|  | 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 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]); | 
|  | }; | 
|  |  | 
|  | /* NOTE:  Mips documentation claims that the bitfield width goes here. | 
|  | But it needs to be emitted earlier.  */ | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Add a tag to the tag table (unless it already exists).  */ | 
|  |  | 
|  | static tag_t * | 
|  | get_tag (const char *tag,	/* tag name */ | 
|  | localsym_t *sym,	/* tag start block */ | 
|  | bt_t basic_type	/* bt_Struct, bt_Union, or bt_Enum */) | 
|  | { | 
|  | shash_t *hash_ptr; | 
|  | tag_t *tag_ptr; | 
|  |  | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | as_fatal (_("no current file pointer")); | 
|  |  | 
|  | hash_ptr = (shash_t *) str_hash_find (tag_hash, tag); | 
|  |  | 
|  | if (hash_ptr != (shash_t *) NULL | 
|  | && hash_ptr->tag_ptr != (tag_t *) NULL) | 
|  | { | 
|  | tag_ptr = hash_ptr->tag_ptr; | 
|  | if (sym != (localsym_t *) NULL) | 
|  | { | 
|  | tag_ptr->basic_type = basic_type; | 
|  | tag_ptr->ifd        = cur_file_ptr->file_index; | 
|  | tag_ptr->sym        = sym; | 
|  | } | 
|  | return tag_ptr; | 
|  | } | 
|  |  | 
|  | if (hash_ptr == (shash_t *) NULL) | 
|  | { | 
|  | char *perm; | 
|  |  | 
|  | perm = xstrdup (tag); | 
|  | hash_ptr = allocate_shash (); | 
|  | str_hash_insert (tag_hash, perm, hash_ptr, 0); | 
|  | hash_ptr->string = perm; | 
|  | } | 
|  |  | 
|  | tag_ptr = allocate_tag (); | 
|  | tag_ptr->forward_ref	= (forward_t *) NULL; | 
|  | tag_ptr->hash_ptr	= hash_ptr; | 
|  | tag_ptr->same_name	= hash_ptr->tag_ptr; | 
|  | tag_ptr->basic_type	= basic_type; | 
|  | tag_ptr->sym		= sym; | 
|  | tag_ptr->ifd		= ((sym == (localsym_t *) NULL) | 
|  | ? (symint_t) -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 (tag_t *ptag /* pointer to tag information */) | 
|  | { | 
|  | shash_t *hash_ptr	= ptag->hash_ptr; | 
|  | char *name		= hash_ptr->string; | 
|  | localsym_t *sym; | 
|  | forward_t **pf; | 
|  |  | 
|  | #ifdef ECOFF_DEBUG | 
|  | 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); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | sym = add_ecoff_symbol (name, | 
|  | st_Block, | 
|  | sc_Info, | 
|  | (symbolS *) NULL, | 
|  | (bfd_vma) 0, | 
|  | (symint_t) 0, | 
|  | (symint_t) 0); | 
|  |  | 
|  | (void) add_ecoff_symbol (name, | 
|  | st_End, | 
|  | sc_Info, | 
|  | (symbolS *) NULL, | 
|  | (bfd_vma) 0, | 
|  | (symint_t) 0, | 
|  | (symint_t) 0); | 
|  |  | 
|  | for (pf = &sym->forward_ref; *pf != (forward_t *) NULL; pf = &(*pf)->next) | 
|  | ; | 
|  | *pf = ptag->forward_ref; | 
|  | } | 
|  |  | 
|  | /* Add a procedure to the current file's list of procedures, and record | 
|  | this is the current procedure.  If AENT, then only set the requested | 
|  | symbol's function type.  */ | 
|  |  | 
|  | static void | 
|  | add_procedure (char *func /* func name */, int aent) | 
|  | { | 
|  | varray_t *vp; | 
|  | proc_t *new_proc_ptr; | 
|  | symbolS *sym; | 
|  |  | 
|  | #ifdef ECOFF_DEBUG | 
|  | if (debug) | 
|  | fputc ('\n', stderr); | 
|  | #endif | 
|  |  | 
|  | /* Set the BSF_FUNCTION flag for the symbol.  */ | 
|  | sym = symbol_find_or_make (func); | 
|  | symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION; | 
|  |  | 
|  | if (aent) | 
|  | return; | 
|  |  | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | as_fatal (_("no current file pointer")); | 
|  |  | 
|  | vp = &cur_file_ptr->procs; | 
|  |  | 
|  | 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++]; | 
|  |  | 
|  | if (first_proc_ptr == (proc_t *) NULL) | 
|  | first_proc_ptr = new_proc_ptr; | 
|  |  | 
|  | vp->num_allocated++; | 
|  |  | 
|  | new_proc_ptr->pdr.isym = -1; | 
|  | new_proc_ptr->pdr.iline = -1; | 
|  | new_proc_ptr->pdr.lnLow = -1; | 
|  | new_proc_ptr->pdr.lnHigh = -1; | 
|  |  | 
|  | /* Push the start of the function.  */ | 
|  | new_proc_ptr->sym = add_ecoff_symbol ((const char *) NULL, st_Proc, sc_Text, | 
|  | sym, (bfd_vma) 0, (symint_t) 0, | 
|  | (symint_t) 0); | 
|  |  | 
|  | ++proc_cnt; | 
|  |  | 
|  | /* Fill in the linenos preceding the .ent, if any.  */ | 
|  | if (noproc_lineno != (lineno_list_t *) NULL) | 
|  | { | 
|  | lineno_list_t *l; | 
|  |  | 
|  | for (l = noproc_lineno; l != (lineno_list_t *) NULL; l = l->next) | 
|  | l->proc = new_proc_ptr; | 
|  | *last_lineno_ptr = noproc_lineno; | 
|  | while (*last_lineno_ptr != NULL) | 
|  | { | 
|  | last_lineno = *last_lineno_ptr; | 
|  | last_lineno_ptr = &last_lineno->next; | 
|  | } | 
|  | noproc_lineno = (lineno_list_t *) NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | symbolS * | 
|  | ecoff_get_cur_proc_sym (void) | 
|  | { | 
|  | return (cur_proc_ptr ? cur_proc_ptr->sym->as_sym : NULL); | 
|  | } | 
|  |  | 
|  | /* 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 (const char *file_name, int indx ATTRIBUTE_UNUSED, int fake) | 
|  | { | 
|  | int first_ch; | 
|  | efdr_t *fil_ptr; | 
|  |  | 
|  | #ifdef ECOFF_DEBUG | 
|  | if (debug) | 
|  | fprintf (stderr, "\tfile\t%.*s\n", len, file_start); | 
|  | #endif | 
|  |  | 
|  | /* If the file name is NULL, then no .file symbol appeared, and we | 
|  | want to use the actual file name.  */ | 
|  | if (file_name == (const char *) NULL) | 
|  | { | 
|  | if (first_file != (efdr_t *) NULL) | 
|  | as_fatal (_("fake .file after real one")); | 
|  | file_name = as_where ((unsigned int *) NULL); | 
|  |  | 
|  | /* Automatically generate ECOFF debugging information, since I | 
|  | think that's what other ECOFF assemblers do.  We don't do | 
|  | this if we see a .file directive with a string, since that | 
|  | implies that some sort of debugging information is being | 
|  | provided.  */ | 
|  | if (! symbol_table_frozen && debug_type == DEBUG_UNSPECIFIED) | 
|  | debug_type = DEBUG_ECOFF; | 
|  | } | 
|  | else if (debug_type == DEBUG_UNSPECIFIED) | 
|  | debug_type = DEBUG_NONE; | 
|  |  | 
|  | #ifndef NO_LISTING | 
|  | if (listing) | 
|  | listing_source_file (file_name); | 
|  | #endif | 
|  |  | 
|  | current_stabs_filename = file_name; | 
|  |  | 
|  | /* If we're creating stabs, then we don't actually make a new FDR. | 
|  | Instead, we just create a stabs symbol.  */ | 
|  | if (stabs_seen) | 
|  | { | 
|  | (void) add_ecoff_symbol (file_name, st_Nil, sc_Nil, | 
|  | symbol_new (FAKE_LABEL_NAME, now_seg, | 
|  | frag_now, frag_now_fix ()), | 
|  | (bfd_vma) 0, 0, ECOFF_MARK_STAB (N_SOL)); | 
|  | return; | 
|  | } | 
|  |  | 
|  | first_ch = *file_name; | 
|  |  | 
|  | /* FIXME: We can't safely merge files which have line number | 
|  | information (fMerge will be zero in this case).  Otherwise, we | 
|  | get incorrect line number debugging info.  See for instance | 
|  | ecoff_build_lineno, which will end up setting all file->fdr.* | 
|  | fields multiple times, resulting in incorrect debug info.  In | 
|  | order to make this work right, all line number and symbol info | 
|  | for the same source file has to be adjacent in the object file, | 
|  | so that a single file descriptor can be used to point to them. | 
|  | This would require maintaining file specific lists of line | 
|  | numbers and symbols for each file, so that they can be merged | 
|  | together (or output together) when two .file pseudo-ops are | 
|  | merged into one file descriptor.  */ | 
|  |  | 
|  | /* See if the file has already been created.  */ | 
|  | for (fil_ptr = first_file; | 
|  | fil_ptr != (efdr_t *) NULL; | 
|  | fil_ptr = fil_ptr->next_file) | 
|  | { | 
|  | if (first_ch == fil_ptr->name[0] | 
|  | && filename_cmp (file_name, fil_ptr->name) == 0 | 
|  | && fil_ptr->fdr.fMerge) | 
|  | { | 
|  | cur_file_ptr = fil_ptr; | 
|  | if (! fake) | 
|  | cur_file_ptr->fake = 0; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* If this is a new file, create it.  */ | 
|  | if (fil_ptr == (efdr_t *) NULL) | 
|  | { | 
|  | if (file_desc.objects_last_page == file_desc.objects_per_page) | 
|  | add_varray_page (&file_desc); | 
|  |  | 
|  | fil_ptr = cur_file_ptr = | 
|  | &file_desc.last->datum->file[file_desc.objects_last_page++]; | 
|  | *fil_ptr = init_file; | 
|  |  | 
|  | fil_ptr->file_index = current_file_idx++; | 
|  | ++file_desc.num_allocated; | 
|  |  | 
|  | fil_ptr->fake = fake; | 
|  |  | 
|  | /* Allocate the string hash table.  */ | 
|  | fil_ptr->str_hash = str_htab_create (); | 
|  |  | 
|  | /* Make sure 0 byte in string table is null  */ | 
|  | add_string (&fil_ptr->strings, | 
|  | fil_ptr->str_hash, | 
|  | "", | 
|  | (shash_t **)0); | 
|  |  | 
|  | if (strlen (file_name) > PAGE_USIZE - 2) | 
|  | as_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_ecoff_symbol (file_name, st_File, sc_Text, | 
|  | (symbolS *) NULL, (bfd_vma) 0, | 
|  | (symint_t) 0, (symint_t) 0); | 
|  | fil_ptr->fdr.rss = 1; | 
|  | fil_ptr->name = &fil_ptr->strings.last->datum->byte[1]; | 
|  |  | 
|  | /* Update the linked list of file descriptors.  */ | 
|  | *last_file_ptr = fil_ptr; | 
|  | last_file_ptr = &fil_ptr->next_file; | 
|  |  | 
|  | /* Add void & int types to the file (void should be first to catch | 
|  | errant 0's within the index fields).  */ | 
|  | fil_ptr->void_type = add_aux_sym_tir (&void_type_info, | 
|  | hash_yes, | 
|  | &cur_file_ptr->thash_head[0]); | 
|  |  | 
|  | fil_ptr->int_type = add_aux_sym_tir (&int_type_info, | 
|  | hash_yes, | 
|  | &cur_file_ptr->thash_head[0]); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* This function is called when the assembler notices a preprocessor | 
|  | directive switching to a new file.  This will not happen in | 
|  | compiler output, only in hand coded assembler.  */ | 
|  |  | 
|  | void | 
|  | ecoff_new_file (const char *name) | 
|  | { | 
|  | if (cur_file_ptr != NULL && filename_cmp (cur_file_ptr->name, name) == 0) | 
|  | return; | 
|  | add_file (name, 0, 0); | 
|  |  | 
|  | /* This is a hand coded assembler file, so automatically turn on | 
|  | debugging information.  */ | 
|  | if (debug_type == DEBUG_UNSPECIFIED) | 
|  | debug_type = DEBUG_ECOFF; | 
|  | } | 
|  |  | 
|  | #ifdef ECOFF_DEBUG | 
|  |  | 
|  | /* 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 "???,"; | 
|  | } | 
|  |  | 
|  | #endif /* DEBUG */ | 
|  |  | 
|  | #ifdef ECOFF_DEBUG | 
|  |  | 
|  | /* 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 "???,"; | 
|  | } | 
|  |  | 
|  | #endif /* DEBUG */ | 
|  |  | 
|  | /* Parse .begin directives which have a label as the first argument | 
|  | which gives the location of the start of the block.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_begin (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | char *name; | 
|  | char name_end; | 
|  |  | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | { | 
|  | as_warn (_(".begin directive without a preceding .file directive")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (cur_proc_ptr == (proc_t *) NULL) | 
|  | { | 
|  | as_warn (_(".begin directive without a preceding .ent directive")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | name_end = get_symbol_name (&name); | 
|  |  | 
|  | (void) add_ecoff_symbol ((const char *) NULL, st_Block, sc_Text, | 
|  | symbol_find_or_make (name), | 
|  | (bfd_vma) 0, (symint_t) 0, (symint_t) 0); | 
|  |  | 
|  | (void) restore_line_pointer (name_end); | 
|  |  | 
|  | /* The line number follows, but we don't use it.  */ | 
|  | (void) get_absolute_expression (); | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Parse .bend directives which have a label as the first argument | 
|  | which gives the location of the end of the block.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_bend (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | char *name; | 
|  | char name_end; | 
|  | symbolS *endsym; | 
|  |  | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | { | 
|  | as_warn (_(".bend directive without a preceding .file directive")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (cur_proc_ptr == (proc_t *) NULL) | 
|  | { | 
|  | as_warn (_(".bend directive without a preceding .ent directive")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | name_end = get_symbol_name (&name); | 
|  |  | 
|  | /* The value is the distance between the .bend directive and the | 
|  | corresponding symbol.  We fill in the offset when we write out | 
|  | the symbol.  */ | 
|  | endsym = symbol_find (name); | 
|  | if (endsym == (symbolS *) NULL) | 
|  | as_warn (_(".bend directive names unknown symbol")); | 
|  | else | 
|  | (void) add_ecoff_symbol ((const char *) NULL, st_End, sc_Text, endsym, | 
|  | (bfd_vma) 0, (symint_t) 0, (symint_t) 0); | 
|  |  | 
|  | restore_line_pointer (name_end); | 
|  |  | 
|  | /* The line number follows, but we don't use it.  */ | 
|  | (void) get_absolute_expression (); | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* COFF debugging information is provided as a series of directives | 
|  | (.def, .scl, etc.).  We build up information as we read the | 
|  | directives in the following static variables, and file it away when | 
|  | we reach the .endef directive.  */ | 
|  | static char *coff_sym_name; | 
|  | static type_info_t coff_type; | 
|  | static sc_t coff_storage_class; | 
|  | static st_t coff_symbol_typ; | 
|  | static int coff_is_function; | 
|  | static char *coff_tag; | 
|  | static valueT coff_value; | 
|  | static symbolS *coff_sym_value; | 
|  | static bfd_vma coff_sym_addend; | 
|  | static int coff_inside_enumeration; | 
|  |  | 
|  | /* Handle a .def directive: start defining a symbol.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_def (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | char *name; | 
|  | char name_end; | 
|  |  | 
|  | ecoff_debugging_seen = 1; | 
|  |  | 
|  | SKIP_WHITESPACE (); | 
|  |  | 
|  | name_end = get_symbol_name (&name); | 
|  |  | 
|  | if (coff_sym_name != (char *) NULL) | 
|  | as_warn (_(".def pseudo-op used inside of .def/.endef; ignored")); | 
|  | else if (*name == '\0') | 
|  | as_warn (_("empty symbol name in .def; ignored")); | 
|  | else | 
|  | { | 
|  | free (coff_sym_name); | 
|  | free (coff_tag); | 
|  |  | 
|  | coff_sym_name = xstrdup (name); | 
|  | coff_type = type_info_init; | 
|  | coff_storage_class = sc_Nil; | 
|  | coff_symbol_typ = st_Nil; | 
|  | coff_is_function = 0; | 
|  | coff_tag = (char *) NULL; | 
|  | coff_value = 0; | 
|  | coff_sym_value = (symbolS *) NULL; | 
|  | coff_sym_addend = 0; | 
|  | } | 
|  |  | 
|  | restore_line_pointer (name_end); | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Handle a .dim directive, used to give dimensions for an array.  The | 
|  | arguments are comma separated numbers.  mips-tfile assumes that | 
|  | there will not be more than 6 dimensions, and gdb won't read any | 
|  | more than that anyhow, so I will also make that assumption.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_dim (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | int dimens[N_TQ]; | 
|  | int i; | 
|  |  | 
|  | if (coff_sym_name == (char *) NULL) | 
|  | { | 
|  | as_warn (_(".dim pseudo-op used outside of .def/.endef; ignored")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | for (i = 0; i < N_TQ; i++) | 
|  | { | 
|  | SKIP_WHITESPACE (); | 
|  | dimens[i] = get_absolute_expression (); | 
|  | if (*input_line_pointer == ',') | 
|  | ++input_line_pointer; | 
|  | else | 
|  | { | 
|  | if (*input_line_pointer != '\n' | 
|  | && *input_line_pointer != ';') | 
|  | as_warn (_("badly formed .dim directive")); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (i == N_TQ) | 
|  | --i; | 
|  |  | 
|  | /* The dimensions are stored away in reverse order.  */ | 
|  | for (; i >= 0; i--) | 
|  | { | 
|  | if (coff_type.num_dims >= N_TQ) | 
|  | { | 
|  | as_warn (_("too many .dim entries")); | 
|  | break; | 
|  | } | 
|  | coff_type.dimensions[coff_type.num_dims] = dimens[i]; | 
|  | ++coff_type.num_dims; | 
|  | } | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Handle a .scl directive, which sets the COFF storage class of the | 
|  | symbol.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_scl (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | long val; | 
|  |  | 
|  | if (coff_sym_name == (char *) NULL) | 
|  | { | 
|  | as_warn (_(".scl pseudo-op used outside of .def/.endef; ignored")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | val = get_absolute_expression (); | 
|  |  | 
|  | coff_symbol_typ = map_coff_sym_type[val]; | 
|  | coff_storage_class = map_coff_storage[val]; | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Handle a .size directive.  For some reason mips-tfile.c thinks that | 
|  | .size can have multiple arguments.  We humor it, although gcc will | 
|  | never generate more than one argument.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_size (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | int sizes[N_TQ]; | 
|  | int i; | 
|  |  | 
|  | if (coff_sym_name == (char *) NULL) | 
|  | { | 
|  | as_warn (_(".size pseudo-op used outside of .def/.endef; ignored")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | for (i = 0; i < N_TQ; i++) | 
|  | { | 
|  | SKIP_WHITESPACE (); | 
|  | sizes[i] = get_absolute_expression (); | 
|  | if (*input_line_pointer == ',') | 
|  | ++input_line_pointer; | 
|  | else | 
|  | { | 
|  | if (*input_line_pointer != '\n' | 
|  | && *input_line_pointer != ';') | 
|  | as_warn (_("badly formed .size directive")); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (i == N_TQ) | 
|  | --i; | 
|  |  | 
|  | /* The sizes are stored away in reverse order.  */ | 
|  | for (; i >= 0; i--) | 
|  | { | 
|  | if (coff_type.num_sizes >= N_TQ) | 
|  | { | 
|  | as_warn (_("too many .size entries")); | 
|  | break; | 
|  | } | 
|  | coff_type.sizes[coff_type.num_sizes] = sizes[i]; | 
|  | ++coff_type.num_sizes; | 
|  | } | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Handle the .type directive, which gives the COFF type of the | 
|  | symbol.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_type (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | long val; | 
|  | tq_t *tq_ptr; | 
|  | tq_t *tq_shft; | 
|  |  | 
|  | if (coff_sym_name == (char *) NULL) | 
|  | { | 
|  | as_warn (_(".type pseudo-op used outside of .def/.endef; ignored")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | val = get_absolute_expression (); | 
|  |  | 
|  | coff_type.orig_type = BTYPE (val); | 
|  | coff_type.basic_type = map_coff_types[coff_type.orig_type]; | 
|  |  | 
|  | tq_ptr = &coff_type.type_qualifiers[N_TQ]; | 
|  | while (val & ~N_BTMASK) | 
|  | { | 
|  | if (tq_ptr == &coff_type.type_qualifiers[0]) | 
|  | { | 
|  | /* FIXME: We could handle this by setting the continued bit. | 
|  | There would still be a limit: the .type argument can not | 
|  | be infinite.  */ | 
|  | as_warn (_("the type of %s is too complex; it will be simplified"), | 
|  | coff_sym_name); | 
|  | break; | 
|  | } | 
|  | if (ISPTR (val)) | 
|  | *--tq_ptr = tq_Ptr; | 
|  | else if (ISFCN (val)) | 
|  | *--tq_ptr = tq_Proc; | 
|  | else if (ISARY (val)) | 
|  | *--tq_ptr = tq_Array; | 
|  | else | 
|  | as_fatal (_("Unrecognized .type argument")); | 
|  |  | 
|  | val = DECREF (val); | 
|  | } | 
|  |  | 
|  | tq_shft = &coff_type.type_qualifiers[0]; | 
|  | while (tq_ptr != &coff_type.type_qualifiers[N_TQ]) | 
|  | *tq_shft++ = *tq_ptr++; | 
|  |  | 
|  | if (tq_shft != &coff_type.type_qualifiers[0] && tq_shft[-1] == tq_Proc) | 
|  | { | 
|  | /* 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 | 
|  | precedes 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.  */ | 
|  | coff_is_function = 1; | 
|  | tq_shft[-1] = tq_Nil; | 
|  | } | 
|  |  | 
|  | while (tq_shft != &coff_type.type_qualifiers[N_TQ]) | 
|  | *tq_shft++ = tq_Nil; | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Handle the .tag directive, which gives the name of a structure, | 
|  | union or enum.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_tag (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | char *name; | 
|  | char name_end; | 
|  |  | 
|  | if (coff_sym_name == (char *) NULL) | 
|  | { | 
|  | as_warn (_(".tag pseudo-op used outside of .def/.endef; ignored")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | name_end = get_symbol_name (&name); | 
|  |  | 
|  | coff_tag = xstrdup (name); | 
|  |  | 
|  | (void) restore_line_pointer (name_end); | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Handle the .val directive, which gives the value of the symbol.  It | 
|  | may be the name of a static or global symbol.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_val (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | expressionS exp; | 
|  |  | 
|  | if (coff_sym_name == (char *) NULL) | 
|  | { | 
|  | as_warn (_(".val pseudo-op used outside of .def/.endef; ignored")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | expression (&exp); | 
|  | if (exp.X_op != O_constant && exp.X_op != O_symbol) | 
|  | { | 
|  | as_bad (_(".val expression is too complex")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (exp.X_op == O_constant) | 
|  | coff_value = exp.X_add_number; | 
|  | else | 
|  | { | 
|  | coff_sym_value = exp.X_add_symbol; | 
|  | coff_sym_addend = exp.X_add_number; | 
|  | } | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Handle the .endef directive, which terminates processing of COFF | 
|  | debugging information for a symbol.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_endef (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | char *name; | 
|  | symint_t indx; | 
|  | localsym_t *sym; | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  |  | 
|  | if (coff_sym_name == (char *) NULL) | 
|  | { | 
|  | as_warn (_(".endef pseudo-op used before .def; ignored")); | 
|  | return; | 
|  | } | 
|  |  | 
|  | name = coff_sym_name; | 
|  | coff_sym_name = (char *) NULL; | 
|  |  | 
|  | /* 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 (coff_sym_value != (symbolS *) NULL) | 
|  | { | 
|  | coff_symbol_typ = st_Nil; | 
|  | coff_storage_class = sc_Nil; | 
|  | } | 
|  |  | 
|  | coff_type.extra_sizes = coff_tag != (char *) NULL; | 
|  | if (coff_type.num_dims > 0) | 
|  | { | 
|  | int diff = coff_type.num_dims - coff_type.num_sizes; | 
|  | int i = coff_type.num_dims - 1; | 
|  | int j; | 
|  |  | 
|  | if (coff_type.num_sizes != 1 || diff < 0) | 
|  | { | 
|  | as_warn (_("bad COFF debugging information")); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* 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.  */ | 
|  | coff_type.extra_sizes = 0; | 
|  | if (diff) | 
|  | { | 
|  | j = (sizeof (coff_type.sizes) / sizeof (coff_type.sizes[0])) - 1; | 
|  | while (j >= 0) | 
|  | { | 
|  | coff_type.sizes[j] = (((j - diff) >= 0) | 
|  | ? coff_type.sizes[j - diff] | 
|  | : 0); | 
|  | j--; | 
|  | } | 
|  |  | 
|  | coff_type.num_sizes = i + 1; | 
|  | for (i--; i >= 0; i--) | 
|  | coff_type.sizes[i] = (coff_type.dimensions[i + 1] == 0 | 
|  | ? 0 | 
|  | : (coff_type.sizes[i + 1] | 
|  | / coff_type.dimensions[i + 1])); | 
|  | } | 
|  | } | 
|  | else if (coff_symbol_typ == st_Member | 
|  | && coff_type.num_sizes - coff_type.extra_sizes == 1) | 
|  | { | 
|  | /* Is this a bitfield?  This is indicated by a structure member | 
|  | having a size field that isn't an array.  */ | 
|  | coff_type.bitfield = 1; | 
|  | } | 
|  |  | 
|  | /* Except for enumeration members & begin/ending of scopes, put the | 
|  | type word in the aux. symbol table.  */ | 
|  | if (coff_symbol_typ == st_Block || coff_symbol_typ == st_End) | 
|  | indx = 0; | 
|  | else if (coff_inside_enumeration) | 
|  | indx = cur_file_ptr->void_type; | 
|  | else | 
|  | { | 
|  | if (coff_type.basic_type == bt_Struct | 
|  | || coff_type.basic_type == bt_Union | 
|  | || coff_type.basic_type == bt_Enum) | 
|  | { | 
|  | if (coff_tag == (char *) NULL) | 
|  | { | 
|  | as_warn (_("no tag specified for %s"), name); | 
|  | return; | 
|  | } | 
|  |  | 
|  | coff_type.tag_ptr = get_tag (coff_tag, (localsym_t *) NULL, | 
|  | coff_type.basic_type); | 
|  | } | 
|  |  | 
|  | if (coff_is_function) | 
|  | { | 
|  | last_func_type_info = coff_type; | 
|  | last_func_sym_value = coff_sym_value; | 
|  | return; | 
|  | } | 
|  |  | 
|  | indx = add_aux_sym_tir (&coff_type, | 
|  | hash_yes, | 
|  | &cur_file_ptr->thash_head[0]); | 
|  | } | 
|  |  | 
|  | /* Do any last minute adjustments that are necessary.  */ | 
|  | switch (coff_symbol_typ) | 
|  | { | 
|  | 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 (coff_type.num_sizes - coff_type.num_dims - coff_type.extra_sizes | 
|  | != 1) | 
|  | { | 
|  | as_warn (_("bad COFF debugging information")); | 
|  | return; | 
|  | } | 
|  | else | 
|  | coff_value = coff_type.sizes[0]; | 
|  |  | 
|  | coff_inside_enumeration = (coff_type.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: | 
|  | free (name); | 
|  | name = (char *) NULL; | 
|  | coff_value = 0; | 
|  | coff_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 distinguished by indx == indexNil.  For enumerations, | 
|  | update the maximum enumeration value.  */ | 
|  | case st_Member: | 
|  | if (! coff_type.bitfield && ! coff_inside_enumeration) | 
|  | coff_value *= 8; | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* Add the symbol.  */ | 
|  | sym = add_ecoff_symbol (name, | 
|  | coff_symbol_typ, | 
|  | coff_storage_class, | 
|  | coff_sym_value, | 
|  | coff_sym_addend, | 
|  | (symint_t) coff_value, | 
|  | indx); | 
|  |  | 
|  | /* deal with struct, union, and enum tags.  */ | 
|  | if (coff_symbol_typ == st_Block) | 
|  | { | 
|  | /* Create or update the tag information.  */ | 
|  | tag_t *tag_ptr = get_tag (name, | 
|  | sym, | 
|  | coff_type.basic_type); | 
|  | forward_t **pf; | 
|  |  | 
|  | /* Remember any forward references.  */ | 
|  | for (pf = &sym->forward_ref; | 
|  | *pf != (forward_t *) NULL; | 
|  | pf = &(*pf)->next) | 
|  | ; | 
|  | *pf = tag_ptr->forward_ref; | 
|  | tag_ptr->forward_ref = (forward_t *) NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Parse .end directives.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_end (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | char *name; | 
|  | char name_end; | 
|  | symbolS *ent; | 
|  |  | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | { | 
|  | as_warn (_(".end directive without a preceding .file directive")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (cur_proc_ptr == (proc_t *) NULL) | 
|  | { | 
|  | as_warn (_(".end directive without a preceding .ent directive")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | name_end = get_symbol_name (&name); | 
|  |  | 
|  | if (name == input_line_pointer) | 
|  | { | 
|  | as_warn (_(".end directive has no name")); | 
|  | (void) restore_line_pointer (name_end); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* The value is the distance between the .end directive and the | 
|  | corresponding symbol.  We create a fake symbol to hold the | 
|  | current location, and put in the offset when we write out the | 
|  | symbol.  */ | 
|  | ent = symbol_find (name); | 
|  | if (ent == (symbolS *) NULL) | 
|  | as_warn (_(".end directive names unknown symbol")); | 
|  | else | 
|  | (void) add_ecoff_symbol ((const char *) NULL, st_End, sc_Text, | 
|  | symbol_new (FAKE_LABEL_NAME, now_seg, | 
|  | frag_now, frag_now_fix ()), | 
|  | (bfd_vma) 0, (symint_t) 0, (symint_t) 0); | 
|  |  | 
|  | #ifdef md_flush_pending_output | 
|  | md_flush_pending_output (); | 
|  | #endif | 
|  |  | 
|  | cur_proc_ptr = (proc_t *) NULL; | 
|  |  | 
|  | (void) restore_line_pointer (name_end); | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Parse .ent directives.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_ent (int aent) | 
|  | { | 
|  | char *name; | 
|  | char name_end; | 
|  |  | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | add_file ((const char *) NULL, 0, 1); | 
|  |  | 
|  | if (!aent && cur_proc_ptr != (proc_t *) NULL) | 
|  | { | 
|  | as_warn (_("second .ent directive found before .end directive")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | name_end = get_symbol_name (&name); | 
|  |  | 
|  | if (name == input_line_pointer) | 
|  | { | 
|  | as_warn (_("%s directive has no name"), aent ? ".aent" : ".ent"); | 
|  | (void) restore_line_pointer (name_end); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | add_procedure (name, aent); | 
|  |  | 
|  | (void) restore_line_pointer (name_end); | 
|  |  | 
|  | /* The .ent directive is sometimes followed by a number.  I'm not | 
|  | really sure what the number means.  I don't see any way to store | 
|  | the information in the PDR.  The Irix 4 assembler seems to ignore | 
|  | the information.  */ | 
|  | SKIP_WHITESPACE (); | 
|  | if (*input_line_pointer == ',') | 
|  | { | 
|  | ++input_line_pointer; | 
|  | SKIP_WHITESPACE (); | 
|  | } | 
|  | if (ISDIGIT (*input_line_pointer) | 
|  | || *input_line_pointer == '-') | 
|  | (void) get_absolute_expression (); | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Parse .extern directives.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_extern (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | char *name; | 
|  | int c; | 
|  | symbolS *symbolp; | 
|  | valueT size; | 
|  |  | 
|  | c = get_symbol_name (&name); | 
|  | symbolp = symbol_find_or_make (name); | 
|  | (void) restore_line_pointer (c); | 
|  |  | 
|  | S_SET_EXTERNAL (symbolp); | 
|  |  | 
|  | if (*input_line_pointer == ',') | 
|  | ++input_line_pointer; | 
|  | size = get_absolute_expression (); | 
|  |  | 
|  | symbol_get_obj (symbolp)->ecoff_extern_size = size; | 
|  | } | 
|  |  | 
|  | /* Parse .file directives.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_file (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | int indx; | 
|  | char *name; | 
|  | int len; | 
|  |  | 
|  | if (cur_proc_ptr != (proc_t *) NULL) | 
|  | { | 
|  | as_warn (_("no way to handle .file within .ent/.end section")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | indx = (int) get_absolute_expression (); | 
|  |  | 
|  | /* FIXME: we don't have to save the name here.  */ | 
|  | name = demand_copy_C_string (&len); | 
|  |  | 
|  | add_file (name, indx - 1, 0); | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Parse .fmask directives.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_fmask (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | long val; | 
|  |  | 
|  | if (cur_proc_ptr == (proc_t *) NULL) | 
|  | { | 
|  | as_warn (_(".fmask outside of .ent")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (get_absolute_expression_and_terminator (&val) != ',') | 
|  | { | 
|  | as_warn (_("bad .fmask directive")); | 
|  | --input_line_pointer; | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | cur_proc_ptr->pdr.fregmask = val; | 
|  | cur_proc_ptr->pdr.fregoffset = get_absolute_expression (); | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Parse .frame directives.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_frame (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | long val; | 
|  |  | 
|  | if (cur_proc_ptr == (proc_t *) NULL) | 
|  | { | 
|  | as_warn (_(".frame outside of .ent")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | cur_proc_ptr->pdr.framereg = tc_get_register (1); | 
|  |  | 
|  | SKIP_WHITESPACE (); | 
|  | if (*input_line_pointer++ != ',' | 
|  | || get_absolute_expression_and_terminator (&val) != ',') | 
|  | { | 
|  | as_warn (_("bad .frame directive")); | 
|  | --input_line_pointer; | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | cur_proc_ptr->pdr.frameoffset = val; | 
|  |  | 
|  | cur_proc_ptr->pdr.pcreg = tc_get_register (0); | 
|  |  | 
|  | /* Alpha-OSF1 adds "the offset of saved $a0 from $sp", according to | 
|  | Sandro.  I don't yet know where this value should be stored, if | 
|  | anywhere.  Don't call demand_empty_rest_of_line ().  */ | 
|  | s_ignore (42); | 
|  | } | 
|  |  | 
|  | /* Parse .mask directives.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_mask (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | long val; | 
|  |  | 
|  | if (cur_proc_ptr == (proc_t *) NULL) | 
|  | { | 
|  | as_warn (_(".mask outside of .ent")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (get_absolute_expression_and_terminator (&val) != ',') | 
|  | { | 
|  | as_warn (_("bad .mask directive")); | 
|  | --input_line_pointer; | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | cur_proc_ptr->pdr.regmask = val; | 
|  | cur_proc_ptr->pdr.regoffset = get_absolute_expression (); | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  |  | 
|  | /* Parse .loc directives.  */ | 
|  |  | 
|  | void | 
|  | ecoff_directive_loc (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | lineno_list_t *list; | 
|  | symint_t lineno; | 
|  |  | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | { | 
|  | as_warn (_(".loc before .file")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (now_seg != text_section) | 
|  | { | 
|  | as_warn (_(".loc outside of .text")); | 
|  | demand_empty_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Skip the file number.  */ | 
|  | SKIP_WHITESPACE (); | 
|  | get_absolute_expression (); | 
|  | SKIP_WHITESPACE (); | 
|  |  | 
|  | lineno = get_absolute_expression (); | 
|  |  | 
|  | #ifndef NO_LISTING | 
|  | if (listing) | 
|  | listing_source_line (lineno); | 
|  | #endif | 
|  |  | 
|  | /* If we're building stabs, then output a special label rather than | 
|  | ECOFF line number info.  */ | 
|  | if (stabs_seen) | 
|  | { | 
|  | (void) add_ecoff_symbol ((char *) NULL, st_Label, sc_Text, | 
|  | symbol_new (FAKE_LABEL_NAME, now_seg, | 
|  | frag_now, frag_now_fix ()), | 
|  | (bfd_vma) 0, 0, lineno); | 
|  | return; | 
|  | } | 
|  |  | 
|  | list = allocate_lineno_list (); | 
|  |  | 
|  | list->next = (lineno_list_t *) NULL; | 
|  | list->file = cur_file_ptr; | 
|  | list->proc = cur_proc_ptr; | 
|  | list->frag = frag_now; | 
|  | list->paddr = frag_now_fix (); | 
|  | list->lineno = lineno; | 
|  |  | 
|  | /* We don't want to merge files which have line numbers.  */ | 
|  | cur_file_ptr->fdr.fMerge = 0; | 
|  |  | 
|  | /* A .loc directive will sometimes appear before a .ent directive, | 
|  | which means that cur_proc_ptr will be NULL here.  Arrange to | 
|  | patch this up.  */ | 
|  | if (cur_proc_ptr == (proc_t *) NULL) | 
|  | { | 
|  | lineno_list_t **pl; | 
|  |  | 
|  | pl = &noproc_lineno; | 
|  | while (*pl != (lineno_list_t *) NULL) | 
|  | pl = &(*pl)->next; | 
|  | *pl = list; | 
|  | } | 
|  | else | 
|  | { | 
|  | last_lineno = list; | 
|  | *last_lineno_ptr = list; | 
|  | last_lineno_ptr = &list->next; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* The MIPS assembler sometimes inserts nop instructions in the | 
|  | instruction stream.  When this happens, we must patch up the .loc | 
|  | information so that it points to the instruction after the nop.  */ | 
|  |  | 
|  | void | 
|  | ecoff_fix_loc (fragS *old_frag, unsigned long old_frag_offset) | 
|  | { | 
|  | if (last_lineno != NULL | 
|  | && last_lineno->frag == old_frag | 
|  | && last_lineno->paddr == old_frag_offset) | 
|  | { | 
|  | last_lineno->frag = frag_now; | 
|  | last_lineno->paddr = frag_now_fix (); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Make sure the @stabs symbol is emitted.  */ | 
|  |  | 
|  | static void | 
|  | mark_stabs (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | if (! stabs_seen) | 
|  | { | 
|  | /* Add a dummy @stabs symbol.  */ | 
|  | stabs_seen = 1; | 
|  | (void) add_ecoff_symbol (stabs_symbol, st_Nil, sc_Info, | 
|  | (symbolS *) NULL, | 
|  | (bfd_vma) 0, (symint_t) -1, | 
|  | ECOFF_MARK_STAB (0)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Parse .weakext directives.  */ | 
|  | #ifndef TC_MIPS | 
|  | /* For TC_MIPS use the version in tc-mips.c.  */ | 
|  | void | 
|  | ecoff_directive_weakext (int ignore ATTRIBUTE_UNUSED) | 
|  | { | 
|  | char *name; | 
|  | int c; | 
|  | symbolS *symbolP; | 
|  | expressionS exp; | 
|  |  | 
|  | c = get_symbol_name (&name); | 
|  | symbolP = symbol_find_or_make (name); | 
|  | (void) restore_line_pointer (c); | 
|  |  | 
|  | SKIP_WHITESPACE (); | 
|  |  | 
|  | if (*input_line_pointer == ',') | 
|  | { | 
|  | if (S_IS_DEFINED (symbolP)) | 
|  | { | 
|  | as_bad (_("symbol `%s' is already defined"), | 
|  | S_GET_NAME (symbolP)); | 
|  | ignore_rest_of_line (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | ++input_line_pointer; | 
|  | SKIP_WHITESPACE (); | 
|  | if (! is_end_of_line[(unsigned char) *input_line_pointer]) | 
|  | { | 
|  | expression (&exp); | 
|  | if (exp.X_op != O_symbol) | 
|  | { | 
|  | as_bad (_("bad .weakext directive")); | 
|  | ignore_rest_of_line (); | 
|  | return; | 
|  | } | 
|  | symbol_set_value_expression (symbolP, &exp); | 
|  | } | 
|  | } | 
|  |  | 
|  | S_SET_WEAK (symbolP); | 
|  |  | 
|  | demand_empty_rest_of_line (); | 
|  | } | 
|  | #endif /* not TC_MIPS */ | 
|  |  | 
|  | /* Handle .stabs directives.  The actual parsing routine is done by a | 
|  | generic routine.  This routine is called via OBJ_PROCESS_STAB. | 
|  | When this is called, input_line_pointer will be pointing at the | 
|  | value field of the stab. | 
|  |  | 
|  | .stabs directives have five fields: | 
|  | "string"	a string, encoding the type information. | 
|  | code		a numeric code, defined in <stab.h> | 
|  | 0		a zero | 
|  | desc		a zero or line number | 
|  | value		a numeric value or an address. | 
|  |  | 
|  | If the value is relocatable, we transform this into: | 
|  | iss		points as an index into string space | 
|  | value		value from lookup of the name | 
|  | st		st from lookup of the name | 
|  | sc		sc from lookup of the name | 
|  | index		code|CODE_MASK | 
|  |  | 
|  | If the value is not relocatable, we transform this into: | 
|  | iss		points as an index into string space | 
|  | value		value | 
|  | st		st_Nil | 
|  | sc		sc_Nil | 
|  | index		code|CODE_MASK | 
|  |  | 
|  | .stabn directives have four fields (string is null): | 
|  | code		a numeric code, defined in <stab.h> | 
|  | 0		a zero | 
|  | desc		a zero or a line number | 
|  | value		a numeric value or an address.  */ | 
|  |  | 
|  | void | 
|  | ecoff_stab (segT sec ATTRIBUTE_UNUSED, | 
|  | int what, | 
|  | const char *string, | 
|  | int type, | 
|  | int other, | 
|  | int desc) | 
|  | { | 
|  | efdr_t *save_file_ptr = cur_file_ptr; | 
|  | symbolS *sym; | 
|  | symint_t value; | 
|  | bfd_vma addend; | 
|  | st_t st; | 
|  | sc_t sc; | 
|  | symint_t indx; | 
|  | localsym_t *hold = NULL; | 
|  |  | 
|  | ecoff_debugging_seen = 1; | 
|  |  | 
|  | /* We don't handle .stabd.  */ | 
|  | if (what != 's' && what != 'n') | 
|  | { | 
|  | as_bad (_(".stab%c is not supported"), what); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* A .stabn uses a null name, not an empty string.  */ | 
|  | if (what == 'n') | 
|  | string = NULL; | 
|  |  | 
|  | /* We ignore the other field.  */ | 
|  | if (other != 0) | 
|  | as_warn (_(".stab%c: ignoring non-zero other field"), what); | 
|  |  | 
|  | /* Make sure we have a current file.  */ | 
|  | if (cur_file_ptr == (efdr_t *) NULL) | 
|  | { | 
|  | add_file ((const char *) NULL, 0, 1); | 
|  | save_file_ptr = cur_file_ptr; | 
|  | } | 
|  |  | 
|  | /* For stabs in ECOFF, the first symbol must be @stabs.  This is a | 
|  | signal to gdb.  */ | 
|  | if (stabs_seen == 0) | 
|  | mark_stabs (0); | 
|  |  | 
|  | /* Line number stabs are handled differently, since they have two | 
|  | values, the line number and the address of the label.  We use the | 
|  | index field (aka desc) to hold the line number, and the value | 
|  | field to hold the address.  The symbol type is st_Label, which | 
|  | should be different from the other stabs, so that gdb can | 
|  | recognize it.  */ | 
|  | if (type == N_SLINE) | 
|  | { | 
|  | SYMR dummy_symr; | 
|  | char *name; | 
|  | char name_end; | 
|  |  | 
|  | #ifndef NO_LISTING | 
|  | if (listing) | 
|  | listing_source_line ((unsigned int) desc); | 
|  | #endif | 
|  |  | 
|  | dummy_symr.index = desc; | 
|  | if (dummy_symr.index != desc) | 
|  | { | 
|  | as_warn (_("line number (%d) for .stab%c directive cannot fit in index field (20 bits)"), | 
|  | desc, what); | 
|  | return; | 
|  | } | 
|  |  | 
|  | name_end = get_symbol_name (&name); | 
|  | sym = symbol_find_or_make (name); | 
|  | (void) restore_line_pointer (name_end); | 
|  |  | 
|  | value = 0; | 
|  | addend = 0; | 
|  | st = st_Label; | 
|  | sc = sc_Text; | 
|  | indx = desc; | 
|  | } | 
|  | else | 
|  | { | 
|  | #ifndef NO_LISTING | 
|  | if (listing && (type == N_SO || type == N_SOL)) | 
|  | listing_source_file (string); | 
|  | #endif | 
|  |  | 
|  | if (ISDIGIT (*input_line_pointer) | 
|  | || *input_line_pointer == '-' | 
|  | || *input_line_pointer == '+') | 
|  | { | 
|  | st = st_Nil; | 
|  | sc = sc_Nil; | 
|  | sym = (symbolS *) NULL; | 
|  | value = get_absolute_expression (); | 
|  | addend = 0; | 
|  | } | 
|  | else if (! is_name_beginner ((unsigned char) *input_line_pointer)) | 
|  | { | 
|  | as_warn (_("illegal .stab%c directive, bad character"), what); | 
|  | return; | 
|  | } | 
|  | else | 
|  | { | 
|  | expressionS exp; | 
|  |  | 
|  | sc = sc_Nil; | 
|  | st = st_Nil; | 
|  |  | 
|  | expression (&exp); | 
|  | if (exp.X_op == O_constant) | 
|  | { | 
|  | sym = NULL; | 
|  | value = exp.X_add_number; | 
|  | addend = 0; | 
|  | } | 
|  | else if (exp.X_op == O_symbol) | 
|  | { | 
|  | sym = exp.X_add_symbol; | 
|  | value = 0; | 
|  | addend = exp.X_add_number; | 
|  | } | 
|  | else | 
|  | { | 
|  | sym = make_expr_symbol (&exp); | 
|  | value = 0; | 
|  | addend = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | indx = ECOFF_MARK_STAB (type); | 
|  | } | 
|  |  | 
|  | /* Don't store the stabs symbol we are creating as the type of the | 
|  | ECOFF symbol.  We want to compute the type of the ECOFF symbol | 
|  | independently.  */ | 
|  | if (sym != (symbolS *) NULL) | 
|  | hold = symbol_get_obj (sym)->ecoff_symbol; | 
|  |  | 
|  | (void) add_ecoff_symbol (string, st, sc, sym, addend, value, indx); | 
|  |  | 
|  | if (sym != (symbolS *) NULL) | 
|  | symbol_get_obj (sym)->ecoff_symbol = hold; | 
|  |  | 
|  | /* Restore normal file type.  */ | 
|  | cur_file_ptr = save_file_ptr; | 
|  | } | 
|  |  | 
|  | static asection ecoff_scom_section; | 
|  | static const asymbol ecoff_scom_symbol = | 
|  | GLOBAL_SYM_INIT (SCOMMON, &ecoff_scom_section); | 
|  | static asection ecoff_scom_section = | 
|  | BFD_FAKE_SECTION (ecoff_scom_section, &ecoff_scom_symbol, | 
|  | SCOMMON, 0, SEC_IS_COMMON | SEC_SMALL_DATA); | 
|  |  | 
|  | /* Frob an ECOFF symbol.  Small common symbols go into a special | 
|  | .scommon section rather than bfd_com_section.  */ | 
|  |  | 
|  | void | 
|  | ecoff_frob_symbol (symbolS *sym) | 
|  | { | 
|  | if (S_IS_COMMON (sym) | 
|  | && S_GET_VALUE (sym) > 0 | 
|  | && S_GET_VALUE (sym) <= bfd_get_gp_size (stdoutput)) | 
|  | { | 
|  | S_SET_SEGMENT (sym, &ecoff_scom_section); | 
|  | } | 
|  |  | 
|  | /* Double check weak symbols.  */ | 
|  | if (S_IS_WEAK (sym)) | 
|  | { | 
|  | if (S_IS_COMMON (sym)) | 
|  | as_bad (_("symbol `%s' can not be both weak and common"), | 
|  | S_GET_NAME (sym)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Add bytes to the symbolic information buffer.  */ | 
|  |  | 
|  | static char * | 
|  | ecoff_add_bytes (char **buf, | 
|  | char **bufend, | 
|  | char *bufptr, | 
|  | unsigned long need) | 
|  | { | 
|  | unsigned long at; | 
|  | unsigned long want; | 
|  |  | 
|  | at = bufptr - *buf; | 
|  | need -= *bufend - bufptr; | 
|  | if (need < PAGE_SIZE) | 
|  | need = PAGE_SIZE; | 
|  | want = (*bufend - *buf) + need; | 
|  | *buf = XRESIZEVEC (char, *buf, want); | 
|  | *bufend = *buf + want; | 
|  | return *buf + at; | 
|  | } | 
|  |  | 
|  | /* Adjust the symbolic information buffer to the alignment required | 
|  | for the ECOFF target debugging information.  */ | 
|  |  | 
|  | static unsigned long | 
|  | ecoff_padding_adjust (const struct ecoff_debug_swap *backend, | 
|  | char **buf, | 
|  | char **bufend, | 
|  | unsigned long offset, | 
|  | char **bufptrptr) | 
|  | { | 
|  | bfd_size_type align; | 
|  |  | 
|  | align = backend->debug_align; | 
|  | if ((offset & (align - 1)) != 0) | 
|  | { | 
|  | unsigned long add; | 
|  |  | 
|  | add = align - (offset & (align - 1)); | 
|  | if ((unsigned long) (*bufend - (*buf + offset)) < add) | 
|  | (void) ecoff_add_bytes (buf, bufend, *buf + offset, add); | 
|  | memset (*buf + offset, 0, add); | 
|  | offset += add; | 
|  | if (bufptrptr != (char **) NULL) | 
|  | *bufptrptr = *buf + offset; | 
|  | } | 
|  |  | 
|  | return offset; | 
|  | } | 
|  |  | 
|  | /* Build the line number information.  */ | 
|  |  | 
|  | static unsigned long | 
|  | ecoff_build_lineno (const struct ecoff_debug_swap *backend, | 
|  | char **buf, | 
|  | char **bufend, | 
|  | unsigned long offset, | 
|  | long *linecntptr) | 
|  | { | 
|  | char *bufptr; | 
|  | lineno_list_t *l; | 
|  | lineno_list_t *last; | 
|  | efdr_t *file; | 
|  | proc_t *proc; | 
|  | unsigned long c; | 
|  | long iline; | 
|  | long totcount; | 
|  | lineno_list_t first; | 
|  | lineno_list_t *local_first_lineno = first_lineno; | 
|  |  | 
|  | if (linecntptr != (long *) NULL) | 
|  | *linecntptr = 0; | 
|  |  | 
|  | bufptr = *buf + offset; | 
|  |  | 
|  | file = (efdr_t *) NULL; | 
|  | proc = (proc_t *) NULL; | 
|  | last = (lineno_list_t *) NULL; | 
|  | c = offset; | 
|  | iline = 0; | 
|  | totcount = 0; | 
|  |  | 
|  | /* FIXME?  Now that MIPS embedded-PIC is gone, it may be safe to | 
|  | remove this code.  */ | 
|  | /* For some reason the address of the first procedure is ignored | 
|  | when reading line numbers.  This doesn't matter if the address of | 
|  | the first procedure is 0, but when gcc is generating MIPS | 
|  | embedded PIC code, it will put strings in the .text section | 
|  | before the first procedure.  We cope by inserting a dummy line if | 
|  | the address of the first procedure is not 0.  Hopefully this | 
|  | won't screw things up too badly. | 
|  |  | 
|  | Don't do this for ECOFF assembly source line numbers.  They work | 
|  | without this extra attention.  */ | 
|  | if (debug_type != DEBUG_ECOFF | 
|  | && first_proc_ptr != (proc_t *) NULL | 
|  | && local_first_lineno != (lineno_list_t *) NULL | 
|  | && ((S_GET_VALUE (first_proc_ptr->sym->as_sym) | 
|  | + bfd_section_vma (S_GET_SEGMENT (first_proc_ptr->sym->as_sym))) | 
|  | != 0)) | 
|  | { | 
|  | first.file = local_first_lineno->file; | 
|  | first.proc = local_first_lineno->proc; | 
|  | first.frag = &zero_address_frag; | 
|  | first.paddr = 0; | 
|  | first.lineno = 0; | 
|  |  | 
|  | first.next = local_first_lineno; | 
|  | local_first_lineno = &first; | 
|  | } | 
|  |  | 
|  | for (l = local_first_lineno; l != (lineno_list_t *) NULL; l = l->next) | 
|  | { | 
|  | long count; | 
|  | long delta; | 
|  |  | 
|  | /* Get the offset to the memory address of the next line number | 
|  | (in words).  Do this first, so that we can skip ahead to the | 
|  | next useful line number entry.  */ | 
|  | if (l->next == (lineno_list_t *) NULL) | 
|  | { | 
|  | /* We want a count of zero, but it will be decremented | 
|  | before it is used.  */ | 
|  | count = 1; | 
|  | } | 
|  | else if (l->next->frag->fr_address + l->next->paddr | 
|  | > l->frag->fr_address + l->paddr) | 
|  | { | 
|  | count = ((l->next->frag->fr_address + l->next->paddr | 
|  | - (l->frag->fr_address + l->paddr)) | 
|  | >> 2); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Don't change last, so we still get the right delta.  */ | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (l->file != file || l->proc != proc) | 
|  | { | 
|  | if (l->proc != proc && proc != (proc_t *) NULL) | 
|  | proc->pdr.lnHigh = last->lineno; | 
|  | if (l->file != file && file != (efdr_t *) NULL) | 
|  | { | 
|  | file->fdr.cbLine = c - file->fdr.cbLineOffset; | 
|  | file->fdr.cline = totcount + count; | 
|  | if (linecntptr != (long *) NULL) | 
|  | *linecntptr += totcount + count; | 
|  | totcount = 0; | 
|  | } | 
|  |  | 
|  | if (l->file != file) | 
|  | { | 
|  | efdr_t *last_file = file; | 
|  |  | 
|  | file = l->file; | 
|  | if (last_file != (efdr_t *) NULL) | 
|  | file->fdr.ilineBase | 
|  | = last_file->fdr.ilineBase + last_file->fdr.cline; | 
|  | else | 
|  | file->fdr.ilineBase = 0; | 
|  | file->fdr.cbLineOffset = c; | 
|  | } | 
|  | if (l->proc != proc) | 
|  | { | 
|  | proc = l->proc; | 
|  | if (proc != (proc_t *) NULL) | 
|  | { | 
|  | proc->pdr.lnLow = l->lineno; | 
|  | proc->pdr.cbLineOffset = c - file->fdr.cbLineOffset; | 
|  | proc->pdr.iline = totcount; | 
|  | } | 
|  | } | 
|  |  | 
|  | last = (lineno_list_t *) NULL; | 
|  | } | 
|  |  | 
|  | totcount += count; | 
|  |  | 
|  | /* Get the offset to this line number.  */ | 
|  | if (last == (lineno_list_t *) NULL) | 
|  | delta = 0; | 
|  | else | 
|  | delta = l->lineno - last->lineno; | 
|  |  | 
|  | /* Put in the offset to this line number.  */ | 
|  | while (delta != 0) | 
|  | { | 
|  | int setcount; | 
|  |  | 
|  | /* 1 is added to each count read.  */ | 
|  | --count; | 
|  | /* We can only adjust the word count by up to 15 words at a | 
|  | time.  */ | 
|  | if (count <= 0x0f) | 
|  | { | 
|  | setcount = count; | 
|  | count = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | setcount = 0x0f; | 
|  | count -= 0x0f; | 
|  | } | 
|  | if (delta >= -7 && delta <= 7) | 
|  | { | 
|  | if (bufptr >= *bufend) | 
|  | bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 1); | 
|  | *bufptr++ = setcount + (delta << 4); | 
|  | delta = 0; | 
|  | ++c; | 
|  | } | 
|  | else | 
|  | { | 
|  | int set; | 
|  |  | 
|  | if (*bufend - bufptr < 3) | 
|  | bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 3); | 
|  | *bufptr++ = setcount + (8 << 4); | 
|  | if (delta < -0x8000) | 
|  | { | 
|  | set = -0x8000; | 
|  | delta += 0x8000; | 
|  | } | 
|  | else if (delta > 0x7fff) | 
|  | { | 
|  | set = 0x7fff; | 
|  | delta -= 0x7fff; | 
|  | } | 
|  | else | 
|  | { | 
|  | set = delta; | 
|  | delta = 0; | 
|  | } | 
|  | *bufptr++ = set >> 8; | 
|  | *bufptr++ = set & 0xffff; | 
|  | c += 3; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Finish adjusting the count.  */ | 
|  | while (count > 0) | 
|  | { | 
|  | if (bufptr >= *bufend) | 
|  | bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 1); | 
|  | /* 1 is added to each count read.  */ | 
|  | --count; | 
|  | if (count > 0x0f) | 
|  | { | 
|  | *bufptr++ = 0x0f; | 
|  | count -= 0x0f; | 
|  | } | 
|  | else | 
|  | { | 
|  | *bufptr++ = count; | 
|  | count = 0; | 
|  | } | 
|  | ++c; | 
|  | } | 
|  |  | 
|  | ++iline; | 
|  | last = l; | 
|  | } | 
|  |  | 
|  | if (proc != (proc_t *) NULL) | 
|  | proc->pdr.lnHigh = last->lineno; | 
|  | if (file != (efdr_t *) NULL) | 
|  | { | 
|  | file->fdr.cbLine = c - file->fdr.cbLineOffset; | 
|  | file->fdr.cline = totcount; | 
|  | } | 
|  |  | 
|  | if (linecntptr != (long *) NULL) | 
|  | *linecntptr += totcount; | 
|  |  | 
|  | c = ecoff_padding_adjust (backend, buf, bufend, c, &bufptr); | 
|  |  | 
|  | return c; | 
|  | } | 
|  |  | 
|  | /* Build and swap out the symbols.  */ | 
|  |  | 
|  | static unsigned long | 
|  | ecoff_build_symbols (const struct ecoff_debug_swap *backend, | 
|  | char **buf, | 
|  | char **bufend, | 
|  | unsigned long offset) | 
|  | { | 
|  | const bfd_size_type external_sym_size = backend->external_sym_size; | 
|  | void (* const swap_sym_out) (bfd *, const SYMR *, void *) | 
|  | = backend->swap_sym_out; | 
|  | char *sym_out; | 
|  | long isym; | 
|  | vlinks_t *file_link; | 
|  |  | 
|  | sym_out = *buf + offset; | 
|  |  | 
|  | isym = 0; | 
|  |  | 
|  | /* The symbols are stored by file.  */ | 
|  | for (file_link = file_desc.first; | 
|  | file_link != (vlinks_t *) NULL; | 
|  | file_link = file_link->next) | 
|  | { | 
|  | int ifilesym; | 
|  | int fil_cnt; | 
|  | efdr_t *fil_ptr; | 
|  | efdr_t *fil_end; | 
|  |  | 
|  | if (file_link->next == (vlinks_t *) NULL) | 
|  | fil_cnt = file_desc.objects_last_page; | 
|  | else | 
|  | fil_cnt = file_desc.objects_per_page; | 
|  | fil_ptr = file_link->datum->file; | 
|  | fil_end = fil_ptr + fil_cnt; | 
|  | for (; fil_ptr < fil_end; fil_ptr++) | 
|  | { | 
|  | vlinks_t *sym_link; | 
|  |  | 
|  | fil_ptr->fdr.isymBase = isym; | 
|  | ifilesym = isym; | 
|  | for (sym_link = fil_ptr->symbols.first; | 
|  | sym_link != (vlinks_t *) NULL; | 
|  | sym_link = sym_link->next) | 
|  | { | 
|  | int sym_cnt; | 
|  | localsym_t *sym_ptr; | 
|  | localsym_t *sym_end; | 
|  |  | 
|  | if (sym_link->next == (vlinks_t *) NULL) | 
|  | sym_cnt = fil_ptr->symbols.objects_last_page; | 
|  | else | 
|  | sym_cnt = fil_ptr->symbols.objects_per_page; | 
|  | sym_ptr = sym_link->datum->sym; | 
|  | sym_end = sym_ptr + sym_cnt; | 
|  | for (; sym_ptr < sym_end; sym_ptr++) | 
|  | { | 
|  | int local; | 
|  | symbolS *as_sym; | 
|  | forward_t *f; | 
|  |  | 
|  | know (sym_ptr->file_ptr == fil_ptr); | 
|  |  | 
|  | /* If there is no associated gas symbol, then this | 
|  | is a pure debugging symbol.  We have already | 
|  | added the name (if any) to fil_ptr->strings. | 
|  | Otherwise we must decide whether this is an | 
|  | external or a local symbol (actually, it may be | 
|  | both if the local provides additional debugging | 
|  | information for the external).  */ | 
|  | local = 1; | 
|  | as_sym = sym_ptr->as_sym; | 
|  | if (as_sym != (symbolS *) NULL) | 
|  | { | 
|  | symint_t indx; | 
|  |  | 
|  | /* The value of a block start symbol is the | 
|  | offset from the start of the procedure.  For | 
|  | other symbols we just use the gas value (but | 
|  | we must offset it by the vma of the section, | 
|  | just as BFD does, because BFD will not see | 
|  | this value).  */ | 
|  | if (sym_ptr->ecoff_sym.asym.st == (int) st_Block | 
|  | && sym_ptr->ecoff_sym.asym.sc == (int) sc_Text) | 
|  | { | 
|  | symbolS *begin_sym; | 
|  |  | 
|  | know (sym_ptr->proc_ptr != (proc_t *) NULL); | 
|  | begin_sym = sym_ptr->proc_ptr->sym->as_sym; | 
|  | if (S_GET_SEGMENT (as_sym) | 
|  | != S_GET_SEGMENT (begin_sym)) | 
|  | as_warn (_(".begin/.bend in different segments")); | 
|  | sym_ptr->ecoff_sym.asym.value = | 
|  | S_GET_VALUE (as_sym) - S_GET_VALUE (begin_sym); | 
|  | } | 
|  | else | 
|  | sym_ptr->ecoff_sym.asym.value = | 
|  | (S_GET_VALUE (as_sym) | 
|  | + bfd_section_vma (S_GET_SEGMENT (as_sym)) | 
|  | + sym_ptr->addend); | 
|  |  | 
|  | sym_ptr->ecoff_sym.weakext = S_IS_WEAK (as_sym); | 
|  |  | 
|  | /* Set st_Proc to st_StaticProc for local | 
|  | functions.  */ | 
|  | if (sym_ptr->ecoff_sym.asym.st == st_Proc | 
|  | && S_IS_DEFINED (as_sym) | 
|  | && ! S_IS_EXTERNAL (as_sym) | 
|  | && ! S_IS_WEAK (as_sym)) | 
|  | sym_ptr->ecoff_sym.asym.st = st_StaticProc; | 
|  |  | 
|  | /* Get the type and storage class based on where | 
|  | the symbol actually wound up.  Traditionally, | 
|  | N_LBRAC and N_RBRAC are *not* relocated.  */ | 
|  | indx = sym_ptr->ecoff_sym.asym.index; | 
|  | if (sym_ptr->ecoff_sym.asym.st == st_Nil | 
|  | && sym_ptr->ecoff_sym.asym.sc == sc_Nil | 
|  | && (! ECOFF_IS_STAB (&sym_ptr->ecoff_sym.asym) | 
|  | || ((ECOFF_UNMARK_STAB (indx) != N_LBRAC) | 
|  | && (ECOFF_UNMARK_STAB (indx) != N_RBRAC)))) | 
|  | { | 
|  | segT seg; | 
|  | const char *segname; | 
|  | st_t st; | 
|  | sc_t sc; | 
|  |  | 
|  | seg = S_GET_SEGMENT (as_sym); | 
|  | segname = segment_name (seg); | 
|  |  | 
|  | if (! ECOFF_IS_STAB (&sym_ptr->ecoff_sym.asym) | 
|  | && (S_IS_EXTERNAL (as_sym) | 
|  | || S_IS_WEAK (as_sym) | 
|  | || ! S_IS_DEFINED (as_sym))) | 
|  | { | 
|  | if ((symbol_get_bfdsym (as_sym)->flags | 
|  | & BSF_FUNCTION) != 0) | 
|  | st = st_Proc; | 
|  | else | 
|  | st = st_Global; | 
|  | } | 
|  | else if (seg == text_section) | 
|  | st = st_Label; | 
|  | else | 
|  | st = st_Static; | 
|  |  | 
|  | if (! S_IS_DEFINED (as_sym)) | 
|  | { | 
|  | valueT s; | 
|  |  | 
|  | s = symbol_get_obj (as_sym)->ecoff_extern_size; | 
|  | if (s == 0 | 
|  | || s > bfd_get_gp_size (stdoutput)) | 
|  | sc = sc_Undefined; | 
|  | else | 
|  | { | 
|  | sc = sc_SUndefined; | 
|  | sym_ptr->ecoff_sym.asym.value = s; | 
|  | } | 
|  | #ifdef S_SET_SIZE | 
|  | S_SET_SIZE (as_sym, s); | 
|  | #endif | 
|  | } | 
|  | else if (S_IS_COMMON (as_sym)) | 
|  | { | 
|  | if (S_GET_VALUE (as_sym) > 0 | 
|  | && (S_GET_VALUE (as_sym) | 
|  | <= bfd_get_gp_size (stdoutput))) | 
|  | sc = sc_SCommon; | 
|  | else | 
|  | sc = sc_Common; | 
|  | } | 
|  | else if (seg == text_section) | 
|  | sc = sc_Text; | 
|  | else if (seg == data_section) | 
|  | sc = sc_Data; | 
|  | else if (strcmp (segname, ".rdata") == 0 | 
|  | || strcmp (segname, ".rodata") == 0) | 
|  | sc = sc_RData; | 
|  | else if (strcmp (segname, ".sdata") == 0) | 
|  | sc = sc_SData; | 
|  | else if (seg == bss_section) | 
|  | sc = sc_Bss; | 
|  | else if (strcmp (segname, ".sbss") == 0) | 
|  | sc = sc_SBss; | 
|  | else if (seg == bfd_abs_section_ptr) | 
|  | sc = sc_Abs; | 
|  | else | 
|  | { | 
|  | /* This must be a user named section. | 
|  | This is not possible in ECOFF, but it | 
|  | is in ELF.  */ | 
|  | sc = sc_Data; | 
|  | } | 
|  |  | 
|  | sym_ptr->ecoff_sym.asym.st = (int) st; | 
|  | sym_ptr->ecoff_sym.asym.sc = (int) sc; | 
|  | } | 
|  |  | 
|  | /* This is just an external symbol if it is | 
|  | outside a procedure and it has a type. | 
|  | FIXME: g++ will generate symbols which have | 
|  | different names in the debugging information | 
|  | than the actual symbol.  Should we handle | 
|  | them here?  */ | 
|  | if ((S_IS_EXTERNAL (as_sym) | 
|  | || S_IS_WEAK (as_sym) | 
|  | || ! S_IS_DEFINED (as_sym)) | 
|  | && sym_ptr->proc_ptr == (proc_t *) NULL | 
|  | && sym_ptr->ecoff_sym.asym.st != (int) st_Nil | 
|  | && ! ECOFF_IS_STAB (&sym_ptr->ecoff_sym.asym)) | 
|  | local = 0; | 
|  |  | 
|  | /* This is just an external symbol if it is a | 
|  | common symbol.  */ | 
|  | if (S_IS_COMMON (as_sym)) | 
|  | local = 0; | 
|  |  | 
|  | /* If an st_end symbol has an associated gas | 
|  | symbol, then it is a local label created for | 
|  | a .bend or .end directive.  Stabs line | 
|  | numbers will have FAKE_LABEL_CHAR in the names.  */ | 
|  | if (local | 
|  | && sym_ptr->ecoff_sym.asym.st != st_End | 
|  | && strchr (sym_ptr->name, FAKE_LABEL_CHAR) == 0) | 
|  | sym_ptr->ecoff_sym.asym.iss = | 
|  | add_string (&fil_ptr->strings, | 
|  | fil_ptr->str_hash, | 
|  | sym_ptr->name, | 
|  | (shash_t **) NULL); | 
|  | } | 
|  |  | 
|  | /* We now know the index of this symbol; fill in | 
|  | locations that have been waiting for that | 
|  | information.  */ | 
|  | if (sym_ptr->begin_ptr != (localsym_t *) NULL) | 
|  | { | 
|  | localsym_t *begin_ptr; | 
|  | st_t begin_type; | 
|  |  | 
|  | know (local); | 
|  | begin_ptr = sym_ptr->begin_ptr; | 
|  | know (begin_ptr->sym_index != -1); | 
|  | sym_ptr->ecoff_sym.asym.index = begin_ptr->sym_index; | 
|  | if (sym_ptr->ecoff_sym.asym.sc != (int) sc_Info) | 
|  | sym_ptr->ecoff_sym.asym.iss = | 
|  | begin_ptr->ecoff_sym.asym.iss; | 
|  |  | 
|  | begin_type = (st_t) begin_ptr->ecoff_sym.asym.st; | 
|  | if (begin_type == st_File | 
|  | || begin_type == st_Block) | 
|  | { | 
|  | begin_ptr->ecoff_sym.asym.index = | 
|  | isym - ifilesym + 1; | 
|  | (*swap_sym_out) (stdoutput, | 
|  | &begin_ptr->ecoff_sym.asym, | 
|  | (*buf | 
|  | + offset | 
|  | + (begin_ptr->sym_index | 
|  | * external_sym_size))); | 
|  | } | 
|  | else | 
|  | { | 
|  | know (begin_ptr->index_ptr != (aux_t *) NULL); | 
|  | begin_ptr->index_ptr->data.isym = | 
|  | isym - ifilesym + 1; | 
|  | } | 
|  |  | 
|  | /* The value of the symbol marking the end of a | 
|  | procedure is the size of the procedure.  The | 
|  | value of the symbol marking the end of a | 
|  | block is the offset from the start of the | 
|  | procedure to the block.  */ | 
|  | if (begin_type == st_Proc | 
|  | || begin_type == st_StaticProc) | 
|  | { | 
|  | know (as_sym != (symbolS *) NULL); | 
|  | know (begin_ptr->as_sym != (symbolS *) NULL); | 
|  | if (S_GET_SEGMENT (as_sym) | 
|  | != S_GET_SEGMENT (begin_ptr->as_sym)) | 
|  | as_warn (_(".begin/.bend in different segments")); | 
|  | sym_ptr->ecoff_sym.asym.value = | 
|  | (S_GET_VALUE (as_sym) | 
|  | - S_GET_VALUE (begin_ptr->as_sym)); | 
|  |  | 
|  | /* If the size is odd, this is probably a | 
|  | mips16 function; force it to be even.  */ | 
|  | if ((sym_ptr->ecoff_sym.asym.value & 1) != 0) | 
|  | ++sym_ptr->ecoff_sym.asym.value; | 
|  |  | 
|  | #ifdef S_SET_SIZE | 
|  | S_SET_SIZE (begin_ptr->as_sym, | 
|  | sym_ptr->ecoff_sym.asym.value); | 
|  | #endif | 
|  | } | 
|  | else if (begin_type == st_Block | 
|  | && sym_ptr->ecoff_sym.asym.sc != (int) sc_Info) | 
|  | { | 
|  | symbolS *begin_sym; | 
|  |  | 
|  | know (as_sym != (symbolS *) NULL); | 
|  | know (sym_ptr->proc_ptr != (proc_t *) NULL); | 
|  | begin_sym = sym_ptr->proc_ptr->sym->as_sym; | 
|  | if (S_GET_SEGMENT (as_sym) | 
|  | != S_GET_SEGMENT (begin_sym)) | 
|  | as_warn (_(".begin/.bend in different segments")); | 
|  | sym_ptr->ecoff_sym.asym.value = | 
|  | S_GET_VALUE (as_sym) - S_GET_VALUE (begin_sym); | 
|  | } | 
|  | } | 
|  |  | 
|  | for (f = sym_ptr->forward_ref; | 
|  | f != (forward_t *) NULL; | 
|  | f = f->next) | 
|  | { | 
|  | know (local); | 
|  | f->ifd_ptr->data.isym = fil_ptr->file_index; | 
|  | f->index_ptr->data.rndx.index = isym - ifilesym; | 
|  | } | 
|  |  | 
|  | if (local) | 
|  | { | 
|  | if ((bfd_size_type)(*bufend - sym_out) < external_sym_size) | 
|  | sym_out = ecoff_add_bytes (buf, bufend, | 
|  | sym_out, | 
|  | external_sym_size); | 
|  | (*swap_sym_out) (stdoutput, &sym_ptr->ecoff_sym.asym, | 
|  | sym_out); | 
|  | sym_out += external_sym_size; | 
|  |  | 
|  | sym_ptr->sym_index = isym; | 
|  |  | 
|  | if (sym_ptr->proc_ptr != (proc_t *) NULL | 
|  | && sym_ptr->proc_ptr->sym == sym_ptr) | 
|  | sym_ptr->proc_ptr->pdr.isym = isym - ifilesym; | 
|  |  | 
|  | ++isym; | 
|  | } | 
|  |  | 
|  | /* Record the local symbol index and file number in | 
|  | case this is an external symbol.  Note that this | 
|  | destroys the asym.index field.  */ | 
|  | if (as_sym != (symbolS *) NULL | 
|  | && symbol_get_obj (as_sym)->ecoff_symbol == sym_ptr) | 
|  | { | 
|  | if ((sym_ptr->ecoff_sym.asym.st == st_Proc | 
|  | || sym_ptr->ecoff_sym.asym.st == st_StaticProc) | 
|  | && local) | 
|  | sym_ptr->ecoff_sym.asym.index = isym - ifilesym - 1; | 
|  | sym_ptr->ecoff_sym.ifd = fil_ptr->file_index; | 
|  |  | 
|  | /* Don't try to merge an FDR which has an | 
|  | external symbol attached to it.  */ | 
|  | if (S_IS_EXTERNAL (as_sym) || S_IS_WEAK (as_sym)) | 
|  | fil_ptr->fdr.fMerge = 0; | 
|  | } | 
|  | } | 
|  | } | 
|  | fil_ptr->fdr.csym = isym - fil_ptr->fdr.isymBase; | 
|  | } | 
|  | } | 
|  |  | 
|  | return offset + isym * external_sym_size; | 
|  | } | 
|  |  | 
|  | /* Swap out the procedure information.  */ | 
|  |  | 
|  | static unsigned long | 
|  | ecoff_build_procs (const struct ecoff_debug_swap *backend, | 
|  | char **buf, | 
|  | char **bufend, | 
|  | unsigned long offset) | 
|  | { | 
|  | const bfd_size_type external_pdr_size = backend->external_pdr_size; | 
|  | void (* const swap_pdr_out) (bfd *, const PDR *, void *) | 
|  | = backend->swap_pdr_out; | 
|  | char *pdr_out; | 
|  | long iproc; | 
|  | vlinks_t *file_link; | 
|  |  | 
|  | pdr_out = *buf + offset; | 
|  |  | 
|  | iproc = 0; | 
|  |  | 
|  | /* The procedures are stored by file.  */ | 
|  | for (file_link = file_desc.first; | 
|  | file_link != (vlinks_t *) NULL; | 
|  | file_link = file_link->next) | 
|  | { | 
|  | int fil_cnt; | 
|  | efdr_t *fil_ptr; | 
|  | efdr_t *fil_end; | 
|  |  | 
|  | if (file_link->next == (vlinks_t *) NULL) | 
|  | fil_cnt = file_desc.objects_last_page; | 
|  | else | 
|  | fil_cnt = file_desc.objects_per_page; | 
|  | fil_ptr = file_link->datum->file; | 
|  | fil_end = fil_ptr + fil_cnt; | 
|  | for (; fil_ptr < fil_end; fil_ptr++) | 
|  | { | 
|  | vlinks_t *proc_link; | 
|  | int first; | 
|  |  | 
|  | fil_ptr->fdr.ipdFirst = iproc; | 
|  | first = 1; | 
|  | for (proc_link = fil_ptr->procs.first; | 
|  | proc_link != (vlinks_t *) NULL; | 
|  | proc_link = proc_link->next) | 
|  | { | 
|  | int prc_cnt; | 
|  | proc_t *proc_ptr; | 
|  | proc_t *proc_end; | 
|  |  | 
|  | if (proc_link->next == (vlinks_t *) NULL) | 
|  | prc_cnt = fil_ptr->procs.objects_last_page; | 
|  | else | 
|  | prc_cnt = fil_ptr->procs.objects_per_page; | 
|  | proc_ptr = proc_link->datum->proc; | 
|  | proc_end = proc_ptr + prc_cnt; | 
|  | for (; proc_ptr < proc_end; proc_ptr++) | 
|  | { | 
|  | symbolS *adr_sym; | 
|  | unsigned long adr; | 
|  |  | 
|  | adr_sym = proc_ptr->sym->as_sym; | 
|  | adr = (S_GET_VALUE (adr_sym) | 
|  | + bfd_section_vma (S_GET_SEGMENT (adr_sym))); | 
|  | if (first) | 
|  | { | 
|  | /* This code used to force the adr of the very | 
|  | first fdr to be 0.  However, the native tools | 
|  | don't do that, and I can't remember why it | 
|  | used to work that way, so I took it out.  */ | 
|  | fil_ptr->fdr.adr = adr; | 
|  | first = 0; | 
|  | } | 
|  | proc_ptr->pdr.adr = adr - fil_ptr->fdr.adr; | 
|  | if ((bfd_size_type)(*bufend - pdr_out) < external_pdr_size) | 
|  | pdr_out = ecoff_add_bytes (buf, bufend, | 
|  | pdr_out, | 
|  | external_pdr_size); | 
|  | (*swap_pdr_out) (stdoutput, &proc_ptr->pdr, pdr_out); | 
|  | pdr_out += external_pdr_size; | 
|  | ++iproc; | 
|  | } | 
|  | } | 
|  | fil_ptr->fdr.cpd = iproc - fil_ptr->fdr.ipdFirst; | 
|  | } | 
|  | } | 
|  |  | 
|  | return offset + iproc * external_pdr_size; | 
|  | } | 
|  |  | 
|  | /* Swap out the aux information.  */ | 
|  |  | 
|  | static unsigned long | 
|  | ecoff_build_aux (const struct ecoff_debug_swap *backend, | 
|  | char **buf, | 
|  | char **bufend, | 
|  | unsigned long offset) | 
|  | { | 
|  | int bigendian; | 
|  | union aux_ext *aux_out; | 
|  | long iaux; | 
|  | vlinks_t *file_link; | 
|  |  | 
|  | bigendian = bfd_big_endian (stdoutput); | 
|  |  | 
|  | aux_out = (union aux_ext *) (*buf + offset); | 
|  |  | 
|  | iaux = 0; | 
|  |  | 
|  | /* The aux entries are stored by file.  */ | 
|  | for (file_link = file_desc.first; | 
|  | file_link != (vlinks_t *) NULL; | 
|  | file_link = file_link->next) | 
|  | { | 
|  | int fil_cnt; | 
|  | efdr_t *fil_ptr; | 
|  | efdr_t *fil_end; | 
|  |  | 
|  | if (file_link->next == (vlinks_t *) NULL) | 
|  | fil_cnt = file_desc.objects_last_page; | 
|  | else | 
|  | fil_cnt = file_desc.objects_per_page; | 
|  | fil_ptr = file_link->datum->file; | 
|  | fil_end = fil_ptr + fil_cnt; | 
|  | for (; fil_ptr < fil_end; fil_ptr++) | 
|  | { | 
|  | vlinks_t *aux_link; | 
|  |  | 
|  | fil_ptr->fdr.fBigendian = bigendian; | 
|  | fil_ptr->fdr.iauxBase = iaux; | 
|  | for (aux_link = fil_ptr->aux_syms.first; | 
|  | aux_link != (vlinks_t *) NULL; | 
|  | aux_link = aux_link->next) | 
|  | { | 
|  | int aux_cnt; | 
|  | aux_t *aux_ptr; | 
|  | aux_t *aux_end; | 
|  |  | 
|  | if (aux_link->next == (vlinks_t *) NULL) | 
|  | aux_cnt = fil_ptr->aux_syms.objects_last_page; | 
|  | else | 
|  | aux_cnt = fil_ptr->aux_syms.objects_per_page; | 
|  | aux_ptr = aux_link->datum->aux; | 
|  | aux_end = aux_ptr + aux_cnt; | 
|  | for (; aux_ptr < aux_end; aux_ptr++) | 
|  | { | 
|  | if ((unsigned long) (*bufend - (char *) aux_out) | 
|  | < sizeof (union aux_ext)) | 
|  | aux_out = ((union aux_ext *) | 
|  | ecoff_add_bytes (buf, bufend, | 
|  | (char *) aux_out, | 
|  | sizeof (union aux_ext))); | 
|  | switch (aux_ptr->type) | 
|  | { | 
|  | case aux_tir: | 
|  | (*backend->swap_tir_out) (bigendian, | 
|  | &aux_ptr->data.ti, | 
|  | &aux_out->a_ti); | 
|  | break; | 
|  | case aux_rndx: | 
|  | (*backend->swap_rndx_out) (bigendian, | 
|  | &aux_ptr->data.rndx, | 
|  | &aux_out->a_rndx); | 
|  | break; | 
|  | case aux_dnLow: | 
|  | AUX_PUT_DNLOW (bigendian, aux_ptr->data.dnLow, | 
|  | aux_out); | 
|  | break; | 
|  | case aux_dnHigh: | 
|  | AUX_PUT_DNHIGH (bigendian, aux_ptr->data.dnHigh, | 
|  | aux_out); | 
|  | break; | 
|  | case aux_isym: | 
|  | AUX_PUT_ISYM (bigendian, aux_ptr->data.isym, | 
|  | aux_out); | 
|  | break; | 
|  | case aux_iss: | 
|  | AUX_PUT_ISS (bigendian, aux_ptr->data.iss, | 
|  | aux_out); | 
|  | break; | 
|  | case aux_width: | 
|  | AUX_PUT_WIDTH (bigendian, aux_ptr->data.width, | 
|  | aux_out); | 
|  | break; | 
|  | case aux_count: | 
|  | AUX_PUT_COUNT (bigendian, aux_ptr->data.count, | 
|  | aux_out); | 
|  | break; | 
|  | } | 
|  |  | 
|  | ++aux_out; | 
|  | ++iaux; | 
|  | } | 
|  | } | 
|  | fil_ptr->fdr.caux = iaux - fil_ptr->fdr.iauxBase; | 
|  | } | 
|  | } | 
|  |  | 
|  | return ecoff_padding_adjust (backend, buf, bufend, | 
|  | offset + iaux * sizeof (union aux_ext), | 
|  | (char **) NULL); | 
|  | } | 
|  |  | 
|  | /* Copy out the strings from a varray_t.  This returns the number of | 
|  | bytes copied, rather than the new offset.  */ | 
|  |  | 
|  | static unsigned long | 
|  | ecoff_build_strings (char **buf, | 
|  | char **bufend, | 
|  | unsigned long offset, | 
|  | varray_t *vp) | 
|  | { | 
|  | unsigned long istr; | 
|  | char *str_out; | 
|  | vlinks_t *str_link; | 
|  |  | 
|  | str_out = *buf + offset; | 
|  |  | 
|  | istr = 0; | 
|  |  | 
|  | for (str_link = vp->first; | 
|  | str_link != (vlinks_t *) NULL; | 
|  | str_link = str_link->next) | 
|  | { | 
|  | unsigned long str_cnt; | 
|  |  | 
|  | if (str_link->next == (vlinks_t *) NULL) | 
|  | str_cnt = vp->objects_last_page; | 
|  | else | 
|  | str_cnt = vp->objects_per_page; | 
|  |  | 
|  | if ((unsigned long)(*bufend - str_out) < str_cnt) | 
|  | str_out = ecoff_add_bytes (buf, bufend, str_out, str_cnt); | 
|  |  | 
|  | memcpy (str_out, str_link->datum->byte, str_cnt); | 
|  | str_out += str_cnt; | 
|  | istr += str_cnt; | 
|  | } | 
|  |  | 
|  | return istr; | 
|  | } | 
|  |  | 
|  | /* Dump out the local strings.  */ | 
|  |  | 
|  | static unsigned long | 
|  | ecoff_build_ss (const struct ecoff_debug_swap *backend, | 
|  | char **buf, | 
|  | char **bufend, | 
|  | unsigned long offset) | 
|  | { | 
|  | long iss; | 
|  | vlinks_t *file_link; | 
|  |  | 
|  | iss = 0; | 
|  |  | 
|  | for (file_link = file_desc.first; | 
|  | file_link != (vlinks_t *) NULL; | 
|  | file_link = file_link->next) | 
|  | { | 
|  | int fil_cnt; | 
|  | efdr_t *fil_ptr; | 
|  | efdr_t *fil_end; | 
|  |  | 
|  | if (file_link->next == (vlinks_t *) NULL) | 
|  | fil_cnt = file_desc.objects_last_page; | 
|  | else | 
|  | fil_cnt = file_desc.objects_per_page; | 
|  | fil_ptr = file_link->datum->file; | 
|  | fil_end = fil_ptr + fil_cnt; | 
|  | for (; fil_ptr < fil_end; fil_ptr++) | 
|  | { | 
|  | long ss_cnt; | 
|  |  | 
|  | fil_ptr->fdr.issBase = iss; | 
|  | ss_cnt = ecoff_build_strings (buf, bufend, offset + iss, | 
|  | &fil_ptr->strings); | 
|  | fil_ptr->fdr.cbSs = ss_cnt; | 
|  | iss += ss_cnt; | 
|  | } | 
|  | } | 
|  |  | 
|  | return ecoff_padding_adjust (backend, buf, bufend, offset + iss, | 
|  | (char **) NULL); | 
|  | } | 
|  |  | 
|  | /* Swap out the file descriptors.  */ | 
|  |  | 
|  | static unsigned long | 
|  | ecoff_build_fdr (const struct ecoff_debug_swap *backend, | 
|  | char **buf, | 
|  | char **bufend, | 
|  | unsigned long offset) | 
|  | { | 
|  | const bfd_size_type external_fdr_size = backend->external_fdr_size; | 
|  | void (* const swap_fdr_out) (bfd *, const FDR *, void *) | 
|  | = backend->swap_fdr_out; | 
|  | long ifile; | 
|  | char *fdr_out; | 
|  | vlinks_t *file_link; | 
|  |  | 
|  | ifile = 0; | 
|  |  | 
|  | fdr_out = *buf + offset; | 
|  |  | 
|  | for (file_link = file_desc.first; | 
|  | file_link != (vlinks_t *) NULL; | 
|  | file_link = file_link->next) | 
|  | { | 
|  | int fil_cnt; | 
|  | efdr_t *fil_ptr; | 
|  | efdr_t *fil_end; | 
|  |  | 
|  | if (file_link->next == (vlinks_t *) NULL) | 
|  | fil_cnt = file_desc.objects_last_page; | 
|  | else | 
|  | fil_cnt = file_desc.objects_per_page; | 
|  | fil_ptr = file_link->datum->file; | 
|  | fil_end = fil_ptr + fil_cnt; | 
|  | for (; fil_ptr < fil_end; fil_ptr++) | 
|  | { | 
|  | if ((bfd_size_type)(*bufend - fdr_out) < external_fdr_size) | 
|  | fdr_out = ecoff_add_bytes (buf, bufend, fdr_out, | 
|  | external_fdr_size); | 
|  | (*swap_fdr_out) (stdoutput, &fil_ptr->fdr, fdr_out); | 
|  | fdr_out += external_fdr_size; | 
|  | ++ifile; | 
|  | } | 
|  | } | 
|  |  | 
|  | return offset + ifile * external_fdr_size; | 
|  | } | 
|  |  | 
|  | /* Set up the external symbols.  These are supposed to be handled by | 
|  | the backend.  This routine just gets the right information and | 
|  | calls a backend function to deal with it.  */ | 
|  |  | 
|  | static void | 
|  | ecoff_setup_ext (void) | 
|  | { | 
|  | symbolS *sym; | 
|  |  | 
|  | for (sym = symbol_rootP; sym != (symbolS *) NULL; sym = symbol_next (sym)) | 
|  | { | 
|  | if (symbol_get_obj (sym)->ecoff_symbol == NULL) | 
|  | continue; | 
|  |  | 
|  | /* If this is a local symbol, then force the fields to zero.  */ | 
|  | if (! S_IS_EXTERNAL (sym) | 
|  | && ! S_IS_WEAK (sym) | 
|  | && S_IS_DEFINED (sym)) | 
|  | { | 
|  | struct localsym *lsym; | 
|  |  | 
|  | lsym = symbol_get_obj (sym)->ecoff_symbol; | 
|  | lsym->ecoff_sym.asym.value = 0; | 
|  | lsym->ecoff_sym.asym.st = (int) st_Nil; | 
|  | lsym->ecoff_sym.asym.sc = (int) sc_Nil; | 
|  | lsym->ecoff_sym.asym.index = indexNil; | 
|  | } | 
|  |  | 
|  | obj_ecoff_set_ext (sym, &symbol_get_obj (sym)->ecoff_symbol->ecoff_sym); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Build the ECOFF debugging information.  */ | 
|  |  | 
|  | unsigned long | 
|  | ecoff_build_debug (HDRR *hdr, | 
|  | char **bufp, | 
|  | const struct ecoff_debug_swap *backend) | 
|  | { | 
|  | const bfd_size_type external_pdr_size = backend->external_pdr_size; | 
|  | tag_t *ptag; | 
|  | tag_t *ptag_next; | 
|  | efdr_t *fil_ptr; | 
|  | int end_warning; | 
|  | efdr_t *hold_file_ptr; | 
|  | proc_t *hold_proc_ptr; | 
|  | symbolS *sym; | 
|  | char *buf; | 
|  | char *bufend; | 
|  | unsigned long offset; | 
|  |  | 
|  | /* Make sure we have a file.  */ | 
|  | if (first_file == (efdr_t *) NULL) | 
|  | add_file ((const char *) NULL, 0, 1); | 
|  |  | 
|  | /* Handle any top level tags.  */ | 
|  | for (ptag = top_tag_head->first_tag; | 
|  | ptag != (tag_t *) NULL; | 
|  | ptag = ptag_next) | 
|  | { | 
|  | if (ptag->forward_ref != (forward_t *) NULL) | 
|  | add_unknown_tag (ptag); | 
|  |  | 
|  | ptag_next = ptag->same_block; | 
|  | ptag->hash_ptr->tag_ptr = ptag->same_name; | 
|  | free_tag (ptag); | 
|  | } | 
|  |  | 
|  | free_thead (top_tag_head); | 
|  |  | 
|  | /* Look through the symbols.  Add debugging information for each | 
|  | symbol that has not already received it.  */ | 
|  | hold_file_ptr = cur_file_ptr; | 
|  | hold_proc_ptr = cur_proc_ptr; | 
|  | cur_proc_ptr = (proc_t *) NULL; | 
|  | for (sym = symbol_rootP; sym != (symbolS *) NULL; sym = symbol_next (sym)) | 
|  | { | 
|  | if (symbol_get_obj (sym)->ecoff_symbol != NULL | 
|  | || symbol_get_obj (sym)->ecoff_file == (efdr_t *) NULL | 
|  | || (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0) | 
|  | continue; | 
|  |  | 
|  | cur_file_ptr = symbol_get_obj (sym)->ecoff_file; | 
|  | add_ecoff_symbol ((const char *) NULL, st_Nil, sc_Nil, sym, | 
|  | (bfd_vma) 0, S_GET_VALUE (sym), indexNil); | 
|  | } | 
|  | cur_proc_ptr = hold_proc_ptr; | 
|  | cur_file_ptr = hold_file_ptr; | 
|  |  | 
|  | /* Output an ending symbol for all the files.  We have to do this | 
|  | here for the last file, so we may as well do it for all of the | 
|  | files.  */ | 
|  | end_warning = 0; | 
|  | for (fil_ptr = first_file; | 
|  | fil_ptr != (efdr_t *) NULL; | 
|  | fil_ptr = fil_ptr->next_file) | 
|  | { | 
|  | cur_file_ptr = fil_ptr; | 
|  | while (cur_file_ptr->cur_scope != (scope_t *) NULL | 
|  | && cur_file_ptr->cur_scope->prev != (scope_t *) NULL) | 
|  | { | 
|  | cur_file_ptr->cur_scope = cur_file_ptr->cur_scope->prev; | 
|  | if (! end_warning && ! cur_file_ptr->fake) | 
|  | { | 
|  | as_warn (_("missing .end or .bend at end of file")); | 
|  | end_warning = 1; | 
|  | } | 
|  | } | 
|  | if (cur_file_ptr->cur_scope != (scope_t *) NULL) | 
|  | (void) add_ecoff_symbol ((const char *) NULL, | 
|  | st_End, sc_Text, | 
|  | (symbolS *) NULL, | 
|  | (bfd_vma) 0, | 
|  | (symint_t) 0, | 
|  | (symint_t) 0); | 
|  | } | 
|  |  | 
|  | /* Build the symbolic information.  */ | 
|  | offset = 0; | 
|  | buf = XNEWVEC (char, PAGE_SIZE); | 
|  | bufend = buf + PAGE_SIZE; | 
|  |  | 
|  | /* Build the line number information.  */ | 
|  | hdr->cbLineOffset = offset; | 
|  | offset = ecoff_build_lineno (backend, &buf, &bufend, offset, | 
|  | &hdr->ilineMax); | 
|  | hdr->cbLine = offset - hdr->cbLineOffset; | 
|  |  | 
|  | /* We don't use dense numbers at all.  */ | 
|  | hdr->idnMax = 0; | 
|  | hdr->cbDnOffset = 0; | 
|  |  | 
|  | /* We can't build the PDR table until we have built the symbols, | 
|  | because a PDR contains a symbol index.  However, we set aside | 
|  | space at this point.  */ | 
|  | hdr->ipdMax = proc_cnt; | 
|  | hdr->cbPdOffset = offset; | 
|  | if ((bfd_size_type)(bufend - (buf + offset)) < proc_cnt * external_pdr_size) | 
|  | (void) ecoff_add_bytes (&buf, &bufend, buf + offset, | 
|  | proc_cnt * external_pdr_size); | 
|  | offset += proc_cnt * external_pdr_size; | 
|  |  | 
|  | /* Build the local symbols.  */ | 
|  | hdr->cbSymOffset = offset; | 
|  | offset = ecoff_build_symbols (backend, &buf, &bufend, offset); | 
|  | hdr->isymMax = (offset - hdr->cbSymOffset) / backend->external_sym_size; | 
|  |  | 
|  | /* Building the symbols initializes the symbol index in the PDR's. | 
|  | Now we can swap out the PDR's.  */ | 
|  | (void) ecoff_build_procs (backend, &buf, &bufend, hdr->cbPdOffset); | 
|  |  | 
|  | /* We don't use optimization symbols.  */ | 
|  | hdr->ioptMax = 0; | 
|  | hdr->cbOptOffset = 0; | 
|  |  | 
|  | /* Swap out the auxiliary type information.  */ | 
|  | hdr->cbAuxOffset = offset; | 
|  | offset = ecoff_build_aux (backend, &buf, &bufend, offset); | 
|  | hdr->iauxMax = (offset - hdr->cbAuxOffset) / sizeof (union aux_ext); | 
|  |  | 
|  | /* Copy out the local strings.  */ | 
|  | hdr->cbSsOffset = offset; | 
|  | offset = ecoff_build_ss (backend, &buf, &bufend, offset); | 
|  | hdr->issMax = offset - hdr->cbSsOffset; | 
|  |  | 
|  | /* We don't use relative file descriptors.  */ | 
|  | hdr->crfd = 0; | 
|  | hdr->cbRfdOffset = 0; | 
|  |  | 
|  | /* Swap out the file descriptors.  */ | 
|  | hdr->cbFdOffset = offset; | 
|  | offset = ecoff_build_fdr (backend, &buf, &bufend, offset); | 
|  | hdr->ifdMax = (offset - hdr->cbFdOffset) / backend->external_fdr_size; | 
|  |  | 
|  | /* Set up the external symbols, which are handled by the BFD back | 
|  | end.  */ | 
|  | hdr->issExtMax = 0; | 
|  | hdr->cbSsExtOffset = 0; | 
|  | hdr->iextMax = 0; | 
|  | hdr->cbExtOffset = 0; | 
|  | ecoff_setup_ext (); | 
|  |  | 
|  | know ((offset & (backend->debug_align - 1)) == 0); | 
|  |  | 
|  | /* FIXME: This value should be determined from the .verstamp directive, | 
|  | with reasonable defaults in config files.  */ | 
|  | #ifdef TC_ALPHA | 
|  | hdr->vstamp = 0x030b; | 
|  | #else | 
|  | hdr->vstamp = 0x020b; | 
|  | #endif | 
|  |  | 
|  | *bufp = buf; | 
|  | return offset; | 
|  | } | 
|  |  | 
|  | /* Allocate a cluster of pages.  */ | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  |  | 
|  | static page_type * | 
|  | allocate_cluster (unsigned long npages) | 
|  | { | 
|  | page_type *value = (page_type *) xmalloc (npages * PAGE_USIZE); | 
|  |  | 
|  | #ifdef ECOFF_DEBUG | 
|  | if (debug > 3) | 
|  | fprintf (stderr, "\talloc\tnpages = %d, value = 0x%.8x\n", npages, value); | 
|  | #endif | 
|  |  | 
|  | memset (value, 0, npages * PAGE_USIZE); | 
|  |  | 
|  | return value; | 
|  | } | 
|  |  | 
|  | static page_type *cluster_ptr = NULL; | 
|  | static unsigned long pages_left = 0; | 
|  |  | 
|  | #endif /* MALLOC_CHECK */ | 
|  |  | 
|  | /* Allocate one page (which is initialized to 0).  */ | 
|  |  | 
|  | static page_type * | 
|  | allocate_page (void) | 
|  | { | 
|  | #ifndef MALLOC_CHECK | 
|  |  | 
|  | if (pages_left == 0) | 
|  | { | 
|  | pages_left = MAX_CLUSTER_PAGES; | 
|  | cluster_ptr = allocate_cluster (pages_left); | 
|  | } | 
|  |  | 
|  | pages_left--; | 
|  | return cluster_ptr++; | 
|  |  | 
|  | #else /* MALLOC_CHECK */ | 
|  |  | 
|  | page_type *ptr; | 
|  |  | 
|  | ptr = xmalloc (PAGE_USIZE); | 
|  | memset (ptr, 0, PAGE_USIZE); | 
|  | return ptr; | 
|  |  | 
|  | #endif /* MALLOC_CHECK */ | 
|  | } | 
|  |  | 
|  | /* Allocate scoping information.  */ | 
|  |  | 
|  | static scope_t * | 
|  | allocate_scope (void) | 
|  | { | 
|  | scope_t *ptr; | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  |  | 
|  | ptr = alloc_counts[(int) alloc_type_scope].free_list.f_scope; | 
|  | if (ptr != (scope_t *) NULL) | 
|  | alloc_counts[(int) alloc_type_scope].free_list.f_scope = ptr->free; | 
|  | else | 
|  | { | 
|  | int unallocated	= alloc_counts[(int) alloc_type_scope].unallocated; | 
|  | page_type *cur_page	= alloc_counts[(int) alloc_type_scope].cur_page; | 
|  |  | 
|  | if (unallocated == 0) | 
|  | { | 
|  | unallocated = PAGE_SIZE / sizeof (scope_t); | 
|  | alloc_counts[(int) alloc_type_scope].cur_page = cur_page = allocate_page (); | 
|  | alloc_counts[(int) alloc_type_scope].total_pages++; | 
|  | } | 
|  |  | 
|  | ptr = &cur_page->scope[--unallocated]; | 
|  | alloc_counts[(int) alloc_type_scope].unallocated = unallocated; | 
|  | } | 
|  |  | 
|  | #else | 
|  |  | 
|  | ptr = XNEW (scope_t); | 
|  |  | 
|  | #endif | 
|  |  | 
|  | alloc_counts[(int) alloc_type_scope].total_alloc++; | 
|  | memset (ptr, 0, sizeof (*ptr)); | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | /* Free scoping information.  */ | 
|  |  | 
|  | static void | 
|  | free_scope (scope_t *ptr) | 
|  | { | 
|  | alloc_counts[(int) alloc_type_scope].total_free++; | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  | ptr->free = alloc_counts[(int) alloc_type_scope].free_list.f_scope; | 
|  | alloc_counts[(int) alloc_type_scope].free_list.f_scope = ptr; | 
|  | #else | 
|  | free ((void *) ptr); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* Allocate links for pages in a virtual array.  */ | 
|  |  | 
|  | static vlinks_t * | 
|  | allocate_vlinks (void) | 
|  | { | 
|  | vlinks_t *ptr; | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  |  | 
|  | int unallocated = alloc_counts[(int) alloc_type_vlinks].unallocated; | 
|  | page_type *cur_page = alloc_counts[(int) alloc_type_vlinks].cur_page; | 
|  |  | 
|  | if (unallocated == 0) | 
|  | { | 
|  | unallocated = PAGE_SIZE / sizeof (vlinks_t); | 
|  | alloc_counts[(int) alloc_type_vlinks].cur_page = cur_page = allocate_page (); | 
|  | alloc_counts[(int) alloc_type_vlinks].total_pages++; | 
|  | } | 
|  |  | 
|  | ptr = &cur_page->vlinks[--unallocated]; | 
|  | alloc_counts[(int) alloc_type_vlinks].unallocated = unallocated; | 
|  |  | 
|  | #else | 
|  |  | 
|  | ptr = XNEW (vlinks_t); | 
|  |  | 
|  | #endif | 
|  |  | 
|  | alloc_counts[(int) alloc_type_vlinks].total_alloc++; | 
|  | memset (ptr, 0, sizeof (*ptr)); | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | /* Allocate string hash buckets.  */ | 
|  |  | 
|  | static shash_t * | 
|  | allocate_shash (void) | 
|  | { | 
|  | shash_t *ptr; | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  |  | 
|  | int unallocated = alloc_counts[(int) alloc_type_shash].unallocated; | 
|  | page_type *cur_page = alloc_counts[(int) alloc_type_shash].cur_page; | 
|  |  | 
|  | if (unallocated == 0) | 
|  | { | 
|  | unallocated = PAGE_SIZE / sizeof (shash_t); | 
|  | alloc_counts[(int) alloc_type_shash].cur_page = cur_page = allocate_page (); | 
|  | alloc_counts[(int) alloc_type_shash].total_pages++; | 
|  | } | 
|  |  | 
|  | ptr = &cur_page->shash[--unallocated]; | 
|  | alloc_counts[(int) alloc_type_shash].unallocated = unallocated; | 
|  |  | 
|  | #else | 
|  |  | 
|  | ptr = XNEW (shash_t); | 
|  |  | 
|  | #endif | 
|  |  | 
|  | alloc_counts[(int) alloc_type_shash].total_alloc++; | 
|  | memset (ptr, 0, sizeof (*ptr)); | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | /* Allocate type hash buckets.  */ | 
|  |  | 
|  | static thash_t * | 
|  | allocate_thash (void) | 
|  | { | 
|  | thash_t *ptr; | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  |  | 
|  | int unallocated = alloc_counts[(int) alloc_type_thash].unallocated; | 
|  | page_type *cur_page = alloc_counts[(int) alloc_type_thash].cur_page; | 
|  |  | 
|  | if (unallocated == 0) | 
|  | { | 
|  | unallocated = PAGE_SIZE / sizeof (thash_t); | 
|  | alloc_counts[(int) alloc_type_thash].cur_page = cur_page = allocate_page (); | 
|  | alloc_counts[(int) alloc_type_thash].total_pages++; | 
|  | } | 
|  |  | 
|  | ptr = &cur_page->thash[--unallocated]; | 
|  | alloc_counts[(int) alloc_type_thash].unallocated = unallocated; | 
|  |  | 
|  | #else | 
|  |  | 
|  | ptr = XNEW (thash_t); | 
|  |  | 
|  | #endif | 
|  |  | 
|  | alloc_counts[(int) alloc_type_thash].total_alloc++; | 
|  | memset (ptr, 0, sizeof (*ptr)); | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | /* Allocate structure, union, or enum tag information.  */ | 
|  |  | 
|  | static tag_t * | 
|  | allocate_tag (void) | 
|  | { | 
|  | tag_t *ptr; | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  |  | 
|  | ptr = alloc_counts[(int) alloc_type_tag].free_list.f_tag; | 
|  | if (ptr != (tag_t *) NULL) | 
|  | alloc_counts[(int) alloc_type_tag].free_list.f_tag = ptr->free; | 
|  | else | 
|  | { | 
|  | int unallocated = alloc_counts[(int) alloc_type_tag].unallocated; | 
|  | page_type *cur_page = alloc_counts[(int) alloc_type_tag].cur_page; | 
|  |  | 
|  | if (unallocated == 0) | 
|  | { | 
|  | unallocated = PAGE_SIZE / sizeof (tag_t); | 
|  | alloc_counts[(int) alloc_type_tag].cur_page = cur_page = allocate_page (); | 
|  | alloc_counts[(int) alloc_type_tag].total_pages++; | 
|  | } | 
|  |  | 
|  | ptr = &cur_page->tag[--unallocated]; | 
|  | alloc_counts[(int) alloc_type_tag].unallocated = unallocated; | 
|  | } | 
|  |  | 
|  | #else | 
|  |  | 
|  | ptr = XNEW (tag_t); | 
|  |  | 
|  | #endif | 
|  |  | 
|  | alloc_counts[(int) alloc_type_tag].total_alloc++; | 
|  | memset (ptr, 0, sizeof (*ptr)); | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | /* Free scoping information.  */ | 
|  |  | 
|  | static void | 
|  | free_tag (tag_t *ptr) | 
|  | { | 
|  | alloc_counts[(int) alloc_type_tag].total_free++; | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  | ptr->free = alloc_counts[(int) alloc_type_tag].free_list.f_tag; | 
|  | alloc_counts[(int) alloc_type_tag].free_list.f_tag = ptr; | 
|  | #else | 
|  | free ((PTR_T) ptr); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* Allocate forward reference to a yet unknown tag.  */ | 
|  |  | 
|  | static forward_t * | 
|  | allocate_forward (void) | 
|  | { | 
|  | forward_t *ptr; | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  |  | 
|  | int unallocated = alloc_counts[(int) alloc_type_forward].unallocated; | 
|  | page_type *cur_page = alloc_counts[(int) alloc_type_forward].cur_page; | 
|  |  | 
|  | if (unallocated == 0) | 
|  | { | 
|  | unallocated = PAGE_SIZE / sizeof (forward_t); | 
|  | alloc_counts[(int) alloc_type_forward].cur_page = cur_page = allocate_page (); | 
|  | alloc_counts[(int) alloc_type_forward].total_pages++; | 
|  | } | 
|  |  | 
|  | ptr = &cur_page->forward[--unallocated]; | 
|  | alloc_counts[(int) alloc_type_forward].unallocated = unallocated; | 
|  |  | 
|  | #else | 
|  |  | 
|  | ptr = XNEW (forward_t); | 
|  |  | 
|  | #endif | 
|  |  | 
|  | alloc_counts[(int) alloc_type_forward].total_alloc++; | 
|  | memset (ptr, 0, sizeof (*ptr)); | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | /* Allocate head of type hash list.  */ | 
|  |  | 
|  | static thead_t * | 
|  | allocate_thead (void) | 
|  | { | 
|  | thead_t *ptr; | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  |  | 
|  | ptr = alloc_counts[(int) alloc_type_thead].free_list.f_thead; | 
|  | if (ptr != (thead_t *) NULL) | 
|  | alloc_counts[(int) alloc_type_thead].free_list.f_thead = ptr->free; | 
|  | else | 
|  | { | 
|  | int unallocated = alloc_counts[(int) alloc_type_thead].unallocated; | 
|  | page_type *cur_page = alloc_counts[(int) alloc_type_thead].cur_page; | 
|  |  | 
|  | if (unallocated == 0) | 
|  | { | 
|  | unallocated = PAGE_SIZE / sizeof (thead_t); | 
|  | alloc_counts[(int) alloc_type_thead].cur_page = cur_page = allocate_page (); | 
|  | alloc_counts[(int) alloc_type_thead].total_pages++; | 
|  | } | 
|  |  | 
|  | ptr = &cur_page->thead[--unallocated]; | 
|  | alloc_counts[(int) alloc_type_thead].unallocated = unallocated; | 
|  | } | 
|  |  | 
|  | #else | 
|  |  | 
|  | ptr = XNEW (thead_t); | 
|  |  | 
|  | #endif | 
|  |  | 
|  | alloc_counts[(int) alloc_type_thead].total_alloc++; | 
|  | memset (ptr, 0, sizeof (*ptr)); | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | /* Free scoping information.  */ | 
|  |  | 
|  | static void | 
|  | free_thead (thead_t *ptr) | 
|  | { | 
|  | alloc_counts[(int) alloc_type_thead].total_free++; | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  | ptr->free = (thead_t *) alloc_counts[(int) alloc_type_thead].free_list.f_thead; | 
|  | alloc_counts[(int) alloc_type_thead].free_list.f_thead = ptr; | 
|  | #else | 
|  | free ((PTR_T) ptr); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static lineno_list_t * | 
|  | allocate_lineno_list (void) | 
|  | { | 
|  | lineno_list_t *ptr; | 
|  |  | 
|  | #ifndef MALLOC_CHECK | 
|  |  | 
|  | int unallocated = alloc_counts[(int) alloc_type_lineno].unallocated; | 
|  | page_type *cur_page = alloc_counts[(int) alloc_type_lineno].cur_page; | 
|  |  | 
|  | if (unallocated == 0) | 
|  | { | 
|  | unallocated = PAGE_SIZE / sizeof (lineno_list_t); | 
|  | alloc_counts[(int) alloc_type_lineno].cur_page = cur_page = allocate_page (); | 
|  | alloc_counts[(int) alloc_type_lineno].total_pages++; | 
|  | } | 
|  |  | 
|  | ptr = &cur_page->lineno[--unallocated]; | 
|  | alloc_counts[(int) alloc_type_lineno].unallocated = unallocated; | 
|  |  | 
|  | #else | 
|  |  | 
|  | ptr = XNEW (lineno_list_t); | 
|  |  | 
|  | #endif | 
|  |  | 
|  | alloc_counts[(int) alloc_type_lineno].total_alloc++; | 
|  | memset (ptr, 0, sizeof (*ptr)); | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | void | 
|  | ecoff_set_gp_prolog_size (int sz) | 
|  | { | 
|  | if (cur_proc_ptr == 0) | 
|  | return; | 
|  |  | 
|  | cur_proc_ptr->pdr.gp_prologue = sz; | 
|  | if (cur_proc_ptr->pdr.gp_prologue != sz) | 
|  | { | 
|  | as_warn (_("GP prologue size exceeds field size, using 0 instead")); | 
|  | cur_proc_ptr->pdr.gp_prologue = 0; | 
|  | } | 
|  |  | 
|  | cur_proc_ptr->pdr.gp_used = 1; | 
|  | } | 
|  |  | 
|  | int | 
|  | ecoff_no_current_file (void) | 
|  | { | 
|  | return cur_file_ptr == (efdr_t *) NULL; | 
|  | } | 
|  |  | 
|  | void | 
|  | ecoff_generate_asm_lineno (void) | 
|  | { | 
|  | unsigned int lineno; | 
|  | const char *filename; | 
|  | lineno_list_t *list; | 
|  |  | 
|  | filename = as_where (&lineno); | 
|  |  | 
|  | if (current_stabs_filename == (char *) NULL | 
|  | || filename_cmp (current_stabs_filename, filename)) | 
|  | add_file (filename, 0, 1); | 
|  |  | 
|  | list = allocate_lineno_list (); | 
|  |  | 
|  | list->next = (lineno_list_t *) NULL; | 
|  | list->file = cur_file_ptr; | 
|  | list->proc = cur_proc_ptr; | 
|  | list->frag = frag_now; | 
|  | list->paddr = frag_now_fix (); | 
|  | list->lineno = lineno; | 
|  |  | 
|  | /* We don't want to merge files which have line numbers.  */ | 
|  | cur_file_ptr->fdr.fMerge = 0; | 
|  |  | 
|  | /* A .loc directive will sometimes appear before a .ent directive, | 
|  | which means that cur_proc_ptr will be NULL here.  Arrange to | 
|  | patch this up.  */ | 
|  | if (cur_proc_ptr == (proc_t *) NULL) | 
|  | { | 
|  | lineno_list_t **pl; | 
|  |  | 
|  | pl = &noproc_lineno; | 
|  | while (*pl != (lineno_list_t *) NULL) | 
|  | pl = &(*pl)->next; | 
|  | *pl = list; | 
|  | } | 
|  | else | 
|  | { | 
|  | last_lineno = list; | 
|  | *last_lineno_ptr = list; | 
|  | last_lineno_ptr = &list->next; | 
|  | } | 
|  | } | 
|  |  | 
|  | #else | 
|  |  | 
|  | void | 
|  | ecoff_generate_asm_lineno (void) | 
|  | { | 
|  | } | 
|  |  | 
|  | #endif /* ECOFF_DEBUGGING */ |