|  | /* srconv.c -- Sysroff conversion program | 
|  | Copyright (C) 1994-2024 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GNU Binutils. | 
|  |  | 
|  | This program 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 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program 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 this program; if not, write to the Free Software | 
|  | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA | 
|  | 02110-1301, USA.  */ | 
|  |  | 
|  | /* Written by Steve Chamberlain (sac@cygnus.com) | 
|  |  | 
|  | This program can be used to convert a coff object file | 
|  | into a Hitachi OM/LM (Sysroff) format. | 
|  |  | 
|  | All debugging information is preserved */ | 
|  |  | 
|  | #include "sysdep.h" | 
|  | #include "bfd.h" | 
|  | #include "bucomm.h" | 
|  | #include "sysroff.h" | 
|  | #include "coffgrok.h" | 
|  | #include "libiberty.h" | 
|  | #include "filenames.h" | 
|  | #include "getopt.h" | 
|  |  | 
|  | #include "coff/internal.h" | 
|  | #include "../bfd/libcoff.h" | 
|  |  | 
|  | /*#define FOOP1 1 */ | 
|  |  | 
|  | static int addrsize; | 
|  | static char *toolname; | 
|  | static char **rnames; | 
|  |  | 
|  | static void walk_tree_symbol | 
|  | (struct coff_sfile *, struct coff_section *, struct coff_symbol *, int); | 
|  | static void walk_tree_scope | 
|  | (struct coff_section *, struct coff_sfile *, struct coff_scope *, int, int); | 
|  | static int find_base (struct coff_sfile *, struct coff_section *); | 
|  | static void wr_globals (struct coff_ofile *, struct coff_sfile *, int); | 
|  |  | 
|  | static FILE *file; | 
|  | static bfd *abfd; | 
|  | static int debug = 0; | 
|  | static int quick = 0; | 
|  | static int noprescan = 0; | 
|  | static struct coff_ofile *tree; | 
|  | /* Obsolete ?? | 
|  | static int absolute_p; | 
|  | */ | 
|  |  | 
|  | static int segmented_p; | 
|  | static int code; | 
|  |  | 
|  | static int ids1[20000]; | 
|  | static int ids2[20000]; | 
|  |  | 
|  | static int base1 = 0x18; | 
|  | static int base2 = 0x2018; | 
|  |  | 
|  | static int | 
|  | get_member_id (int x) | 
|  | { | 
|  | if (ids2[x]) | 
|  | return ids2[x]; | 
|  |  | 
|  | ids2[x] = base2++; | 
|  | return ids2[x]; | 
|  | } | 
|  |  | 
|  | static int | 
|  | get_ordinary_id (int x) | 
|  | { | 
|  | if (ids1[x]) | 
|  | return ids1[x]; | 
|  |  | 
|  | ids1[x] = base1++; | 
|  | return ids1[x]; | 
|  | } | 
|  | static char * | 
|  | section_translate (char *n) | 
|  | { | 
|  | if (strcmp (n, ".text") == 0) | 
|  | return "P"; | 
|  | if (strcmp (n, ".data") == 0) | 
|  | return "D"; | 
|  | if (strcmp (n, ".bss") == 0) | 
|  | return "B"; | 
|  | return n; | 
|  | } | 
|  |  | 
|  | #define DATE "940201073000";	/* Just a time on my birthday */ | 
|  |  | 
|  | static char * | 
|  | strip_suffix (const char *name) | 
|  | { | 
|  | int i; | 
|  | char *res; | 
|  |  | 
|  | for (i = 0; name[i] != 0 && name[i] != '.'; i++) | 
|  | ; | 
|  | res = (char *) xmalloc (i + 1); | 
|  | memcpy (res, name, i); | 
|  | res[i] = 0; | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /* IT LEN stuff CS */ | 
|  | static void | 
|  | checksum (FILE *ffile, unsigned char *ptr, int size, int ccode) | 
|  | { | 
|  | int j; | 
|  | int last; | 
|  | int sum = 0; | 
|  | int bytes = size / 8; | 
|  |  | 
|  | last = !(ccode & 0xff00); | 
|  | if (size & 0x7) | 
|  | fatal (_("Checksum failure")); | 
|  |  | 
|  | ptr[0] = ccode | (last ? 0x80 : 0); | 
|  | ptr[1] = bytes + 1; | 
|  |  | 
|  | for (j = 0; j < bytes; j++) | 
|  | sum += ptr[j]; | 
|  |  | 
|  | /* Glue on a checksum too.  */ | 
|  | ptr[bytes] = ~sum; | 
|  | if (fwrite (ptr, bytes + 1, 1, ffile) != 1) | 
|  | /* FIXME: Return error status.  */ | 
|  | fatal (_("Failed to write checksum")); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | writeINT (int n, unsigned char *ptr, int *idx, int size, FILE *ffile) | 
|  | { | 
|  | int byte = *idx / 8; | 
|  |  | 
|  | if (size == -2) | 
|  | size = addrsize; | 
|  | else if (size == -1) | 
|  | size = 0; | 
|  |  | 
|  | if (byte > 240) | 
|  | { | 
|  | /* Lets write out that record and do another one.  */ | 
|  | checksum (ffile, ptr, *idx, code | 0x1000); | 
|  | *idx = 16; | 
|  | byte = *idx / 8; | 
|  | } | 
|  |  | 
|  | switch (size) | 
|  | { | 
|  | case 0: | 
|  | break; | 
|  | case 1: | 
|  | ptr[byte] = n; | 
|  | break; | 
|  | case 2: | 
|  | ptr[byte + 0] = n >> 8; | 
|  | ptr[byte + 1] = n; | 
|  | break; | 
|  | case 4: | 
|  | ptr[byte + 0] = n >> 24; | 
|  | ptr[byte + 1] = n >> 16; | 
|  | ptr[byte + 2] = n >> 8; | 
|  | ptr[byte + 3] = n >> 0; | 
|  | break; | 
|  | default: | 
|  | fatal (_("Unsupported integer write size: %d"), size); | 
|  | } | 
|  | *idx += size * 8; | 
|  | } | 
|  |  | 
|  | static void | 
|  | writeBITS (int val, unsigned char *ptr, int *idx, int size) | 
|  | { | 
|  | int byte = *idx / 8; | 
|  | int bit = *idx % 8; | 
|  | int old; | 
|  |  | 
|  | *idx += size; | 
|  |  | 
|  | old = ptr[byte]; | 
|  | /* Turn off all about to change bits.  */ | 
|  | old &= ~((~0 >> (8 - bit - size)) & ((1 << size) - 1)); | 
|  | /* Turn on the bits we want.  */ | 
|  | old |= (val & ((1 << size) - 1)) << (8 - bit - size); | 
|  | ptr[byte] = old; | 
|  | } | 
|  |  | 
|  | static void | 
|  | writeBARRAY (barray data, unsigned char *ptr, int *idx, | 
|  | int size ATTRIBUTE_UNUSED, FILE *ffile) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | writeINT (data.len, ptr, idx, 1, ffile); | 
|  | for (i = 0; i < data.len; i++) | 
|  | writeINT (data.data[i], ptr, idx, 1, ffile); | 
|  | } | 
|  |  | 
|  | static void | 
|  | writeCHARS (char *string, unsigned char *ptr, int *idx, int size, FILE *ffile) | 
|  | { | 
|  | int i = *idx / 8; | 
|  |  | 
|  | if (i > 240) | 
|  | { | 
|  | /* Lets write out that record and do another one.  */ | 
|  | checksum (ffile, ptr, *idx, code | 0x1000); | 
|  | *idx = 16; | 
|  | i = *idx / 8; | 
|  | } | 
|  |  | 
|  | if (size == 0) | 
|  | { | 
|  | /* Variable length string.  */ | 
|  | size = strlen (string); | 
|  | ptr[i++] = size; | 
|  | } | 
|  |  | 
|  | /* BUG WAITING TO HAPPEN.  */ | 
|  | memcpy (ptr + i, string, size); | 
|  | i += size; | 
|  | *idx = i * 8; | 
|  | } | 
|  |  | 
|  | #define SYSROFF_SWAP_OUT | 
|  | #include "sysroff.c" | 
|  |  | 
|  | static char *rname_sh[] = | 
|  | { | 
|  | "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15" | 
|  | }; | 
|  |  | 
|  | static char *rname_h8300[] = | 
|  | { | 
|  | "ER0", "ER1", "ER2", "ER3", "ER4", "ER5", "ER6", "ER7", "PC", "CCR" | 
|  | }; | 
|  |  | 
|  | static void | 
|  | wr_tr (void) | 
|  | { | 
|  | /* The TR block is not normal - it doesn't have any contents.  */ | 
|  |  | 
|  | static char b[] = | 
|  | { | 
|  | 0xff,			/* IT */ | 
|  | 0x03,			/* RL */ | 
|  | 0xfd,			/* CS */ | 
|  | }; | 
|  |  | 
|  | if (fwrite (b, sizeof (b), 1, file) != 1) | 
|  | /* FIXME: Return error status.  */ | 
|  | fatal (_("Failed to write TR block")); | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_un (struct coff_ofile *ptr, struct coff_sfile *sfile, int first, | 
|  | int nsecs ATTRIBUTE_UNUSED) | 
|  | { | 
|  | struct IT_un un; | 
|  | struct coff_symbol *s; | 
|  |  | 
|  | un.spare1 = 0; | 
|  |  | 
|  | if (bfd_get_file_flags (abfd) & EXEC_P) | 
|  | un.format = FORMAT_LM; | 
|  | else | 
|  | un.format = FORMAT_OM; | 
|  | un.spare1 = 0; | 
|  |  | 
|  | /* Don't count the abs section.  */ | 
|  | un.nsections = ptr->nsections - 1; | 
|  |  | 
|  | un.nextdefs = 0; | 
|  | un.nextrefs = 0; | 
|  | /* Count all the undefined and defined variables with global scope.  */ | 
|  |  | 
|  | if (first) | 
|  | { | 
|  | for (s = ptr->symbol_list_head; s; s = s->next_in_ofile_list) | 
|  | { | 
|  | if (s->visible->type == coff_vis_ext_def | 
|  | || s->visible->type == coff_vis_common) | 
|  | un.nextdefs++; | 
|  |  | 
|  | if (s->visible->type == coff_vis_ext_ref) | 
|  | un.nextrefs++; | 
|  | } | 
|  | } | 
|  | un.tool = toolname; | 
|  | un.tcd = DATE; | 
|  | un.linker = "L_GX00"; | 
|  | un.lcd = DATE; | 
|  | un.name = sfile->name; | 
|  | sysroff_swap_un_out (file, &un); | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_hd (struct coff_ofile *p) | 
|  | { | 
|  | struct IT_hd hd; | 
|  |  | 
|  | hd.spare1 = 0; | 
|  | hd.spare2 = 0; | 
|  | if (bfd_get_file_flags (abfd) & EXEC_P) | 
|  | hd.mt = MTYPE_ABS_LM; | 
|  | else | 
|  | hd.mt = MTYPE_OMS_OR_LMS; | 
|  |  | 
|  | hd.cd = DATE; | 
|  |  | 
|  | hd.nu = p->nsources;		/* Always one unit */ | 
|  | hd.code = 0;			/* Always ASCII */ | 
|  | hd.ver = "0200";		/* Version 2.00 */ | 
|  |  | 
|  | switch (bfd_get_arch (abfd)) | 
|  | { | 
|  | case bfd_arch_h8300: | 
|  | hd.au = 8; | 
|  | hd.si = 0; | 
|  | hd.spcsz = 32; | 
|  | hd.segsz = 0; | 
|  | hd.segsh = 0; | 
|  | switch (bfd_get_mach (abfd)) | 
|  | { | 
|  | case bfd_mach_h8300: | 
|  | hd.cpu = "H8300"; | 
|  | hd.afl = 2; | 
|  | addrsize = 2; | 
|  | toolname = "C_H8/300"; | 
|  | break; | 
|  | case bfd_mach_h8300h: | 
|  | hd.cpu = "H8300H"; | 
|  | hd.afl = 4; | 
|  | addrsize = 4; | 
|  | toolname = "C_H8/300H"; | 
|  | break; | 
|  | case bfd_mach_h8300s: | 
|  | hd.cpu = "H8300S"; | 
|  | hd.afl = 4; | 
|  | addrsize = 4; | 
|  | toolname = "C_H8/300S"; | 
|  | break; | 
|  | default: | 
|  | fatal (_("Unrecognized H8300 sub-architecture: %ld"), | 
|  | bfd_get_mach (abfd)); | 
|  | } | 
|  | rnames = rname_h8300; | 
|  | break; | 
|  | case bfd_arch_sh: | 
|  | hd.au = 8; | 
|  | hd.si = 0; | 
|  | hd.afl = 4; | 
|  | hd.spcsz = 32; | 
|  | hd.segsz = 0; | 
|  | hd.segsh = 0; | 
|  | hd.cpu = "SH"; | 
|  | addrsize = 4; | 
|  | toolname = "C_SH"; | 
|  | rnames = rname_sh; | 
|  | break; | 
|  | default: | 
|  | fatal (_("Unsupported architecture: %d"), bfd_get_arch (abfd)); | 
|  | } | 
|  |  | 
|  | if (! (bfd_get_file_flags(abfd) & EXEC_P)) | 
|  | { | 
|  | hd.ep = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | hd.ep = 1; | 
|  | hd.uan = 0; | 
|  | hd.sa = 0; | 
|  | hd.sad = 0; | 
|  | hd.address = bfd_get_start_address (abfd); | 
|  | } | 
|  |  | 
|  | hd.os = ""; | 
|  | hd.sys = ""; | 
|  | hd.mn = strip_suffix (bfd_get_filename (abfd)); | 
|  |  | 
|  | sysroff_swap_hd_out (file, &hd); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | wr_sh (struct coff_ofile *p ATTRIBUTE_UNUSED, struct coff_section *sec) | 
|  | { | 
|  | struct IT_sh sh; | 
|  | sh.unit = 0; | 
|  | sh.section = sec->number; | 
|  | #ifdef FOOP1 | 
|  | sh.section = 0; | 
|  | #endif | 
|  | sysroff_swap_sh_out (file, &sh); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | wr_ob (struct coff_ofile *p ATTRIBUTE_UNUSED, struct coff_section *section) | 
|  | { | 
|  | bfd_size_type i; | 
|  | int first = 1; | 
|  | unsigned char stuff[200]; | 
|  |  | 
|  | i = 0; | 
|  | while (i < bfd_section_size (section->bfd_section)) | 
|  | { | 
|  | struct IT_ob ob; | 
|  | int todo = 200;		/* Copy in 200 byte lumps.  */ | 
|  |  | 
|  | ob.spare = 0; | 
|  | if (i + todo > bfd_section_size (section->bfd_section)) | 
|  | todo = bfd_section_size (section->bfd_section) - i; | 
|  |  | 
|  | if (first) | 
|  | { | 
|  | ob.saf = 1; | 
|  | if (bfd_get_file_flags (abfd) & EXEC_P) | 
|  | ob.address = section->address; | 
|  | else | 
|  | ob.address = 0; | 
|  |  | 
|  | first = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | ob.saf = 0; | 
|  | } | 
|  |  | 
|  | ob.cpf = 0;		/* Never compress.  */ | 
|  | ob.data.len = todo; | 
|  | bfd_get_section_contents (abfd, section->bfd_section, stuff, i, todo); | 
|  | ob.data.data = stuff; | 
|  | sysroff_swap_ob_out (file, &ob /*, i + todo < section->size */ ); | 
|  | i += todo; | 
|  | } | 
|  |  | 
|  | /* Now fill the rest with blanks.  */ | 
|  | while (i < (bfd_size_type) section->size) | 
|  | { | 
|  | struct IT_ob ob; | 
|  | int todo = 200;		/* Copy in 200 byte lumps.  */ | 
|  |  | 
|  | ob.spare = 0; | 
|  | if (i + todo > (bfd_size_type) section->size) | 
|  | todo = section->size - i; | 
|  | ob.saf = 0; | 
|  |  | 
|  | ob.cpf = 0;		/* Never compress.  */ | 
|  | ob.data.len = todo; | 
|  | memset (stuff, 0, todo); | 
|  | ob.data.data = stuff; | 
|  | sysroff_swap_ob_out (file, &ob); | 
|  | i += todo; | 
|  | } | 
|  | /* Now fill the rest with blanks.  */ | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_rl (struct coff_ofile *ptr ATTRIBUTE_UNUSED, struct coff_section *sec) | 
|  | { | 
|  | int nr = sec->nrelocs; | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < nr; i++) | 
|  | { | 
|  | struct coff_reloc *r = sec->relocs + i; | 
|  | struct coff_symbol *ref; | 
|  | struct IT_rl rl; | 
|  |  | 
|  | rl.apol = 0; | 
|  | rl.boundary = 0; | 
|  | rl.segment = 1; | 
|  | rl.sign = 0; | 
|  | rl.check = 0; | 
|  | rl.addr = r->offset; | 
|  | rl.bitloc = 0; | 
|  | rl.flen = 32;		/* SH Specific.  */ | 
|  |  | 
|  | /* What sort of reloc ? Look in the section to find out.  */ | 
|  | ref = r->symbol; | 
|  | if (ref->visible->type == coff_vis_ext_ref) | 
|  | { | 
|  | rl.bcount = 4;	/* Always 4 for us.  */ | 
|  | rl.op = OP_EXT_REF; | 
|  | rl.symn = ref->er_number; | 
|  | } | 
|  | else if (ref->visible->type == coff_vis_common) | 
|  | { | 
|  | rl.bcount = 11;	/* Always 11 for us.  */ | 
|  | rl.op = OP_SEC_REF; | 
|  | rl.secn = ref->where->section->number; | 
|  | rl.copcode_is_3 = 3; | 
|  | rl.alength_is_4 = 4; | 
|  | rl.addend = ref->where->offset - ref->where->section->address; | 
|  | rl.aopcode_is_0x20 = 0x20; | 
|  | } | 
|  | else | 
|  | { | 
|  | rl.bcount = 11;	/* Always 11 for us.  */ | 
|  | rl.op = OP_SEC_REF; | 
|  | rl.secn = ref->where->section->number; | 
|  | rl.copcode_is_3 = 3; | 
|  | rl.alength_is_4 = 4; | 
|  | rl.addend = -ref->where->section->address; | 
|  | rl.aopcode_is_0x20 = 0x20; | 
|  | } | 
|  |  | 
|  | rl.end = 0xff; | 
|  |  | 
|  | if (   rl.op == OP_SEC_REF | 
|  | || rl.op == OP_EXT_REF) | 
|  | sysroff_swap_rl_out (file, &rl); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_object_body (struct coff_ofile *p) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 1; i < p->nsections; i++) | 
|  | { | 
|  | wr_sh (p, p->sections + i); | 
|  | wr_ob (p, p->sections + i); | 
|  | wr_rl (p, p->sections + i); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_dps_start (struct coff_sfile *sfile, | 
|  | struct coff_section *section ATTRIBUTE_UNUSED, | 
|  | struct coff_scope *scope, int type, int nest) | 
|  | { | 
|  | struct IT_dps dps; | 
|  |  | 
|  | dps.end = 0; | 
|  | dps.opt = 0; | 
|  | dps.type = type; | 
|  |  | 
|  | if (scope->sec) | 
|  | { | 
|  | dps.san = scope->sec->number; | 
|  | dps.address = scope->offset - find_base (sfile, scope->sec); | 
|  | dps.block_size = scope->size; | 
|  |  | 
|  | if (debug) | 
|  | { | 
|  | printf ("DPS %s %d %x\n", | 
|  | sfile->name, | 
|  | nest, | 
|  | dps.address); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | dps.san = 0; | 
|  | dps.address = 0; | 
|  | dps.block_size = 0; | 
|  | } | 
|  |  | 
|  | dps.nesting = nest; | 
|  | dps.neg = 0x1001; | 
|  | sysroff_swap_dps_out (file, &dps); | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_dps_end (struct coff_section *section ATTRIBUTE_UNUSED, | 
|  | struct coff_scope *scope ATTRIBUTE_UNUSED, int type) | 
|  | { | 
|  | struct IT_dps dps; | 
|  |  | 
|  | dps.end = 1; | 
|  | dps.type = type; | 
|  | sysroff_swap_dps_out (file, &dps); | 
|  | } | 
|  |  | 
|  | static int * | 
|  | nints (int x) | 
|  | { | 
|  | return (int *) (xcalloc (x, sizeof (int))); | 
|  | } | 
|  |  | 
|  | static void | 
|  | walk_tree_type_1 (struct coff_sfile *sfile, struct coff_symbol *symbol, | 
|  | struct coff_type *type, int nest) | 
|  | { | 
|  | switch (type->type) | 
|  | { | 
|  | case coff_secdef_type: | 
|  | case coff_basic_type: | 
|  | { | 
|  | struct IT_dbt dbt; | 
|  |  | 
|  | switch (type->u.basic) | 
|  | { | 
|  | case T_NULL: | 
|  | case T_VOID: | 
|  | dbt.btype = BTYPE_VOID; | 
|  | dbt.sign = BTYPE_UNSPEC; | 
|  | dbt.fptype = FPTYPE_NOTSPEC; | 
|  | break; | 
|  |  | 
|  | case T_CHAR: | 
|  | dbt.btype = BTYPE_CHAR; | 
|  | dbt.sign = BTYPE_UNSPEC; | 
|  | dbt.fptype = FPTYPE_NOTSPEC; | 
|  | break; | 
|  |  | 
|  | case T_SHORT: | 
|  | case T_INT: | 
|  | case T_LONG: | 
|  | dbt.btype = BTYPE_INT; | 
|  | dbt.sign = SIGN_SIGNED; | 
|  | dbt.fptype = FPTYPE_NOTSPEC; | 
|  | break; | 
|  |  | 
|  | case T_FLOAT: | 
|  | dbt.btype = BTYPE_FLOAT; | 
|  | dbt.fptype = FPTYPE_SINGLE; | 
|  | break; | 
|  |  | 
|  | case T_DOUBLE: | 
|  | dbt.btype = BTYPE_FLOAT; | 
|  | dbt.fptype = FPTYPE_DOUBLE; | 
|  | break; | 
|  |  | 
|  | case T_LNGDBL: | 
|  | dbt.btype = BTYPE_FLOAT; | 
|  | dbt.fptype = FPTYPE_EXTENDED; | 
|  | break; | 
|  |  | 
|  | case T_UCHAR: | 
|  | dbt.btype = BTYPE_CHAR; | 
|  | dbt.sign = SIGN_UNSIGNED; | 
|  | dbt.fptype = FPTYPE_NOTSPEC; | 
|  | break; | 
|  |  | 
|  | case T_USHORT: | 
|  | case T_UINT: | 
|  | case T_ULONG: | 
|  | dbt.btype = BTYPE_INT; | 
|  | dbt.sign = SIGN_UNSIGNED; | 
|  | dbt.fptype = FPTYPE_NOTSPEC; | 
|  | break; | 
|  | } | 
|  |  | 
|  | dbt.bitsize = type->size; | 
|  | dbt.neg = 0x1001; | 
|  | sysroff_swap_dbt_out (file, &dbt); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case coff_pointer_type: | 
|  | { | 
|  | struct IT_dpt dpt; | 
|  |  | 
|  | dpt.dunno = 0; | 
|  | walk_tree_type_1 (sfile, symbol, type->u.pointer.points_to, nest + 1); | 
|  | dpt.neg = 0x1001; | 
|  | sysroff_swap_dpt_out (file, &dpt); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case coff_function_type: | 
|  | { | 
|  | struct IT_dfp dfp; | 
|  | struct coff_symbol *param; | 
|  |  | 
|  | dfp.end = 0; | 
|  | dfp.spare = 0; | 
|  | dfp.nparams = type->u.function.parameters->nvars; | 
|  | dfp.neg = 0x1001; | 
|  |  | 
|  | walk_tree_type_1 (sfile, symbol, type->u.function.function_returns, nest + 1); | 
|  |  | 
|  | sysroff_swap_dfp_out (file, &dfp); | 
|  |  | 
|  | for (param = type->u.function.parameters->vars_head; | 
|  | param; | 
|  | param = param->next) | 
|  | walk_tree_symbol (sfile, 0, param, nest); | 
|  |  | 
|  | dfp.end = 1; | 
|  | sysroff_swap_dfp_out (file, &dfp); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case coff_structdef_type: | 
|  | { | 
|  | struct IT_dbt dbt; | 
|  | struct IT_dds dds; | 
|  | struct coff_symbol *member; | 
|  |  | 
|  | dds.spare = 0; | 
|  | dbt.btype = BTYPE_STRUCT; | 
|  | dbt.bitsize = type->size; | 
|  | dbt.sign = SIGN_UNSPEC; | 
|  | dbt.fptype = FPTYPE_NOTSPEC; | 
|  | dbt.sid = get_member_id (type->u.astructdef.idx); | 
|  | dbt.neg = 0x1001; | 
|  | sysroff_swap_dbt_out (file, &dbt); | 
|  | dds.end = 0; | 
|  | dds.neg = 0x1001; | 
|  | sysroff_swap_dds_out (file, &dds); | 
|  |  | 
|  | for (member = type->u.astructdef.elements->vars_head; | 
|  | member; | 
|  | member = member->next) | 
|  | walk_tree_symbol (sfile, 0, member, nest + 1); | 
|  |  | 
|  | dds.end = 1; | 
|  | sysroff_swap_dds_out (file, &dds); | 
|  |  | 
|  | } | 
|  | break; | 
|  |  | 
|  | case coff_structref_type: | 
|  | { | 
|  | struct IT_dbt dbt; | 
|  |  | 
|  | dbt.btype = BTYPE_TAG; | 
|  | dbt.bitsize = type->size; | 
|  | dbt.sign = SIGN_UNSPEC; | 
|  | dbt.fptype = FPTYPE_NOTSPEC; | 
|  |  | 
|  | if (type->u.astructref.ref) | 
|  | dbt.sid = get_member_id (type->u.astructref.ref->number); | 
|  | else | 
|  | dbt.sid = 0; | 
|  |  | 
|  | dbt.neg = 0x1001; | 
|  | sysroff_swap_dbt_out (file, &dbt); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case coff_array_type: | 
|  | { | 
|  | struct IT_dar dar; | 
|  | int j; | 
|  | int dims = 1;		/* Only output one dimension at a time.  */ | 
|  |  | 
|  | dar.dims = dims; | 
|  | dar.variable = nints (dims); | 
|  | dar.subtype = nints (dims); | 
|  | dar.spare = nints (dims); | 
|  | dar.max_variable = nints (dims); | 
|  | dar.maxspare = nints (dims); | 
|  | dar.max = nints (dims); | 
|  | dar.min_variable = nints (dims); | 
|  | dar.min = nints (dims); | 
|  | dar.minspare = nints (dims); | 
|  | dar.neg = 0x1001; | 
|  | dar.length = type->size / type->u.array.dim; | 
|  |  | 
|  | for (j = 0; j < dims; j++) | 
|  | { | 
|  | dar.variable[j] = VARIABLE_FIXED; | 
|  | dar.subtype[j] = SUB_INTEGER; | 
|  | dar.spare[j] = 0; | 
|  | dar.max_variable[j] = 0; | 
|  | dar.max[j] = type->u.array.dim; | 
|  | dar.min_variable[j] = 0; | 
|  | dar.min[j] = 1;	/* Why isn't this 0 ? */ | 
|  | } | 
|  | walk_tree_type_1 (sfile, symbol, type->u.array.array_of, nest + 1); | 
|  | sysroff_swap_dar_out (file, &dar); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case coff_enumdef_type: | 
|  | { | 
|  | struct IT_dbt dbt; | 
|  | struct IT_den den; | 
|  | struct coff_symbol *member; | 
|  |  | 
|  | dbt.btype = BTYPE_ENUM; | 
|  | dbt.bitsize = type->size; | 
|  | dbt.sign = SIGN_UNSPEC; | 
|  | dbt.fptype = FPTYPE_NOTSPEC; | 
|  | dbt.sid = get_member_id (type->u.aenumdef.idx); | 
|  | dbt.neg = 0x1001; | 
|  | sysroff_swap_dbt_out (file, &dbt); | 
|  |  | 
|  | den.end = 0; | 
|  | den.neg = 0x1001; | 
|  | den.spare = 0; | 
|  | sysroff_swap_den_out (file, &den); | 
|  |  | 
|  | for (member = type->u.aenumdef.elements->vars_head; | 
|  | member; | 
|  | member = member->next) | 
|  | walk_tree_symbol (sfile, 0, member, nest + 1); | 
|  |  | 
|  | den.end = 1; | 
|  | sysroff_swap_den_out (file, &den); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case coff_enumref_type: | 
|  | { | 
|  | struct IT_dbt dbt; | 
|  |  | 
|  | dbt.btype = BTYPE_TAG; | 
|  | dbt.bitsize = type->size; | 
|  | dbt.sign = SIGN_UNSPEC; | 
|  | dbt.fptype = FPTYPE_NOTSPEC; | 
|  | dbt.sid = get_member_id (type->u.aenumref.ref->number); | 
|  | dbt.neg = 0x1001; | 
|  | sysroff_swap_dbt_out (file, &dbt); | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | fatal (_("Unrecognised type: %d"), type->type); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Obsolete ? | 
|  | static void | 
|  | dty_start () | 
|  | { | 
|  | struct IT_dty dty; | 
|  | dty.end = 0; | 
|  | dty.neg = 0x1001; | 
|  | dty.spare = 0; | 
|  | sysroff_swap_dty_out (file, &dty); | 
|  | } | 
|  |  | 
|  | static void | 
|  | dty_stop () | 
|  | { | 
|  | struct IT_dty dty; | 
|  | dty.end = 0; | 
|  | dty.neg = 0x1001; | 
|  | dty.end = 1; | 
|  | sysroff_swap_dty_out (file, &dty); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | dump_tree_structure (sfile, symbol, type, nest) | 
|  | struct coff_sfile *sfile; | 
|  | struct coff_symbol *symbol; | 
|  | struct coff_type *type; | 
|  | int nest; | 
|  | { | 
|  | if (symbol->type->type == coff_function_type) | 
|  | { | 
|  |  | 
|  |  | 
|  | } | 
|  |  | 
|  | } | 
|  | */ | 
|  |  | 
|  | static void | 
|  | walk_tree_type (struct coff_sfile *sfile, struct coff_symbol *symbol, | 
|  | struct coff_type *type, int nest) | 
|  | { | 
|  | struct IT_dty dty; | 
|  |  | 
|  | dty.spare = 0; | 
|  | dty.end = 0; | 
|  | dty.neg = 0x1001; | 
|  |  | 
|  | if (symbol->type->type == coff_function_type) | 
|  | { | 
|  | sysroff_swap_dty_out (file, &dty); | 
|  | walk_tree_type_1 (sfile, symbol, type, nest); | 
|  | dty.end = 1; | 
|  | sysroff_swap_dty_out (file, &dty); | 
|  |  | 
|  | wr_dps_start (sfile, | 
|  | symbol->where->section, | 
|  | symbol->type->u.function.code, | 
|  | BLOCK_TYPE_FUNCTION, nest); | 
|  | wr_dps_start (sfile, symbol->where->section, | 
|  | symbol->type->u.function.code, | 
|  | BLOCK_TYPE_BLOCK, nest); | 
|  | walk_tree_scope (symbol->where->section, | 
|  | sfile, | 
|  | symbol->type->u.function.code, | 
|  | nest + 1, BLOCK_TYPE_BLOCK); | 
|  |  | 
|  | wr_dps_end (symbol->where->section, | 
|  | symbol->type->u.function.code, | 
|  | BLOCK_TYPE_BLOCK); | 
|  | wr_dps_end (symbol->where->section, | 
|  | symbol->type->u.function.code, BLOCK_TYPE_FUNCTION); | 
|  | } | 
|  | else | 
|  | { | 
|  | sysroff_swap_dty_out (file, &dty); | 
|  | walk_tree_type_1 (sfile, symbol, type, nest); | 
|  | dty.end = 1; | 
|  | sysroff_swap_dty_out (file, &dty); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | walk_tree_symbol (struct coff_sfile *sfile, struct coff_section *section ATTRIBUTE_UNUSED, struct coff_symbol *symbol, int nest) | 
|  | { | 
|  | struct IT_dsy dsy; | 
|  |  | 
|  | memset (&dsy, 0, sizeof(dsy)); | 
|  | dsy.nesting = nest; | 
|  |  | 
|  | switch (symbol->type->type) | 
|  | { | 
|  | case coff_function_type: | 
|  | dsy.type = STYPE_FUNC; | 
|  | dsy.assign = 1; | 
|  | break; | 
|  |  | 
|  | case coff_structref_type: | 
|  | case coff_pointer_type: | 
|  | case coff_array_type: | 
|  | case coff_basic_type: | 
|  | case coff_enumref_type: | 
|  | dsy.type = STYPE_VAR; | 
|  | dsy.assign = 1; | 
|  | break; | 
|  |  | 
|  | case coff_enumdef_type: | 
|  | dsy.type = STYPE_TAG; | 
|  | dsy.assign = 0; | 
|  | dsy.magic = 2; | 
|  | break; | 
|  |  | 
|  | case coff_structdef_type: | 
|  | dsy.type = STYPE_TAG; | 
|  | dsy.assign = 0; | 
|  | dsy.magic = symbol->type->u.astructdef.isstruct ? 0 : 1; | 
|  | break; | 
|  |  | 
|  | case coff_secdef_type: | 
|  | return; | 
|  |  | 
|  | default: | 
|  | fatal (_("Unrecognised coff symbol type: %d"), symbol->type->type); | 
|  | } | 
|  |  | 
|  | if (symbol->where->where == coff_where_member_of_struct) | 
|  | { | 
|  | dsy.assign = 0; | 
|  | dsy.type = STYPE_MEMBER; | 
|  | } | 
|  |  | 
|  | if (symbol->where->where == coff_where_member_of_enum) | 
|  | { | 
|  | dsy.type = STYPE_ENUM; | 
|  | dsy.assign = 0; | 
|  | dsy.evallen = 4; | 
|  | dsy.evalue = symbol->where->offset; | 
|  | } | 
|  |  | 
|  | if (symbol->type->type == coff_structdef_type | 
|  | || symbol->where->where == coff_where_entag | 
|  | || symbol->where->where == coff_where_strtag) | 
|  | { | 
|  | dsy.snumber = get_member_id (symbol->number); | 
|  | } | 
|  | else | 
|  | { | 
|  | dsy.snumber = get_ordinary_id (symbol->number); | 
|  | } | 
|  |  | 
|  | dsy.sname = symbol->name[0] == '_' ? symbol->name + 1 : symbol->name; | 
|  |  | 
|  | switch (symbol->visible->type) | 
|  | { | 
|  | case coff_vis_common: | 
|  | case coff_vis_ext_def: | 
|  | dsy.ainfo = AINFO_STATIC_EXT_DEF; | 
|  | break; | 
|  |  | 
|  | case coff_vis_ext_ref: | 
|  | dsy.ainfo = AINFO_STATIC_EXT_REF; | 
|  | break; | 
|  |  | 
|  | case coff_vis_int_def: | 
|  | dsy.ainfo = AINFO_STATIC_INT; | 
|  | break; | 
|  |  | 
|  | case coff_vis_auto: | 
|  | case coff_vis_autoparam: | 
|  | dsy.ainfo = AINFO_AUTO; | 
|  | break; | 
|  |  | 
|  | case coff_vis_register: | 
|  | case coff_vis_regparam: | 
|  | dsy.ainfo = AINFO_REG; | 
|  | break; | 
|  | break; | 
|  |  | 
|  | case coff_vis_tag: | 
|  | case coff_vis_member_of_struct: | 
|  | case coff_vis_member_of_enum: | 
|  | break; | 
|  |  | 
|  | default: | 
|  | fatal (_("Unrecognised coff symbol visibility: %d"), symbol->visible->type); | 
|  | } | 
|  |  | 
|  | dsy.dlength = symbol->type->size; | 
|  |  | 
|  | switch (symbol->where->where) | 
|  | { | 
|  | case coff_where_memory: | 
|  |  | 
|  | dsy.section = symbol->where->section->number; | 
|  | #ifdef FOOP | 
|  | dsy.section = 0; | 
|  | #endif | 
|  | break; | 
|  |  | 
|  | case coff_where_member_of_struct: | 
|  | case coff_where_member_of_enum: | 
|  | case coff_where_stack: | 
|  | case coff_where_register: | 
|  | case coff_where_unknown: | 
|  | case coff_where_strtag: | 
|  | case coff_where_entag: | 
|  | case coff_where_typedef: | 
|  | break; | 
|  |  | 
|  | default: | 
|  | fatal (_("Unrecognised coff symbol location: %d"), symbol->where->where); | 
|  | } | 
|  |  | 
|  | switch (symbol->where->where) | 
|  | { | 
|  | case coff_where_memory: | 
|  | dsy.address = symbol->where->offset - find_base (sfile, symbol->where->section); | 
|  | break; | 
|  |  | 
|  | case coff_where_stack: | 
|  | dsy.address = symbol->where->offset; | 
|  | break; | 
|  |  | 
|  | case coff_where_member_of_struct: | 
|  | if (symbol->where->bitsize) | 
|  | { | 
|  | int bits = (symbol->where->offset * 8 + symbol->where->bitoffset); | 
|  | dsy.bitunit = 1; | 
|  | dsy.field_len = symbol->where->bitsize; | 
|  | dsy.field_off = (bits / 32) * 4; | 
|  | dsy.field_bitoff = bits % 32; | 
|  | } | 
|  | else | 
|  | { | 
|  | dsy.bitunit = 0; | 
|  |  | 
|  | dsy.field_len = symbol->type->size; | 
|  | dsy.field_off = symbol->where->offset; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case coff_where_member_of_enum: | 
|  | /*      dsy.bitunit = 0; | 
|  | dsy.field_len  = symbol->type->size; | 
|  | dsy.field_off = symbol->where->offset; */ | 
|  | break; | 
|  |  | 
|  | case coff_where_register: | 
|  | case coff_where_unknown: | 
|  | case coff_where_strtag: | 
|  | case coff_where_entag: | 
|  | case coff_where_typedef: | 
|  | break; | 
|  |  | 
|  | default: | 
|  | fatal (_("Unrecognised coff symbol location: %d"), symbol->where->where); | 
|  | } | 
|  |  | 
|  | if (symbol->where->where == coff_where_register) | 
|  | dsy.reg = rnames[symbol->where->offset]; | 
|  |  | 
|  | switch (symbol->visible->type) | 
|  | { | 
|  | case coff_vis_common: | 
|  | /* We do this 'cause common C symbols are treated as extdefs.  */ | 
|  | case coff_vis_ext_def: | 
|  | case coff_vis_ext_ref: | 
|  | dsy.ename = symbol->name; | 
|  | break; | 
|  |  | 
|  | case coff_vis_regparam: | 
|  | case coff_vis_autoparam: | 
|  | dsy.type = STYPE_PARAMETER; | 
|  | break; | 
|  |  | 
|  | case coff_vis_int_def: | 
|  | case coff_vis_auto: | 
|  | case coff_vis_register: | 
|  | case coff_vis_tag: | 
|  | case coff_vis_member_of_struct: | 
|  | case coff_vis_member_of_enum: | 
|  | break; | 
|  |  | 
|  | default: | 
|  | fatal (_("Unrecognised coff symbol visibility: %d"), symbol->visible->type); | 
|  | } | 
|  |  | 
|  | dsy.sfn = 0; | 
|  | dsy.sln = 2; | 
|  | dsy.neg = 0x1001; | 
|  |  | 
|  | sysroff_swap_dsy_out (file, &dsy); | 
|  |  | 
|  | walk_tree_type (sfile, symbol, symbol->type, nest); | 
|  | } | 
|  |  | 
|  | static void | 
|  | walk_tree_scope (struct coff_section *section, struct coff_sfile *sfile, struct coff_scope *scope, int nest, int type) | 
|  | { | 
|  | struct coff_symbol *vars; | 
|  | struct coff_scope *child; | 
|  |  | 
|  | if (scope->vars_head | 
|  | || (scope->list_head && scope->list_head->vars_head)) | 
|  | { | 
|  | wr_dps_start (sfile, section, scope, type, nest); | 
|  |  | 
|  | if (nest == 0) | 
|  | wr_globals (tree, sfile, nest + 1); | 
|  |  | 
|  | for (vars = scope->vars_head; vars; vars = vars->next) | 
|  | walk_tree_symbol (sfile, section, vars, nest); | 
|  |  | 
|  | for (child = scope->list_head; child; child = child->next) | 
|  | walk_tree_scope (section, sfile, child, nest + 1, BLOCK_TYPE_BLOCK); | 
|  |  | 
|  | wr_dps_end (section, scope, type); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | walk_tree_sfile (struct coff_section *section, struct coff_sfile *sfile) | 
|  | { | 
|  | walk_tree_scope (section, sfile, sfile->scope, 0, BLOCK_TYPE_COMPUNIT); | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_program_structure (struct coff_ofile *p, struct coff_sfile *sfile) | 
|  | { | 
|  | if (p->nsections < 4) | 
|  | return; | 
|  | walk_tree_sfile (p->sections + 4, sfile); | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_du (struct coff_ofile *p, struct coff_sfile *sfile, int n) | 
|  | { | 
|  | struct IT_du du; | 
|  | int lim; | 
|  | int i; | 
|  | int j; | 
|  | unsigned int *lowest = (unsigned *) nints (p->nsections); | 
|  | unsigned int *highest = (unsigned *) nints (p->nsections); | 
|  |  | 
|  | du.format = bfd_get_file_flags (abfd) & EXEC_P ? 0 : 1; | 
|  | du.optimized = 0; | 
|  | du.stackfrmt = 0; | 
|  | du.spare = 0; | 
|  | du.unit = n; | 
|  | du.sections = p->nsections - 1; | 
|  | du.san = (int *) xcalloc (du.sections, sizeof (int)); | 
|  | du.address = nints (du.sections); | 
|  | du.length = nints (du.sections); | 
|  |  | 
|  | for (i = 0; i < du.sections; i++) | 
|  | { | 
|  | lowest[i] = ~0; | 
|  | highest[i] = 0; | 
|  | } | 
|  |  | 
|  | lim = du.sections; | 
|  | for (j = 0; j < lim; j++) | 
|  | { | 
|  | int src = j; | 
|  | int dst = j; | 
|  |  | 
|  | du.san[dst] = dst; | 
|  |  | 
|  | if (sfile->section[src].init) | 
|  | { | 
|  | du.length[dst] | 
|  | = sfile->section[src].high - sfile->section[src].low + 1; | 
|  | du.address[dst] | 
|  | = sfile->section[src].low; | 
|  | } | 
|  | else | 
|  | { | 
|  | du.length[dst] = 0; | 
|  | du.address[dst] = 0; | 
|  | } | 
|  |  | 
|  | if (debug) | 
|  | { | 
|  | if (sfile->section[src].parent) | 
|  | { | 
|  | printf (" section %6s 0x%08x..0x%08x\n", | 
|  | sfile->section[src].parent->name, | 
|  | du.address[dst], | 
|  | du.address[dst] + du.length[dst] - 1); | 
|  | } | 
|  | } | 
|  |  | 
|  | du.sections = dst + 1; | 
|  | } | 
|  |  | 
|  | du.tool = "c_gcc"; | 
|  | du.date = DATE; | 
|  |  | 
|  | sysroff_swap_du_out (file, &du); | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_dus (struct coff_ofile *p ATTRIBUTE_UNUSED, struct coff_sfile *sfile) | 
|  | { | 
|  | struct IT_dus dus; | 
|  |  | 
|  | dus.efn = 0x1001; | 
|  | dus.ns = 1;			/* p->nsources; sac 14 jul 94 */ | 
|  | dus.drb = nints (dus.ns); | 
|  | dus.fname = (char **) xcalloc (dus.ns, sizeof (char *)); | 
|  | dus.spare = nints (dus.ns); | 
|  | dus.ndir = 0; | 
|  | /* Find the filenames.  */ | 
|  | dus.drb[0] = 0; | 
|  | dus.fname[0] = sfile->name; | 
|  |  | 
|  | sysroff_swap_dus_out (file, &dus); | 
|  |  | 
|  | } | 
|  |  | 
|  | /* Find the offset of the .text section for this sfile in the | 
|  | .text section for the output file.  */ | 
|  |  | 
|  | static int | 
|  | find_base (struct coff_sfile *sfile, struct coff_section *section) | 
|  | { | 
|  | return sfile->section[section->number].low; | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_dln (struct coff_ofile *p ATTRIBUTE_UNUSED, struct coff_sfile *sfile, | 
|  | int n ATTRIBUTE_UNUSED) | 
|  | { | 
|  | /* Count up all the linenumbers */ | 
|  |  | 
|  | struct coff_symbol *sy; | 
|  | int lc = 0; | 
|  | struct IT_dln dln; | 
|  |  | 
|  | int idx; | 
|  |  | 
|  | for (sy = sfile->scope->vars_head; | 
|  | sy; | 
|  | sy = sy->next) | 
|  | { | 
|  | struct coff_type *t = sy->type; | 
|  | if (t->type == coff_function_type) | 
|  | { | 
|  | struct coff_line *l = t->u.function.lines; | 
|  | if (l) | 
|  | lc += l->nlines; | 
|  | } | 
|  | } | 
|  |  | 
|  | dln.sfn = nints (lc); | 
|  | dln.sln = nints (lc); | 
|  | dln.cc = nints (lc); | 
|  | dln.section = nints (lc); | 
|  |  | 
|  | dln.from_address = nints (lc); | 
|  | dln.to_address = nints (lc); | 
|  |  | 
|  |  | 
|  | dln.neg = 0x1001; | 
|  |  | 
|  | dln.nln = lc; | 
|  |  | 
|  | /* Run through once more and fill up the structure */ | 
|  | idx = 0; | 
|  | for (sy = sfile->scope->vars_head; | 
|  | sy; | 
|  | sy = sy->next) | 
|  | { | 
|  | if (sy->type->type == coff_function_type) | 
|  | { | 
|  | int i; | 
|  | struct coff_line *l = sy->type->u.function.lines; | 
|  | if (l) | 
|  | { | 
|  | int base = find_base (sfile, sy->where->section); | 
|  | for (i = 0; i < l->nlines; i++) | 
|  | { | 
|  | dln.section[idx] = sy->where->section->number; | 
|  | dln.sfn[idx] = 0; | 
|  | dln.sln[idx] = l->lines[i]; | 
|  | dln.from_address[idx] = | 
|  | l->addresses[i] + sy->where->section->address - base; | 
|  | dln.cc[idx] = 0; | 
|  | if (idx) | 
|  | dln.to_address[idx - 1] = dln.from_address[idx]; | 
|  | idx++; | 
|  |  | 
|  | } | 
|  | dln.to_address[idx - 1] = dln.from_address[idx - 1] + 2; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (lc) | 
|  | sysroff_swap_dln_out (file, &dln); | 
|  | } | 
|  |  | 
|  | /* Write the global symbols out to the debug info.  */ | 
|  |  | 
|  | static void | 
|  | wr_globals (struct coff_ofile *p, struct coff_sfile *sfile, | 
|  | int n ATTRIBUTE_UNUSED) | 
|  | { | 
|  | struct coff_symbol *sy; | 
|  |  | 
|  | for (sy = p->symbol_list_head; | 
|  | sy; | 
|  | sy = sy->next_in_ofile_list) | 
|  | { | 
|  | if (sy->visible->type == coff_vis_ext_def | 
|  | || sy->visible->type == coff_vis_ext_ref) | 
|  | { | 
|  | /* Only write out symbols if they belong to | 
|  | the current source file.  */ | 
|  | if (sy->sfile == sfile) | 
|  | walk_tree_symbol (sfile, 0, sy, 0); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_debug (struct coff_ofile *p) | 
|  | { | 
|  | struct coff_sfile *sfile; | 
|  | int n = 0; | 
|  |  | 
|  | for (sfile = p->source_head; | 
|  | sfile; | 
|  | sfile = sfile->next) | 
|  | { | 
|  | if (debug) | 
|  | printf ("%s\n", sfile->name); | 
|  |  | 
|  | wr_du (p, sfile, n); | 
|  | wr_dus (p, sfile); | 
|  | wr_program_structure (p, sfile); | 
|  | wr_dln (p, sfile, n); | 
|  | n++; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_cs (void) | 
|  | { | 
|  | /* It seems that the CS struct is not normal - the size is wrong | 
|  | heres one I prepared earlier.  */ | 
|  | static char b[] = | 
|  | { | 
|  | 0x80,			/* IT */ | 
|  | 0x21,			/* RL */ | 
|  | 0x00,			/* number of chars in variable length part */ | 
|  | 0x80,			/* hd */ | 
|  | 0x00,			/* hs */ | 
|  | 0x80,			/* un */ | 
|  | 0x00,			/* us */ | 
|  | 0x80,			/* sc */ | 
|  | 0x00,			/* ss */ | 
|  | 0x80,			/* er */ | 
|  | 0x80,			/* ed */ | 
|  | 0x80,			/* sh */ | 
|  | 0x80,			/* ob */ | 
|  | 0x80,			/* rl */ | 
|  | 0x80,			/* du */ | 
|  | 0x80,			/* dps */ | 
|  | 0x80,			/* dsy */ | 
|  | 0x80,			/* dty */ | 
|  | 0x80,			/* dln */ | 
|  | 0x80,			/* dso */ | 
|  | 0x80,			/* dus */ | 
|  | 0x00,			/* dss */ | 
|  | 0x80,			/* dbt */ | 
|  | 0x00,			/* dpp */ | 
|  | 0x80,			/* dfp */ | 
|  | 0x80,			/* den */ | 
|  | 0x80,			/* dds */ | 
|  | 0x80,			/* dar */ | 
|  | 0x80,			/* dpt */ | 
|  | 0x00,			/* dul */ | 
|  | 0x00,			/* dse */ | 
|  | 0x00,			/* dot */ | 
|  | 0xDE			/* CS */ | 
|  | }; | 
|  |  | 
|  | if (fwrite (b, sizeof (b), 1, file) != 1) | 
|  | /* FIXME: Return error status.  */ | 
|  | fatal (_("Failed to write CS struct")); | 
|  | } | 
|  |  | 
|  | /* Write out the SC records for a unit.  Create an SC | 
|  | for all the sections which appear in the output file, even | 
|  | if there isn't an equivalent one on the input.  */ | 
|  |  | 
|  | static int | 
|  | wr_sc (struct coff_ofile *ptr, struct coff_sfile *sfile) | 
|  | { | 
|  | int i; | 
|  | int scount = 0; | 
|  | /* First work out the total number of sections.  */ | 
|  | int total_sec = ptr->nsections; | 
|  | struct myinfo | 
|  | { | 
|  | struct coff_section *sec; | 
|  | struct coff_symbol *symbol; | 
|  | }; | 
|  | struct coff_symbol *symbol; | 
|  | struct myinfo *info | 
|  | = (struct myinfo *) calloc (total_sec, sizeof (struct myinfo)); | 
|  |  | 
|  |  | 
|  | for (i = 0; i < total_sec; i++) | 
|  | { | 
|  | info[i].sec = ptr->sections + i; | 
|  | info[i].symbol = 0; | 
|  | } | 
|  |  | 
|  | for (symbol = sfile->scope->vars_head; | 
|  | symbol; | 
|  | symbol = symbol->next) | 
|  | { | 
|  |  | 
|  | if (symbol->type->type == coff_secdef_type) | 
|  | { | 
|  | for (i = 0; i < total_sec; i++) | 
|  | { | 
|  | if (symbol->where->section == info[i].sec) | 
|  | { | 
|  | info[i].symbol = symbol; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Now output all the section info, and fake up some stuff for sections | 
|  | we don't have.  */ | 
|  | for (i = 1; i < total_sec; i++) | 
|  | { | 
|  | struct IT_sc sc; | 
|  | char *name; | 
|  |  | 
|  | symbol = info[i].symbol; | 
|  | sc.spare = 0; | 
|  | sc.spare1 = 0; | 
|  |  | 
|  | if (!symbol) | 
|  | { | 
|  | /* Don't have a symbol set aside for this section, which means | 
|  | that nothing in this file does anything for the section.  */ | 
|  | sc.format = !(bfd_get_file_flags (abfd) & EXEC_P); | 
|  | sc.addr = 0; | 
|  | sc.length = 0; | 
|  | name = info[i].sec->name; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (bfd_get_file_flags (abfd) & EXEC_P) | 
|  | { | 
|  | sc.format = 0; | 
|  | sc.addr = symbol->where->offset; | 
|  | } | 
|  | else | 
|  | { | 
|  | sc.format = 1; | 
|  | sc.addr = 0; | 
|  | } | 
|  | sc.length = symbol->type->size; | 
|  | name = symbol->name; | 
|  | } | 
|  |  | 
|  | sc.align = 4; | 
|  | sc.concat = CONCAT_SIMPLE; | 
|  | sc.read = 3; | 
|  | sc.write = 3; | 
|  | sc.exec = 3; | 
|  | sc.init = 3; | 
|  | sc.mode = 3; | 
|  | sc.spare = 0; | 
|  | sc.segadd = 0; | 
|  | sc.spare1 = 0;		/* If not zero, then it doesn't work.  */ | 
|  | sc.name = section_translate (name); | 
|  |  | 
|  | if (strlen (sc.name) == 1) | 
|  | { | 
|  | switch (sc.name[0]) | 
|  | { | 
|  | case 'D': | 
|  | case 'B': | 
|  | sc.contents = CONTENTS_DATA; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | sc.contents = CONTENTS_CODE; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | sc.contents = CONTENTS_CODE; | 
|  | } | 
|  |  | 
|  | sysroff_swap_sc_out (file, &sc); | 
|  | scount++; | 
|  | } | 
|  | free (info); | 
|  | return scount; | 
|  | } | 
|  |  | 
|  | /* Write out the ER records for a unit.  */ | 
|  |  | 
|  | static void | 
|  | wr_er (struct coff_ofile *ptr, struct coff_sfile *sfile ATTRIBUTE_UNUSED, | 
|  | int first) | 
|  | { | 
|  | int idx = 0; | 
|  | struct coff_symbol *sym; | 
|  |  | 
|  | if (first) | 
|  | { | 
|  | for (sym = ptr->symbol_list_head; sym; sym = sym->next_in_ofile_list) | 
|  | { | 
|  | if (sym->visible->type == coff_vis_ext_ref) | 
|  | { | 
|  | struct IT_er er; | 
|  |  | 
|  | er.spare = 0; | 
|  | er.type = ER_NOTSPEC; | 
|  | er.name = sym->name; | 
|  | sysroff_swap_er_out (file, &er); | 
|  | sym->er_number = idx++; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Write out the ED records for a unit.  */ | 
|  |  | 
|  | static void | 
|  | wr_ed (struct coff_ofile *ptr, struct coff_sfile *sfile ATTRIBUTE_UNUSED, | 
|  | int first) | 
|  | { | 
|  | struct coff_symbol *s; | 
|  |  | 
|  | if (first) | 
|  | { | 
|  | for (s = ptr->symbol_list_head; s; s = s->next_in_ofile_list) | 
|  | { | 
|  | if (s->visible->type == coff_vis_ext_def | 
|  | || s->visible->type == coff_vis_common) | 
|  | { | 
|  | struct IT_ed ed; | 
|  |  | 
|  | ed.section = s->where->section->number; | 
|  | ed.spare = 0; | 
|  |  | 
|  | if (s->where->section->data) | 
|  | { | 
|  | ed.type = ED_TYPE_DATA; | 
|  | } | 
|  | else if (s->where->section->code & SEC_CODE) | 
|  | { | 
|  | ed.type = ED_TYPE_ENTRY; | 
|  | } | 
|  | else | 
|  | { | 
|  | ed.type = ED_TYPE_NOTSPEC; | 
|  | ed.type = ED_TYPE_DATA; | 
|  | } | 
|  |  | 
|  | ed.address = s->where->offset - s->where->section->address; | 
|  | ed.name = s->name; | 
|  | sysroff_swap_ed_out (file, &ed); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_unit_info (struct coff_ofile *ptr) | 
|  | { | 
|  | struct coff_sfile *sfile; | 
|  | int first = 1; | 
|  |  | 
|  | for (sfile = ptr->source_head; | 
|  | sfile; | 
|  | sfile = sfile->next) | 
|  | { | 
|  | long p1; | 
|  | long p2; | 
|  | int nsecs; | 
|  |  | 
|  | p1 = ftell (file); | 
|  | wr_un (ptr, sfile, first, 0); | 
|  | nsecs = wr_sc (ptr, sfile); | 
|  | p2 = ftell (file); | 
|  | fseek (file, p1, SEEK_SET); | 
|  | wr_un (ptr, sfile, first, nsecs); | 
|  | fseek (file, p2, SEEK_SET); | 
|  | wr_er (ptr, sfile, first); | 
|  | wr_ed (ptr, sfile, first); | 
|  | first = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | wr_module (struct coff_ofile *p) | 
|  | { | 
|  | wr_cs (); | 
|  | wr_hd (p); | 
|  | wr_unit_info (p); | 
|  | wr_object_body (p); | 
|  | wr_debug (p); | 
|  | wr_tr (); | 
|  | } | 
|  |  | 
|  | static int | 
|  | align (int x) | 
|  | { | 
|  | return (x + 3) & ~3; | 
|  | } | 
|  |  | 
|  | /* Find all the common variables and turn them into | 
|  | ordinary defs - dunno why, but thats what hitachi does with 'em.  */ | 
|  |  | 
|  | static void | 
|  | prescan (struct coff_ofile *otree) | 
|  | { | 
|  | struct coff_symbol *s; | 
|  | struct coff_section *common_section; | 
|  |  | 
|  | if (otree->nsections < 3) | 
|  | return; | 
|  |  | 
|  | /* Find the common section - always section 3.  */ | 
|  | common_section = otree->sections + 3; | 
|  |  | 
|  | for (s = otree->symbol_list_head; | 
|  | s; | 
|  | s = s->next_in_ofile_list) | 
|  | { | 
|  | if (s->visible->type == coff_vis_common) | 
|  | { | 
|  | struct coff_where *w = s->where; | 
|  | /*      s->visible->type = coff_vis_ext_def; leave it as common */ | 
|  | common_section->size = align (common_section->size); | 
|  | w->offset = common_section->size + common_section->address; | 
|  | w->section = common_section; | 
|  | common_section->size += s->type->size; | 
|  | common_section->size = align (common_section->size); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | ATTRIBUTE_NORETURN static void | 
|  | show_usage (FILE *ffile, int status) | 
|  | { | 
|  | fprintf (ffile, _("Usage: %s [option(s)] in-file [out-file]\n"), program_name); | 
|  | fprintf (ffile, _("Convert a COFF object file into a SYSROFF object file\n")); | 
|  | fprintf (ffile, _(" The options are:\n\ | 
|  | -q --quick       (Obsolete - ignored)\n\ | 
|  | -n --noprescan   Do not perform a scan to convert commons into defs\n\ | 
|  | -d --debug       Display information about what is being done\n\ | 
|  | @<file>          Read options from <file>\n\ | 
|  | -h --help        Display this information\n\ | 
|  | -v --version     Print the program's version number\n")); | 
|  |  | 
|  | if (REPORT_BUGS_TO[0] && status == 0) | 
|  | fprintf (ffile, _("Report bugs to %s\n"), REPORT_BUGS_TO); | 
|  | exit (status); | 
|  | } | 
|  |  | 
|  | int | 
|  | main (int ac, char **av) | 
|  | { | 
|  | int opt; | 
|  | static struct option long_options[] = | 
|  | { | 
|  | {"debug", no_argument, 0, 'd'}, | 
|  | {"quick", no_argument, 0, 'q'}, | 
|  | {"noprescan", no_argument, 0, 'n'}, | 
|  | {"help", no_argument, 0, 'h'}, | 
|  | {"version", no_argument, 0, 'V'}, | 
|  | {NULL, no_argument, 0, 0} | 
|  | }; | 
|  | char **matching; | 
|  | char *input_file; | 
|  | char *output_file; | 
|  |  | 
|  | #ifdef HAVE_LC_MESSAGES | 
|  | setlocale (LC_MESSAGES, ""); | 
|  | #endif | 
|  | setlocale (LC_CTYPE, ""); | 
|  | bindtextdomain (PACKAGE, LOCALEDIR); | 
|  | textdomain (PACKAGE); | 
|  |  | 
|  | program_name = av[0]; | 
|  | xmalloc_set_program_name (program_name); | 
|  | bfd_set_error_program_name (program_name); | 
|  |  | 
|  | expandargv (&ac, &av); | 
|  |  | 
|  | while ((opt = getopt_long (ac, av, "dHhVvqn", long_options, | 
|  | (int *) NULL)) | 
|  | != EOF) | 
|  | { | 
|  | switch (opt) | 
|  | { | 
|  | case 'q': | 
|  | quick = 1; | 
|  | break; | 
|  | case 'n': | 
|  | noprescan = 1; | 
|  | break; | 
|  | case 'd': | 
|  | debug = 1; | 
|  | break; | 
|  | case 'H': | 
|  | case 'h': | 
|  | show_usage (stdout, 0); | 
|  | /*NOTREACHED */ | 
|  | case 'v': | 
|  | case 'V': | 
|  | print_version ("srconv"); | 
|  | exit (0); | 
|  | /*NOTREACHED */ | 
|  | case 0: | 
|  | break; | 
|  | default: | 
|  | show_usage (stderr, 1); | 
|  | /*NOTREACHED */ | 
|  | } | 
|  | } | 
|  |  | 
|  | /* The input and output files may be named on the command line.  */ | 
|  | output_file = NULL; | 
|  | if (optind < ac) | 
|  | { | 
|  | input_file = av[optind]; | 
|  | ++optind; | 
|  | if (optind < ac) | 
|  | { | 
|  | output_file = av[optind]; | 
|  | ++optind; | 
|  | if (optind < ac) | 
|  | show_usage (stderr, 1); | 
|  | if (filename_cmp (input_file, output_file) == 0) | 
|  | { | 
|  | fatal (_("input and output files must be different")); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | input_file = 0; | 
|  |  | 
|  | if (!input_file) | 
|  | { | 
|  | fatal (_("no input file specified")); | 
|  | } | 
|  |  | 
|  | if (!output_file) | 
|  | { | 
|  | /* Take a .o off the input file and stick on a .obj.  If | 
|  | it doesn't end in .o, then stick a .obj on anyway */ | 
|  |  | 
|  | int len = strlen (input_file); | 
|  |  | 
|  | output_file = xmalloc (len + 5); | 
|  | strcpy (output_file, input_file); | 
|  |  | 
|  | if (len > 3 | 
|  | && output_file[len - 2] == '.' | 
|  | && output_file[len - 1] == 'o') | 
|  | { | 
|  | output_file[len] = 'b'; | 
|  | output_file[len + 1] = 'j'; | 
|  | output_file[len + 2] = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | strcat (output_file, ".obj"); | 
|  | } | 
|  | } | 
|  |  | 
|  | abfd = bfd_openr (input_file, 0); | 
|  |  | 
|  | if (!abfd) | 
|  | bfd_fatal (input_file); | 
|  |  | 
|  | if (!bfd_check_format_matches (abfd, bfd_object, &matching)) | 
|  | { | 
|  | bfd_nonfatal (input_file); | 
|  |  | 
|  | if (bfd_get_error () == bfd_error_file_ambiguously_recognized) | 
|  | list_matching_formats (matching); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | file = fopen (output_file, FOPEN_WB); | 
|  |  | 
|  | if (!file) | 
|  | fatal (_("unable to open output file %s"), output_file); | 
|  |  | 
|  | if (debug) | 
|  | printf ("ids %d %d\n", base1, base2); | 
|  |  | 
|  | tree = coff_grok (abfd); | 
|  | if (tree) | 
|  | { | 
|  | if (!noprescan) | 
|  | prescan (tree); | 
|  |  | 
|  | wr_module (tree); | 
|  | } | 
|  | return 0; | 
|  | } |