aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorKung Hsu <kung@cygnus>1994-03-01 23:13:56 +0000
committerKung Hsu <kung@cygnus>1994-03-01 23:13:56 +0000
commit1340861c99fc5ca7f4acacbdaa449f1d4c57eb80 (patch)
tree81dddce5ec765062988b2b06eec7dbca18a2e91c /gdb
parentbb37e7161e6c7f271f56d8b920cb3a0ad06116de (diff)
downloadgdb-1340861c99fc5ca7f4acacbdaa449f1d4c57eb80.zip
gdb-1340861c99fc5ca7f4acacbdaa449f1d4c57eb80.tar.gz
gdb-1340861c99fc5ca7f4acacbdaa449f1d4c57eb80.tar.bz2
Modified Files:
ChangeLog objfiles.c objfiles.h symfile.c target.c main.c Makefile.in configure.in Added Files: os9kread.c os9kstab.c remote-os9k.c * os9kread.c: New file to read os9000 style symbo table. * os9kstab.c: new file to read os9000 style stabs. * remote-os9k.c: remote protocol talking to os9000 rombug monitor. * objfiles.c (find_pc_objfile): new function to search objfile from pc. * objfiles.c (objfile_relocate_data): new function to relocate data symbols in symbol table. * objfiles.h: Add two aux fields in struct objfile to handle multiple symbol table files situation like in os9000. * symfile.c: Change so 'symbol-file' command can handle multiple files. Also call target_link() to get relocation infos. * target.c (target_link): new function to get relocation info when a symbol file is requested to load. * main.c (quit_command): take out 'inferior_pid != 0' condition, because in cross mode there's no inferior pid, bit they need to be detached. Makefile.in: add os9kread.c os9kstab.c and .o's. configure.in: add i386os9k target. config/i386/i386os9k.mt: new add. config/i386/tm-i386os9k.h: new add.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog23
-rw-r--r--gdb/Makefile.in15
-rw-r--r--gdb/configure.in2
-rw-r--r--gdb/main.c9
-rw-r--r--gdb/objfiles.c116
-rw-r--r--gdb/objfiles.h5
-rw-r--r--gdb/os9kread.c1659
-rw-r--r--gdb/os9kstab.c2024
-rw-r--r--gdb/remote-os9k.c1181
-rw-r--r--gdb/symfile.c40
-rw-r--r--gdb/target.c13
11 files changed, 5074 insertions, 13 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 12f89b6..3ed27e1 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,26 @@
+Tue Mar 1 14:56:14 1994 Kung Hsu (kung@mexican.cygnus.com)
+
+ * os9kread.c: New file to read os9000 style symbo table.
+ * os9kstab.c: new file to read os9000 style stabs.
+ * remote-os9k.c: remote protocol talking to os9000 rombug monitor.
+ * objfiles.c (find_pc_objfile): new function to search objfile
+ from pc.
+ * objfiles.c (objfile_relocate_data): new function to relocate
+ data symbols in symbol table.
+ * objfiles.h: Add two aux fields in struct objfile to handle
+ multiple symbol table files situation like in os9000.
+ * symfile.c: Change so 'symbol-file' command can handle multiple
+ files. Also call target_link() to get relocation infos.
+ * target.c (target_link): new function to get relocation info when
+ a symbol file is requested to load.
+ * main.c (quit_command): take out 'inferior_pid != 0' condition,
+ because in cross mode there's no inferior pid, bit they need to
+ be detached.
+ Makefile.in: add os9kread.c os9kstab.c and .o's.
+ configure.in: add i386os9k target.
+ config/i386/i386os9k.mt: new add.
+ config/i386/tm-i386os9k.h: new add.
+
Tue Mar 1 13:16:10 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
* config/sparc/tm-sun4sol2.h (IN_SIGTRAMP): Handle ucbsigvechandler.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index dfedc1f..34407a8 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -178,7 +178,7 @@ CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) \
ADD_FILES = $(REGEX) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES)
ADD_DEPS = $(REGEX1) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES)
-VERSION = 4.12.1
+VERSION = 4.12.2
DIST=gdb
LINT=/usr/5bin/lint
@@ -305,7 +305,8 @@ SFILES = blockframe.c breakpoint.c buildsym.c c-exp.y c-lang.c \
mem-break.c minsyms.c mipsread.c nlmread.c objfiles.c parse.c \
printcmd.c remote.c source.c stabsread.c stack.c symfile.c symmisc.c \
symtab.c target.c thread.c typeprint.c utils.c valarith.c valops.c \
- valprint.c values.c serial.c ser-unix.c mdebugread.c
+ valprint.c values.c serial.c ser-unix.c mdebugread.c os9kread.c \
+ os9kstab.c
# Files that are not source code, but need to go into
# gdb-$(VERSION).tar.Z.
@@ -442,7 +443,7 @@ OBS = version.o main.o blockframe.o breakpoint.o findvar.o stack.o thread.o \
dwarfread.o mipsread.o stabsread.o core.o c-lang.o ch-lang.o m2-lang.o \
complaints.o typeprint.o c-typeprint.o ch-typeprint.o m2-typeprint.o \
c-valprint.o cp-valprint.o ch-valprint.o m2-valprint.o nlmread.o \
- serial.o mdebugread.o
+ serial.o mdebugread.o os9kread.o os9kstab.o
TSOBS = inflow.o
@@ -1275,6 +1276,14 @@ mdebugread.o: mdebugread.c buildsym.h complaints.h $(bfd_h) $(defs_h) \
$(expression_h) gdb-stabs.h $(gdbcore_h) $(gdbtypes_h) language.h \
objfiles.h partial-stab.h stabsread.h symfile.h $(symtab_h)
+os9kread.o: os9kread.c buildsym.h complaints.h $(bfd_h) $(def_h) \
+ $(expression_h) gdb-stabs.h $(gdbcore_h) $(gdbtypes_h) language.h \
+ objfiles.h partial-stab.h stabsread.h symfile.h $(symtab_h)
+
+os9kstab.o: os9kstab.c $(bfd_h) $(INCLUDE_DIR)/aout/stab.def \
+ $(INCLUDE_DIR)/aout/stab_gnu.h buildsym.h complaints.h $(defs_h) \
+ $(gdbtypes_h) objfiles.h stabsread.h symfile.h $(symtab_h)
+
mem-break.o: mem-break.c $(defs_h)
minsyms.o: minsyms.c $(bfd_h) $(defs_h) objfiles.h symfile.h \
diff --git a/gdb/configure.in b/gdb/configure.in
index 9af7805..1f9682b 100644
--- a/gdb/configure.in
+++ b/gdb/configure.in
@@ -59,6 +59,7 @@ i[34]86-*-sysv4*) gdb_host=i386v4 ;;
i[34]86-*-unixware) gdb_host=i386v4 ;;
i[34]86-*-sysv*) gdb_host=i386v ;;
i[34]86-*-isc*) gdb_host=i386v32 ;;
+i[34]86-*-os9k) gdb_host=i386os9k ;;
m680[01]0-sun-sunos3*) gdb_host=sun2os3 ;;
m680[01]0-sun-sunos4*) gdb_host=sun2os4 ;;
@@ -199,6 +200,7 @@ i[34]86-*-elf*) gdb_target=i386v ;;
i[34]86-*-aix*) gdb_target=i386aix ;;
i[34]86-*-bsd*) gdb_target=i386bsd ;;
i[34]86-*-netbsd*) gdb_target=i386bsd ;;
+i[34]86-*-os9k) gdb_target=i386os9k ;;
i[34]86-*-go32*) gdb_target=i386aout ;;
i[34]86-*-lynxos*) gdb_target=i386lynx
configdirs="${configdirs} gdbserver"
diff --git a/gdb/main.c b/gdb/main.c
index 2cdabaf..13154e1 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -2222,7 +2222,10 @@ quit_command (args, from_tty)
char *args;
int from_tty;
{
- if (inferior_pid != 0 && target_has_execution)
+ /* kung: inferior_pid may not exist in cross mode debugging,
+ I commented it out temporarily, if it does not cause other problem,
+ we should take it out permenantly. */
+ if (/*inferior_pid != 0 &&*/ target_has_execution)
{
if (attach_flag)
{
@@ -2239,9 +2242,13 @@ quit_command (args, from_tty)
error ("Not confirmed.");
}
}
+ /* UDI wants this, to kill the TIP. */
+ target_close (1);
+
/* Save the history information if it is appropriate to do so. */
if (write_history_p && history_filename)
write_history (history_filename);
+
exit (0);
}
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 381a095..40ab8fb 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -421,6 +421,21 @@ free_all_objfiles ()
clear_symtab_users ();
}
+struct objfile *
+find_pc_objfile(pc)
+ CORE_ADDR pc;
+{
+struct objfile *obj;
+struct obj_section *s;
+
+ ALL_OBJFILES (obj)
+ for (s = obj->sections; s < obj->sections_end; s++)
+ {
+ if (s->addr <= pc && s->endaddr > pc) return obj;
+ }
+ return (struct objfile *)NULL;
+}
+
/* Relocate OBJFILE to NEW_OFFSETS. There should be OBJFILE->NUM_SECTIONS
entries in new_offsets. */
void
@@ -540,6 +555,107 @@ objfile_relocate (objfile, new_offsets)
}
}
+/* Relocate OBJFILE to NEW_OFFSETS. There should be OBJFILE->NUM_SECTIONS
+ entries in new_offsets. */
+void
+objfile_relocate_data (objfile, new_offsets)
+ struct objfile *objfile;
+ struct section_offsets *new_offsets;
+{
+ struct section_offsets *delta = (struct section_offsets *) alloca
+ (sizeof (struct section_offsets)
+ + objfile->num_sections * sizeof (delta->offsets));
+
+ {
+ int i;
+ int something_changed = 0;
+ for (i = 0; i < objfile->num_sections; ++i)
+ {
+ if (i != SECT_OFF_DATA && i != SECT_OFF_BSS)
+ ANOFFSET (delta, i) = 0;
+ else
+ ANOFFSET (delta, i) = ANOFFSET(new_offsets, i)
+ - ANOFFSET (objfile->section_offsets, i);
+ if (ANOFFSET (delta, i) != 0)
+ something_changed = 1;
+ }
+ if (!something_changed)
+ return;
+ }
+
+ /* OK, get all the symtabs. */
+ {
+ struct symtab *s;
+
+ for (s = objfile->symtabs; s; s = s->next)
+ {
+ struct linetable *l;
+ struct blockvector *bv;
+ int i;
+
+ /* Don't relocate a shared blockvector more than once. */
+ if (!s->primary)
+ continue;
+
+ bv = BLOCKVECTOR (s);
+ for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i)
+ {
+ struct block *b;
+ int j;
+
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ BLOCK_START (b) += ANOFFSET (delta, s->block_line_section);
+ BLOCK_END (b) += ANOFFSET (delta, s->block_line_section);
+
+ for (j = 0; j < BLOCK_NSYMS (b); ++j)
+ {
+ struct symbol *sym = BLOCK_SYM (b, j);
+ /* The RS6000 code from which this was taken skipped
+ any symbols in STRUCT_NAMESPACE or UNDEF_NAMESPACE.
+ But I'm leaving out that test, on the theory that
+ they can't possibly pass the tests below. */
+ if ((SYMBOL_CLASS (sym) == LOC_LABEL
+ || SYMBOL_CLASS (sym) == LOC_STATIC)
+ && SYMBOL_SECTION (sym) >= 0)
+ {
+ SYMBOL_VALUE_ADDRESS (sym) +=
+ ANOFFSET (delta, SYMBOL_SECTION (sym));
+ }
+ }
+ }
+ }
+ }
+
+ {
+ struct partial_symbol *psym;
+
+ for (psym = objfile->global_psymbols.list;
+ psym < objfile->global_psymbols.next;
+ psym++)
+ if (SYMBOL_SECTION (psym) >= 0)
+ SYMBOL_VALUE_ADDRESS (psym) += ANOFFSET (delta, SYMBOL_SECTION (psym));
+ for (psym = objfile->static_psymbols.list;
+ psym < objfile->static_psymbols.next;
+ psym++)
+ if (SYMBOL_SECTION (psym) >= 0)
+ SYMBOL_VALUE_ADDRESS (psym) += ANOFFSET (delta, SYMBOL_SECTION (psym));
+ }
+
+ {
+ struct minimal_symbol *msym;
+ ALL_OBJFILE_MSYMBOLS (objfile, msym)
+ if (SYMBOL_SECTION (msym) >= 0)
+ SYMBOL_VALUE_ADDRESS (msym) += ANOFFSET (delta, SYMBOL_SECTION (msym));
+ }
+
+ {
+ int i;
+ for (i = 0; i < objfile->num_sections; ++i)
+ if (i == SECT_OFF_DATA || i == SECT_OFF_BSS)
+ ANOFFSET (objfile->section_offsets, i) = ANOFFSET (new_offsets, i);
+ }
+}
+
/* Many places in gdb want to test just to see if we have any partial
symbols available. This function returns zero if none are currently
available, nonzero otherwise. */
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index 6cff2ca..381a6d6 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -310,6 +310,9 @@ struct objfile
struct obj_section
*sections,
*sections_end;
+
+ /* two auxiliary fields, used to hold the fp of separate symbol files */
+ FILE *auxf1, *auxf2;
};
/* Defines for the objfile flag word. */
@@ -370,6 +373,8 @@ extern void free_objfile PARAMS ((struct objfile *));
extern void
free_all_objfiles PARAMS ((void));
+extern struct objfile * find_pc_objfile PARAMS ((CORE_ADDR));
+
extern void
objfile_relocate PARAMS ((struct objfile *, struct section_offsets *));
diff --git a/gdb/os9kread.c b/gdb/os9kread.c
new file mode 100644
index 0000000..5857c25
--- /dev/null
+++ b/gdb/os9kread.c
@@ -0,0 +1,1659 @@
+/* Read os9/os9k symbol tables and convert to internal format, for GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This module provides three functions: os9k_symfile_init,
+ which initializes to read a symbol file; os9k_new_init, which
+ discards existing cached information when all symbols are being
+ discarded; and os9k_symfile_read, which reads a symbol table
+ from a file.
+
+ os9k_symfile_read only does the minimum work necessary for letting the
+ user "name" things symbolically; it does not read the entire symtab.
+ Instead, it reads the external and static symbols and puts them in partial
+ symbol tables. When more extensive information is requested of a
+ file, the corresponding partial symbol table is mutated into a full
+ fledged symbol table by going back and reading the symbols
+ for real. os9k_psymtab_to_symtab() is the function that does this */
+
+#include "defs.h"
+#include <string.h>
+#include <stdio.h>
+
+#if defined(USG) || defined(__CYGNUSCLIB__)
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#include <obstack.h>
+#include <sys/param.h>
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+#include <sys/stat.h>
+#include <ctype.h>
+#include "symtab.h"
+#include "breakpoint.h"
+#include "command.h"
+#include "target.h"
+#include "gdbcore.h" /* for bfd stuff */
+#include "libbfd.h" /* FIXME Secret internal BFD stuff (bfd_read) */
+#include "libaout.h" /* FIXME Secret internal BFD stuff for a.out */
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "gdb-stabs.h"
+#include "demangle.h"
+#include "language.h" /* Needed inside partial-stab.h */
+#include "complaints.h"
+#include "os9k.h"
+
+#if !defined (SEEK_SET)
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#endif
+
+/* Each partial symbol table entry contains a pointer to private data for the
+ read_symtab() function to use when expanding a partial symbol table entry
+ to a full symbol table entry.
+
+ For dbxread this structure contains the offset within the file symbol table
+ of first local symbol for this file, and count of the section
+ of the symbol table devoted to this file's symbols (actually, the section
+ bracketed may contain more than just this file's symbols). It also contains
+ further information needed to locate the symbols if they are in an ELF file.
+
+ If ldsymcnt is 0, the only reason for this thing's existence is the
+ dependency list. Nothing else will happen when it is read in. */
+
+#define LDSYMOFF(p) (((struct symloc *)((p)->read_symtab_private))->ldsymoff)
+#define LDSYMCNT(p) (((struct symloc *)((p)->read_symtab_private))->ldsymnum)
+
+struct symloc {
+ int ldsymoff;
+ int ldsymnum;
+};
+
+/* Remember what we deduced to be the source language of this psymtab. */
+static enum language psymtab_language = language_unknown;
+
+/* keep partial symbol table file nested depth */
+static int psymfile_depth = 0;
+
+/* keep symbol table file nested depth */
+static int symfile_depth = 0;
+
+/* Nonzero means give verbose info on gdb action. From main.c. */
+extern int info_verbose;
+
+extern int previous_stab_code;
+
+/* The BFD for this file -- implicit parameter to next_symbol_text. */
+static bfd *symfile_bfd;
+
+/* Name of last function encountered. Used in Solaris to approximate
+ object file boundaries. */
+static char *last_function_name;
+
+/* Complaints about the symbols we have encountered. */
+extern struct complaint lbrac_complaint;
+
+extern struct complaint unknown_symtype_complaint;
+
+extern struct complaint unknown_symchar_complaint;
+
+extern struct complaint lbrac_rbrac_complaint;
+
+extern struct complaint repeated_header_complaint;
+
+extern struct complaint repeated_header_name_complaint;
+
+static struct complaint lbrac_unmatched_complaint =
+ {"unmatched Increment Block Entry before symtab pos %d", 0, 0};
+
+static struct complaint lbrac_mismatch_complaint =
+ {"IBE/IDE symbol mismatch at symtab pos %d", 0, 0};
+
+extern struct symbol *
+os9k_define_symbol PARAMS ((CORE_ADDR, char *, int, int, struct objfile *));
+
+
+/* Local function prototypes */
+static void
+os9k_read_ofile_symtab PARAMS ((struct partial_symtab *));
+
+static void
+os9k_psymtab_to_symtab PARAMS ((struct partial_symtab *));
+
+static void
+os9k_psymtab_to_symtab_1 PARAMS ((struct partial_symtab *));
+
+static void
+read_os9k_psymtab PARAMS ((struct section_offsets *, struct objfile *,
+ CORE_ADDR, int));
+
+static void
+init_psymbol_list PARAMS ((struct objfile *));
+
+static char *
+os9k_next_symbol_text PARAMS ((void));
+
+static int
+fill_sym PARAMS ((FILE *, bfd *));
+
+static void
+os9k_symfile_init PARAMS ((struct objfile *));
+
+static void
+os9k_new_init PARAMS ((struct objfile *));
+
+static void
+os9k_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int));
+
+static void
+os9k_symfile_finish PARAMS ((struct objfile *));
+
+static void
+os9k_process_one_symbol PARAMS ((int, int, CORE_ADDR, char *,
+ struct section_offsets *, struct objfile *));
+
+static struct partial_symtab *
+os9k_start_psymtab PARAMS ((struct objfile *, struct section_offsets *, char *,
+ CORE_ADDR, int, int, struct partial_symbol *,
+ struct partial_symbol *));
+
+static struct partial_symtab *
+os9k_end_psymtab PARAMS ((struct partial_symtab *, char **, int, int, CORE_ADDR,
+ struct partial_symtab **, int));
+
+static void
+record_minimal_symbol PARAMS ((char *, CORE_ADDR, int, struct objfile *));
+
+#define HANDLE_RBRAC(val) \
+ if ((val) > pst->texthigh) pst->texthigh = (val);
+
+#define SWAP_STBHDR(hdrp, abfd) \
+ { \
+ (hdrp)->fmtno = bfd_get_16(abfd, (unsigned char *)&(hdrp)->fmtno); \
+ (hdrp)->crc = bfd_get_32(abfd, (unsigned char *)&(hdrp)->crc); \
+ (hdrp)->offset = bfd_get_32(abfd, (unsigned char *)&(hdrp)->offset); \
+ (hdrp)->nsym = bfd_get_32(abfd, (unsigned char *)&(hdrp)->nsym); \
+ }
+#define SWAP_STBSYM(symp, abfd) \
+ { \
+ (symp)->value = bfd_get_32(abfd, (unsigned char *)&(symp)->value); \
+ (symp)->type = bfd_get_16(abfd, (unsigned char *)&(symp)->type); \
+ (symp)->stroff = bfd_get_32(abfd, (unsigned char *)&(symp)->stroff); \
+ }
+#define N_DATA 0
+#define N_BSS 1
+#define N_RDATA 2
+#define N_IDATA 3
+#define N_TEXT 4
+#define N_ABS 6
+
+static void
+record_minimal_symbol (name, address, type, objfile)
+ char *name;
+ CORE_ADDR address;
+ int type;
+ struct objfile *objfile;
+{
+ enum minimal_symbol_type ms_type;
+
+ switch (type)
+ {
+ case N_TEXT: ms_type = mst_text; break;
+ case N_DATA: ms_type = mst_data; break;
+ case N_BSS: ms_type = mst_bss; break;
+ case N_RDATA: ms_type = mst_bss; break;
+ case N_IDATA: ms_type = mst_data; break;
+ case N_ABS: ms_type = mst_abs; break;
+ default: ms_type = mst_unknown; break;
+ }
+
+ prim_record_minimal_symbol
+ (obsavestring (name, strlen(name), &objfile->symbol_obstack),
+ address, ms_type, objfile);
+}
+
+/* read and process .stb file and store in minimal symbol table */
+typedef char mhhdr[80];
+struct stbhdr {
+ mhhdr comhdr;
+ char * name;
+ short fmtno;
+ int crc;
+ int offset;
+ int nsym;
+ char *pad;
+};
+struct stbsymbol {
+ int value;
+ short type;
+ int stroff;
+};
+#define STBSYMSIZE 10
+
+static int
+read_minimal_symbols(objfile)
+ struct objfile *objfile;
+{
+FILE *fp;
+bfd *abfd;
+struct stbhdr hdr;
+struct stbsymbol sym;
+int ch, i, j, off;
+char buf[64], buf1[128];
+
+ fp = objfile->auxf1;
+ if (fp == NULL) return;
+ abfd = objfile->obfd;
+ fread(&hdr.comhdr[0], sizeof(mhhdr), 1, fp);
+ i = 0;
+ ch = getc(fp);
+ while (ch != -1) {
+ buf[i] = (char)ch;
+ i++;
+ if (ch == 0) break;
+ ch = getc(fp);
+ };
+ hdr.name = &buf[0];
+
+ fread(&hdr.fmtno, sizeof(hdr.fmtno), 1, fp);
+ fread(&hdr.crc, sizeof(hdr.crc), 1, fp);
+ fread(&hdr.offset, sizeof(hdr.offset), 1, fp);
+ fread(&hdr.nsym, sizeof(hdr.nsym), 1, fp);
+ SWAP_STBHDR(&hdr, abfd);
+
+ /* read symbols */
+ init_minimal_symbol_collection();
+ off = hdr.offset;
+ for (i = hdr.nsym; i > 0; i--) {
+ fseek(fp, (long)off, 0);
+ fread(&sym.value, sizeof(sym.value), 1, fp);
+ fread(&sym.type, sizeof(sym.type), 1, fp);
+ fread(&sym.stroff, sizeof(sym.stroff), 1, fp);
+ SWAP_STBSYM (&sym, abfd);
+ fseek(fp, (long)sym.stroff, 0);
+ j = 0;
+ ch = getc(fp);
+ while (ch != -1) {
+ buf1[j] = (char)ch;
+ j++;
+ if (ch == 0) break;
+ ch = getc(fp);
+ };
+ record_minimal_symbol(buf1, sym.value, sym.type&7, objfile);
+ off += STBSYMSIZE;
+ };
+ install_minimal_symbols (objfile);
+ return 1;
+}
+
+/* Scan and build partial symbols for a symbol file.
+ We have been initialized by a call to os9k_symfile_init, which
+ put all the relevant info into a "struct os9k_symfile_info",
+ hung off the objfile structure.
+
+ SECTION_OFFSETS contains offsets relative to which the symbols in the
+ various sections are (depending where the sections were actually loaded).
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file). */
+
+static void
+os9k_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline; /* FIXME comments above */
+{
+ bfd *sym_bfd;
+ int val;
+ int stb_exist;
+ struct cleanup *back_to;
+
+ sym_bfd = objfile->obfd;
+ /* If we are reinitializing, or if we have never loaded syms yet, init */
+ if (mainline || objfile->global_psymbols.size == 0 ||
+ objfile->static_psymbols.size == 0)
+ init_psymbol_list (objfile);
+
+ pending_blocks = 0;
+ back_to = make_cleanup (really_free_pendings, 0);
+
+ make_cleanup (discard_minimal_symbols, 0);
+ read_minimal_symbols (objfile);
+
+ /* Now that the symbol table data of the executable file are all in core,
+ process them and define symbols accordingly. */
+ read_os9k_psymtab (section_offsets, objfile,
+ bfd_section_vma (sym_bfd, DBX_TEXT_SECT (objfile)),
+ bfd_section_size (sym_bfd, DBX_TEXT_SECT (objfile)));
+
+ if (!have_partial_symbols ()) {
+ wrap_here ("");
+ printf_filtered ("(no debugging symbols found)...");
+ wrap_here ("");
+ }
+
+ do_cleanups (back_to);
+}
+
+/* Initialize anything that needs initializing when a completely new
+ symbol file is specified (not just adding some symbols from another
+ file, e.g. a shared library). */
+
+static void
+os9k_new_init (ignore)
+ struct objfile *ignore;
+{
+ stabsread_new_init ();
+ buildsym_new_init ();
+ psymfile_depth = 0;
+/*
+ init_header_files ();
+*/
+}
+
+/* os9k_symfile_init ()
+ It is passed a struct objfile which contains, among other things,
+ the BFD for the file whose symbols are being read, and a slot for a pointer
+ to "private data" which we fill with goodies.
+
+ Since BFD doesn't know how to read debug symbols in a format-independent
+ way (and may never do so...), we have to do it ourselves. We will never
+ be called unless this is an a.out (or very similar) file.
+ FIXME, there should be a cleaner peephole into the BFD environment here. */
+
+static void
+os9k_symfile_init (objfile)
+ struct objfile *objfile;
+{
+ int val;
+ bfd *sym_bfd = objfile->obfd;
+ char *name = bfd_get_filename (sym_bfd);
+ char dbgname[64], stbname[64];
+ FILE *symfile = 0;
+ FILE *minfile = 0;
+
+
+ strcpy(dbgname, name);
+ strcat(dbgname, ".dbg");
+ strcpy(stbname, name);
+ strcat(stbname, ".stb");
+
+ if ((symfile = fopen(dbgname, "r")) == NULL) {
+ warning("Symbol file %s not found", dbgname);
+ }
+ objfile->auxf2 = symfile;
+
+ if ((minfile = fopen(stbname, "r")) == NULL) {
+ warning("Symbol file %s not found", stbname);
+ }
+ objfile->auxf1 = minfile;
+
+ /* Allocate struct to keep track of the symfile */
+ objfile->sym_stab_info = (PTR)
+ xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info));
+ DBX_SYMFILE_INFO (objfile)->stab_section_info = NULL;
+
+ DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text");
+ if (!DBX_TEXT_SECT (objfile))
+ error ("Can't find .text section in file");
+
+ DBX_SYMBOL_SIZE (objfile) = 0; /* variable size symbol */
+ DBX_SYMCOUNT (objfile) = 0; /* used to be bfd_get_symcount(sym_bfd) */
+ DBX_SYMTAB_OFFSET (objfile) = 0; /* used to be SYMBOL_TABLE_OFFSET */
+}
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+os9k_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+ if (objfile->sym_stab_info != NULL)
+ {
+ mfree (objfile -> md, objfile->sym_stab_info);
+ }
+/*
+ free_header_files ();
+*/
+}
+
+
+struct dbghdr {
+ int sync;
+ short rev;
+ int crc;
+ short os;
+ short cpu;
+};
+
+#define SWAP_DBGHDR(hdrp, abfd) \
+ { \
+ (hdrp)->sync = bfd_get_32(abfd, (unsigned char *)&(hdrp)->sync); \
+ (hdrp)->rev = bfd_get_16(abfd, (unsigned char *)&(hdrp)->rev); \
+ (hdrp)->crc = bfd_get_32(abfd, (unsigned char *)&(hdrp)->crc); \
+ (hdrp)->os = bfd_get_16(abfd, (unsigned char *)&(hdrp)->os); \
+ (hdrp)->cpu = bfd_get_16(abfd, (unsigned char *)&(hdrp)->cpu); \
+ }
+
+#define N_SYM_CMPLR 0
+#define N_SYM_SLINE 1
+#define N_SYM_SYM 2
+#define N_SYM_LBRAC 3
+#define N_SYM_RBRAC 4
+#define N_SYM_SE 5
+
+struct internal_symstruct {
+ short n_type;
+ short n_desc;
+ long n_value;
+ char * n_strx;
+};
+static struct internal_symstruct symbol;
+static struct internal_symstruct *symbuf = &symbol;
+static char strbuf[256];
+
+static int
+fill_sym (dbg_file, abfd)
+ FILE *dbg_file;
+ bfd *abfd;
+{
+short id;
+short si;
+long li;
+int ii;
+
+ int nbytes = fread(&si, sizeof(si), 1, dbg_file);
+ if (nbytes == 0)
+ return 0;
+ if (nbytes < 0)
+ perror_with_name ("reading .dbg file.");
+ symbuf->n_desc = 0;
+ symbuf->n_value = 0;
+ symbuf->n_strx = NULL;
+ symbuf->n_type = bfd_get_16 (abfd, (unsigned char *)&si);
+ symbuf->n_type = 0xf & symbuf->n_type;
+ switch (symbuf->n_type)
+ {
+ case N_SYM_CMPLR:
+ fread(&si, sizeof(si), 1, dbg_file);
+ symbuf->n_desc = bfd_get_16(abfd, (unsigned char *)&si);
+ break;
+ case N_SYM_SLINE:
+ fread(&li, sizeof(li), 1, dbg_file);
+ symbuf->n_value = bfd_get_32(abfd, (unsigned char *)&li);
+ fread(&li, sizeof(li), 1, dbg_file);
+ li = bfd_get_32(abfd, (unsigned char *)&li);
+ symbuf->n_strx = (char *)(li >> 12);
+ symbuf->n_desc = li & 0xfff;
+ break;
+ case N_SYM_SYM:
+ fread(&li, sizeof(li), 1, dbg_file);
+ symbuf->n_value = bfd_get_32(abfd, (unsigned char *)&li);
+ si = 0;
+ do {
+ ii = getc(dbg_file);
+ strbuf[si++] = (char) ii;
+ } while (ii != 0 || si % 2 != 0);
+ symbuf->n_strx = strbuf;
+ break;
+ case N_SYM_LBRAC:
+ fread(&li, sizeof(li), 1, dbg_file);
+ symbuf->n_value = bfd_get_32(abfd, (unsigned char *)&li);
+ break;
+ case N_SYM_RBRAC:
+ fread(&li, sizeof(li), 1, dbg_file);
+ symbuf->n_value = bfd_get_32(abfd, (unsigned char *)&li);
+ break;
+ case N_SYM_SE:
+ break;
+ }
+ return 1;
+}
+
+/* Initializes storage for all of the partial symbols that will be
+ created by read_dbx_symtab and subsidiaries. */
+
+static void
+init_psymbol_list (objfile)
+ struct objfile *objfile;
+{
+ /* Free any previously allocated psymbol lists. */
+ if (objfile -> global_psymbols.list)
+ mfree (objfile -> md, (PTR)objfile -> global_psymbols.list);
+ if (objfile -> static_psymbols.list)
+ mfree (objfile -> md, (PTR)objfile -> static_psymbols.list);
+
+ /* Current best guess is that there are approximately a twentieth
+ of the total symbols (in a debugging file) are global or static
+ oriented symbols */
+ objfile -> global_psymbols.size = DBX_SYMCOUNT (objfile) / 10;
+ objfile -> static_psymbols.size = DBX_SYMCOUNT (objfile) / 10;
+ objfile -> global_psymbols.next = objfile -> global_psymbols.list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, objfile -> global_psymbols.size * sizeof (struct partial_symbol));
+ objfile -> static_psymbols.next = objfile -> static_psymbols.list = (struct partial_symbol *)
+ xmmalloc (objfile -> md, objfile -> static_psymbols.size * sizeof (struct partial_symbol));
+}
+
+/* Given pointers to an a.out symbol table in core containing dbx
+ style data, setup partial_symtab's describing each source file for
+ which debugging information is available.
+ SYMFILE_NAME is the name of the file we are reading from
+ and SECTION_OFFSETS is the set of offsets for the various sections
+ of the file (a set of zeros if the mainline program). */
+
+static void
+read_os9k_psymtab (section_offsets, objfile, text_addr, text_size)
+ struct section_offsets *section_offsets;
+ struct objfile *objfile;
+ CORE_ADDR text_addr;
+ int text_size;
+{
+ register struct internal_symstruct *bufp = 0; /* =0 avoids gcc -Wall glitch*/
+ register char *namestring;
+ int nsl;
+ int past_first_source_file = 0;
+ CORE_ADDR last_o_file_start = 0;
+ struct cleanup *back_to;
+ bfd *abfd;
+ FILE *fp;
+ struct dbghdr hdr;
+
+ /* End of the text segment of the executable file. */
+ static CORE_ADDR end_of_text_addr;
+
+ /* Current partial symtab */
+ static struct partial_symtab *pst = 0;
+
+ /* List of current psymtab's include files */
+ char **psymtab_include_list;
+ int includes_allocated;
+ int includes_used;
+
+ /* Index within current psymtab dependency list */
+ struct partial_symtab **dependency_list;
+ int dependencies_used, dependencies_allocated;
+
+ includes_allocated = 30;
+ includes_used = 0;
+ psymtab_include_list = (char **) alloca (includes_allocated *
+ sizeof (char *));
+
+ dependencies_allocated = 30;
+ dependencies_used = 0;
+ dependency_list =
+ (struct partial_symtab **) alloca (dependencies_allocated *
+ sizeof (struct partial_symtab *));
+
+ last_source_file = NULL;
+
+#ifdef END_OF_TEXT_DEFAULT
+ end_of_text_addr = END_OF_TEXT_DEFAULT;
+#else
+ end_of_text_addr = text_addr + section_offsets->offsets[SECT_OFF_TEXT]
+ + text_size; /* Relocate */
+#endif
+
+ abfd = objfile->obfd;
+ fp = objfile->auxf2;
+
+ fread(&hdr.sync, sizeof(hdr.sync), 1, fp);
+ fread(&hdr.rev, sizeof(hdr.rev), 1, fp);
+ fread(&hdr.crc, sizeof(hdr.crc), 1, fp);
+ fread(&hdr.os, sizeof(hdr.os), 1, fp);
+ fread(&hdr.cpu, sizeof(hdr.cpu), 1, fp);
+ SWAP_DBGHDR(&hdr, abfd);
+
+ symnum = 0;
+ while(1)
+ {
+ int ret;
+ long cursymoffset;
+
+ /* Get the symbol for this run and pull out some info */
+ QUIT; /* allow this to be interruptable */
+ cursymoffset = ftell(objfile->auxf2);
+ ret = fill_sym(objfile->auxf2, abfd);
+ if (ret <= 0) break;
+ else symnum++;
+ bufp = symbuf;
+
+ /* Special case to speed up readin. */
+ if (bufp->n_type == (short)N_SYM_SLINE) continue;
+
+#define CUR_SYMBOL_VALUE bufp->n_value
+ /* partial-stab.h */
+
+ switch (bufp->n_type)
+ {
+ char *p;
+
+ case N_SYM_CMPLR:
+ continue;
+
+ case N_SYM_SE:
+ CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT);
+ if (psymfile_depth == 1 && pst)
+ {
+ os9k_end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum, CUR_SYMBOL_VALUE,
+ dependency_list, dependencies_used);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ psymfile_depth--;
+ continue;
+
+ case N_SYM_SYM: /* Typedef or automatic variable. */
+ namestring = bufp->n_strx;
+ p = (char *) strchr (namestring, ':');
+ if (!p)
+ continue; /* Not a debugging symbol. */
+
+ /* Main processing section for debugging symbols which
+ the initial read through the symbol tables needs to worry
+ about. If we reach this point, the symbol which we are
+ considering is definitely one we are interested in.
+ p must also contain the (valid) index into the namestring
+ which indicates the debugging type symbol. */
+
+ switch (p[1])
+ {
+ case 'S' :
+ {
+ unsigned long valu;
+ enum language tmp_language;
+
+ valu = CUR_SYMBOL_VALUE +
+ ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ past_first_source_file = 1;
+
+ if (psymfile_depth == 0) {
+ if (!pst)
+ pst = os9k_start_psymtab (objfile, section_offsets,
+ namestring, valu,
+ cursymoffset,
+ symnum-1,
+ objfile -> global_psymbols.next,
+ objfile -> static_psymbols.next);
+ } else { /* this is a include file */
+ tmp_language = deduce_language_from_filename (namestring);
+ if (tmp_language != language_unknown
+ && (tmp_language != language_c
+ || psymtab_language != language_cplus))
+ psymtab_language = tmp_language;
+
+/*
+ if (pst && STREQ (namestring, pst->filename))
+ continue;
+ {
+ register int i;
+ for (i = 0; i < includes_used; i++)
+ if (STREQ (namestring, psymtab_include_list[i]))
+ {
+ i = -1;
+ break;
+ }
+ if (i == -1)
+ continue;
+ }
+*/
+
+ psymtab_include_list[includes_used++] = namestring;
+ if (includes_used >= includes_allocated)
+ {
+ char **orig = psymtab_include_list;
+
+ psymtab_include_list = (char **)
+ alloca ((includes_allocated *= 2) * sizeof (char *));
+ memcpy ((PTR)psymtab_include_list, (PTR)orig,
+ includes_used * sizeof (char *));
+ }
+
+ }
+ psymfile_depth++;
+ continue;
+ }
+
+ case 'v':
+ ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_STATIC,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+ case 'V':
+ ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_STATIC,
+ objfile->global_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ case 'T':
+ if (p != namestring) /* a name is there, not just :T... */
+ {
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ STRUCT_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ if (p[2] == 't')
+ {
+ /* Also a typedef with the same name. */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE, psymtab_language,
+ objfile);
+ p += 1;
+ }
+ /* The semantics of C++ state that "struct foo { ... }"
+ also defines a typedef for "foo". Unfortuantely, cfront
+ never makes the typedef when translating from C++ to C.
+ We make the typedef here so that "ptype foo" works as
+ expected for cfront translated code. */
+ else if (psymtab_language == language_cplus)
+ {
+ /* Also a typedef with the same name. */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE, psymtab_language,
+ objfile);
+ }
+ }
+ goto check_enum;
+ case 't':
+ if (p != namestring) /* a name is there, not just :T... */
+ {
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ }
+ check_enum:
+ /* If this is an enumerated type, we need to
+ add all the enum constants to the partial symbol
+ table. This does not cover enums without names, e.g.
+ "enum {a, b} c;" in C, but fortunately those are
+ rare. There is no way for GDB to find those from the
+ enum type without spending too much time on it. Thus
+ to solve this problem, the compiler needs to put out the
+ enum in a nameless type. GCC2 does this. */
+
+ /* We are looking for something of the form
+ <name> ":" ("t" | "T") [<number> "="] "e" <size>
+ {<constant> ":" <value> ","} ";". */
+
+ /* Skip over the colon and the 't' or 'T'. */
+ p += 2;
+ /* This type may be given a number. Also, numbers can come
+ in pairs like (0,26). Skip over it. */
+ while ((*p >= '0' && *p <= '9')
+ || *p == '(' || *p == ',' || *p == ')'
+ || *p == '=')
+ p++;
+
+ if (*p++ == 'e')
+ {
+ /* We have found an enumerated type. skip size */
+ while (*p >= '0' && *p <= '9') p++;
+ /* According to comments in read_enum_type
+ a comma could end it instead of a semicolon.
+ I don't know where that happens.
+ Accept either. */
+ while (*p && *p != ';' && *p != ',')
+ {
+ char *q;
+
+ /* Check for and handle cretinous dbx symbol name
+ continuation!
+ if (*p == '\\')
+ p = next_symbol_text ();
+ */
+
+ /* Point to the character after the name
+ of the enum constant. */
+ for (q = p; *q && *q != ':'; q++)
+ ;
+ /* Note that the value doesn't matter for
+ enum constants in psymtabs, just in symtabs. */
+ ADD_PSYMBOL_TO_LIST (p, q - p,
+ VAR_NAMESPACE, LOC_CONST,
+ objfile->static_psymbols, 0,
+ psymtab_language, objfile);
+ /* Point past the name. */
+ p = q;
+ /* Skip over the value. */
+ while (*p && *p != ',')
+ p++;
+ /* Advance past the comma. */
+ if (*p)
+ p++;
+ }
+ }
+ continue;
+ case 'c':
+ /* Constant, e.g. from "const" in Pascal. */
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_CONST,
+ objfile->static_psymbols, CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ case 'f':
+ CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT);
+ if (pst && pst->textlow == 0)
+ pst->textlow = CUR_SYMBOL_VALUE;
+
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile->static_psymbols, CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ case 'F':
+ CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT);
+ if (pst && pst->textlow == 0)
+ pst->textlow = CUR_SYMBOL_VALUE;
+
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_BLOCK,
+ objfile->global_psymbols, CUR_SYMBOL_VALUE,
+ psymtab_language, objfile);
+ continue;
+
+ case 'p':
+ case 'l':
+ continue;
+
+ case ':':
+ /* It is a C++ nested symbol. We don't need to record it
+ (I don't think); if we try to look up foo::bar::baz,
+ then symbols for the symtab containing foo should get
+ read in, I think. */
+ /* Someone says sun cc puts out symbols like
+ /foo/baz/maclib::/usr/local/bin/maclib,
+ which would get here with a symbol type of ':'. */
+ continue;
+
+ default:
+ /* Unexpected symbol descriptor. The second and subsequent stabs
+ of a continued stab can show up here. The question is
+ whether they ever can mimic a normal stab--it would be
+ nice if not, since we certainly don't want to spend the
+ time searching to the end of every string looking for
+ a backslash. */
+
+ complain (&unknown_symchar_complaint, p[1]);
+ continue;
+ }
+
+ case N_SYM_RBRAC:
+ CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT);
+#ifdef HANDLE_RBRAC
+ HANDLE_RBRAC(CUR_SYMBOL_VALUE);
+ continue;
+#endif
+ case N_SYM_LBRAC:
+ continue;
+
+ default:
+ /* If we haven't found it yet, ignore it. It's probably some
+ new type we don't know about yet. */
+ complain (&unknown_symtype_complaint,
+ local_hex_string ((unsigned long) bufp->n_type));
+ continue;
+ }
+ }
+
+ DBX_SYMCOUNT (objfile) = symnum;
+
+ /* If there's stuff to be cleaned up, clean it up. */
+ if (DBX_SYMCOUNT (objfile) > 0
+/*FIXME, does this have a bug at start address 0? */
+ && last_o_file_start
+ && objfile -> ei.entry_point < bufp->n_value
+ && objfile -> ei.entry_point >= last_o_file_start)
+ {
+ objfile -> ei.entry_file_lowpc = last_o_file_start;
+ objfile -> ei.entry_file_highpc = bufp->n_value;
+ }
+
+ if (pst)
+ {
+ os9k_end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum, end_of_text_addr,
+ dependency_list, dependencies_used);
+ }
+/*
+ do_cleanups (back_to);
+*/
+}
+
+/* Allocate and partially fill a partial symtab. It will be
+ completely filled at the end of the symbol list.
+
+ SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR
+ is the address relative to which its symbols are (incremental) or 0
+ (normal). */
+
+
+static struct partial_symtab *
+os9k_start_psymtab (objfile, section_offsets,
+ filename, textlow, ldsymoff,ldsymcnt, global_syms, static_syms)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ char *filename;
+ CORE_ADDR textlow;
+ int ldsymoff;
+ int ldsymcnt;
+ struct partial_symbol *global_syms;
+ struct partial_symbol *static_syms;
+{
+ struct partial_symtab *result =
+ start_psymtab_common(objfile, section_offsets,
+ filename, textlow, global_syms, static_syms);
+
+ result->read_symtab_private = (char *)
+ obstack_alloc (&objfile -> psymbol_obstack, sizeof (struct symloc));
+
+ LDSYMOFF(result) = ldsymoff;
+ LDSYMCNT(result) = ldsymcnt;
+ result->read_symtab = os9k_psymtab_to_symtab;
+
+ /* Deduce the source language from the filename for this psymtab. */
+ psymtab_language = deduce_language_from_filename (filename);
+ return result;
+}
+
+/* Close off the current usage of PST.
+ Returns PST or NULL if the partial symtab was empty and thrown away.
+ FIXME: List variables and peculiarities of same. */
+
+static struct partial_symtab *
+os9k_end_psymtab (pst, include_list, num_includes, capping_symbol_cnt,
+ capping_text, dependency_list, number_dependencies)
+ struct partial_symtab *pst;
+ char **include_list;
+ int num_includes;
+ int capping_symbol_cnt;
+ CORE_ADDR capping_text;
+ struct partial_symtab **dependency_list;
+ int number_dependencies;
+/* struct partial_symbol *capping_global, *capping_static;*/
+{
+ int i;
+ struct partial_symtab *p1;
+ struct objfile *objfile = pst -> objfile;
+
+ if (capping_symbol_cnt != -1)
+ LDSYMCNT(pst) = capping_symbol_cnt - LDSYMCNT(pst);
+
+ /* Under Solaris, the N_SO symbols always have a value of 0,
+ instead of the usual address of the .o file. Therefore,
+ we have to do some tricks to fill in texthigh and textlow.
+ The first trick is in partial-stab.h: if we see a static
+ or global function, and the textlow for the current pst
+ is still 0, then we use that function's address for
+ the textlow of the pst.
+
+ Now, to fill in texthigh, we remember the last function seen
+ in the .o file (also in partial-stab.h). Also, there's a hack in
+ bfd/elf.c and gdb/elfread.c to pass the ELF st_size field
+ to here via the misc_info field. Therefore, we can fill in
+ a reliable texthigh by taking the address plus size of the
+ last function in the file.
+
+ Unfortunately, that does not cover the case where the last function
+ in the file is static. See the paragraph below for more comments
+ on this situation.
+
+ Finally, if we have a valid textlow for the current file, we run
+ down the partial_symtab_list filling in previous texthighs that
+ are still unknown. */
+
+ if (pst->texthigh == 0 && last_function_name) {
+ char *p;
+ int n;
+ struct minimal_symbol *minsym;
+
+ p = strchr (last_function_name, ':');
+ if (p == NULL)
+ p = last_function_name;
+ n = p - last_function_name;
+ p = alloca (n + 1);
+ strncpy (p, last_function_name, n);
+ p[n] = 0;
+
+ minsym = lookup_minimal_symbol (p, objfile);
+
+ if (minsym) {
+ pst->texthigh = SYMBOL_VALUE_ADDRESS(minsym)+(long)MSYMBOL_INFO(minsym);
+ } else {
+ /* This file ends with a static function, and it's
+ difficult to imagine how hard it would be to track down
+ the elf symbol. Luckily, most of the time no one will notice,
+ since the next file will likely be compiled with -g, so
+ the code below will copy the first fuction's start address
+ back to our texthigh variable. (Also, if this file is the
+ last one in a dynamically linked program, texthigh already
+ has the right value.) If the next file isn't compiled
+ with -g, then the last function in this file winds up owning
+ all of the text space up to the next -g file, or the end (minus
+ shared libraries). This only matters for single stepping,
+ and even then it will still work, except that it will single
+ step through all of the covered functions, instead of setting
+ breakpoints around them as it usualy does. This makes it
+ pretty slow, but at least it doesn't fail.
+
+ We can fix this with a fairly big change to bfd, but we need
+ to coordinate better with Cygnus if we want to do that. FIXME. */
+ }
+ last_function_name = NULL;
+ }
+
+ /* this test will be true if the last .o file is only data */
+ if (pst->textlow == 0)
+ pst->textlow = pst->texthigh;
+
+ /* If we know our own starting text address, then walk through all other
+ psymtabs for this objfile, and if any didn't know their ending text
+ address, set it to our starting address. Take care to not set our
+ own ending address to our starting address, nor to set addresses on
+ `dependency' files that have both textlow and texthigh zero. */
+ if (pst->textlow) {
+ ALL_OBJFILE_PSYMTABS (objfile, p1) {
+ if (p1->texthigh == 0 && p1->textlow != 0 && p1 != pst) {
+ p1->texthigh = pst->textlow;
+ /* if this file has only data, then make textlow match texthigh */
+ if (p1->textlow == 0)
+ p1->textlow = p1->texthigh;
+ }
+ }
+ }
+
+ /* End of kludge for patching Solaris textlow and texthigh. */
+
+ pst->n_global_syms =
+ objfile->global_psymbols.next - (objfile->global_psymbols.list + pst->globals_offset);
+ pst->n_static_syms =
+ objfile->static_psymbols.next - (objfile->static_psymbols.list + pst->statics_offset);
+
+ pst->number_of_dependencies = number_dependencies;
+ if (number_dependencies)
+ {
+ pst->dependencies = (struct partial_symtab **)
+ obstack_alloc (&objfile->psymbol_obstack,
+ number_dependencies * sizeof (struct partial_symtab *));
+ memcpy (pst->dependencies, dependency_list,
+ number_dependencies * sizeof (struct partial_symtab *));
+ }
+ else
+ pst->dependencies = 0;
+
+ for (i = 0; i < num_includes; i++)
+ {
+ struct partial_symtab *subpst =
+ allocate_psymtab (include_list[i], objfile);
+
+ subpst->section_offsets = pst->section_offsets;
+ subpst->read_symtab_private =
+ (char *) obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct symloc));
+ LDSYMOFF(subpst) =
+ LDSYMCNT(subpst) =
+ subpst->textlow =
+ subpst->texthigh = 0;
+
+ /* We could save slight bits of space by only making one of these,
+ shared by the entire set of include files. FIXME-someday. */
+ subpst->dependencies = (struct partial_symtab **)
+ obstack_alloc (&objfile->psymbol_obstack,
+ sizeof (struct partial_symtab *));
+ subpst->dependencies[0] = pst;
+ subpst->number_of_dependencies = 1;
+
+ subpst->globals_offset =
+ subpst->n_global_syms =
+ subpst->statics_offset =
+ subpst->n_static_syms = 0;
+
+ subpst->readin = 0;
+ subpst->symtab = 0;
+ subpst->read_symtab = pst->read_symtab;
+ }
+
+ sort_pst_symbols (pst);
+
+ /* If there is already a psymtab or symtab for a file of this name,
+ remove it.
+ (If there is a symtab, more drastic things also happen.)
+ This happens in VxWorks. */
+ free_named_symtabs (pst->filename);
+
+ if (num_includes == 0
+ && number_dependencies == 0
+ && pst->n_global_syms == 0
+ && pst->n_static_syms == 0) {
+ /* Throw away this psymtab, it's empty. We can't deallocate it, since
+ it is on the obstack, but we can forget to chain it on the list. */
+ struct partial_symtab *prev_pst;
+
+ /* First, snip it out of the psymtab chain */
+
+ if (pst->objfile->psymtabs == pst)
+ pst->objfile->psymtabs = pst->next;
+ else
+ for (prev_pst = pst->objfile->psymtabs; prev_pst; prev_pst = pst->next)
+ if (prev_pst->next == pst)
+ prev_pst->next = pst->next;
+
+ /* Next, put it on a free list for recycling */
+ pst->next = pst->objfile->free_psymtabs;
+ pst->objfile->free_psymtabs = pst;
+
+ /* Indicate that psymtab was thrown away. */
+ pst = (struct partial_symtab *)NULL;
+ }
+ return pst;
+}
+
+static void
+os9k_psymtab_to_symtab_1 (pst)
+ struct partial_symtab *pst;
+{
+ struct cleanup *old_chain;
+ int i;
+
+ if (!pst)
+ return;
+
+ if (pst->readin)
+ {
+ fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in. Shouldn't happen.\n",
+ pst->filename);
+ return;
+ }
+
+ /* Read in all partial symtabs on which this one is dependent */
+ for (i = 0; i < pst->number_of_dependencies; i++)
+ if (!pst->dependencies[i]->readin)
+ {
+ /* Inform about additional files that need to be read in. */
+ if (info_verbose)
+ {
+ fputs_filtered (" ", gdb_stdout);
+ wrap_here ("");
+ fputs_filtered ("and ", gdb_stdout);
+ wrap_here ("");
+ printf_filtered ("%s...", pst->dependencies[i]->filename);
+ wrap_here (""); /* Flush output */
+ gdb_flush (gdb_stdout);
+ }
+ os9k_psymtab_to_symtab_1 (pst->dependencies[i]);
+ }
+
+ if (LDSYMCNT(pst)) /* Otherwise it's a dummy */
+ {
+ /* Init stuff necessary for reading in symbols */
+ stabsread_init ();
+ buildsym_init ();
+ old_chain = make_cleanup (really_free_pendings, 0);
+
+ /* Read in this file's symbols */
+ os9k_read_ofile_symtab (pst);
+ sort_symtab_syms (pst->symtab);
+ do_cleanups (old_chain);
+ }
+
+ pst->readin = 1;
+}
+
+/* Read in all of the symbols for a given psymtab for real.
+ Be verbose about it if the user wants that. */
+
+static void
+os9k_psymtab_to_symtab (pst)
+ struct partial_symtab *pst;
+{
+ bfd *sym_bfd;
+
+ if (!pst)
+ return;
+
+ if (pst->readin)
+ {
+ fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in. Shouldn't happen.\n",
+ pst->filename);
+ return;
+ }
+
+ if (LDSYMCNT(pst) || pst->number_of_dependencies)
+ {
+ /* Print the message now, before reading the string table,
+ to avoid disconcerting pauses. */
+ if (info_verbose)
+ {
+ printf_filtered ("Reading in symbols for %s...", pst->filename);
+ gdb_flush (gdb_stdout);
+ }
+
+ sym_bfd = pst->objfile->obfd;
+ os9k_psymtab_to_symtab_1 (pst);
+
+ /* Match with global symbols. This only needs to be done once,
+ after all of the symtabs and dependencies have been read in. */
+ scan_file_globals (pst->objfile);
+
+ /* Finish up the debug error message. */
+ if (info_verbose)
+ printf_filtered ("done.\n");
+ }
+}
+
+/* Read in a defined section of a specific object file's symbols. */
+static void
+os9k_read_ofile_symtab (pst)
+ struct partial_symtab *pst;
+{
+ register struct internal_symstruct *bufp;
+ unsigned char type;
+ unsigned max_symnum;
+ register bfd *abfd;
+ struct objfile *objfile;
+ int sym_offset; /* Offset to start of symbols to read */
+ CORE_ADDR text_offset; /* Start of text segment for symbols */
+ int text_size; /* Size of text segment for symbols */
+ struct section_offsets *section_offsets;
+ FILE *dbg_file;
+
+ objfile = pst->objfile;
+ sym_offset = LDSYMOFF(pst);
+ max_symnum = LDSYMCNT(pst);
+ text_offset = pst->textlow;
+ text_size = pst->texthigh - pst->textlow;
+ section_offsets = pst->section_offsets;
+
+ current_objfile = objfile;
+ subfile_stack = NULL;
+ last_source_file = NULL;
+
+ abfd = objfile->obfd;
+ dbg_file = objfile->auxf2;
+
+#if 0
+ /* It is necessary to actually read one symbol *before* the start
+ of this symtab's symbols, because the GCC_COMPILED_FLAG_SYMBOL
+ occurs before the N_SO symbol.
+ Detecting this in read_dbx_symtab
+ would slow down initial readin, so we look for it here instead. */
+ if (!processing_acc_compilation && sym_offset >= (int)symbol_size)
+ {
+ fseek (objefile->auxf2, sym_offset, SEEK_CUR);
+ fill_sym(objfile->auxf2, abfd);
+ bufp = symbuf;
+
+ processing_gcc_compilation = 0;
+ if (bufp->n_type == N_TEXT)
+ {
+ if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 1;
+ else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 2;
+ }
+
+ /* Try to select a C++ demangling based on the compilation unit
+ producer. */
+
+ if (processing_gcc_compilation)
+ {
+ if (AUTO_DEMANGLING)
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+ }
+ }
+ else
+ {
+ /* The N_SO starting this symtab is the first symbol, so we
+ better not check the symbol before it. I'm not this can
+ happen, but it doesn't hurt to check for it. */
+ bfd_seek (symfile_bfd, sym_offset, SEEK_CUR);
+ processing_gcc_compilation = 0;
+ }
+#endif 0
+
+ fseek(dbg_file, (long)sym_offset, 0);
+/*
+ if (bufp->n_type != (unsigned char)N_SYM_SYM)
+ error("First symbol in segment of executable not a source symbol");
+*/
+
+ for (symnum = 0; symnum < max_symnum; symnum++)
+ {
+ QUIT; /* Allow this to be interruptable */
+ fill_sym(dbg_file, abfd);
+ bufp = symbuf;
+ type = bufp->n_type;
+
+ os9k_process_one_symbol (type, bufp->n_desc, bufp->n_value,
+ bufp->n_strx, section_offsets, objfile);
+
+ /* We skip checking for a new .o or -l file; that should never
+ happen in this routine. */
+#if 0
+ else if (type == N_TEXT)
+ {
+ /* I don't think this code will ever be executed, because
+ the GCC_COMPILED_FLAG_SYMBOL usually is right before
+ the N_SO symbol which starts this source file.
+ However, there is no reason not to accept
+ the GCC_COMPILED_FLAG_SYMBOL anywhere. */
+
+ if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 1;
+ else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 2;
+
+ if (AUTO_DEMANGLING)
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+ }
+ else if (type & N_EXT || type == (unsigned char)N_TEXT
+ || type == (unsigned char)N_NBTEXT
+ ) {
+ /* Global symbol: see if we came across a dbx defintion for
+ a corresponding symbol. If so, store the value. Remove
+ syms from the chain when their values are stored, but
+ search the whole chain, as there may be several syms from
+ different files with the same name. */
+ /* This is probably not true. Since the files will be read
+ in one at a time, each reference to a global symbol will
+ be satisfied in each file as it appears. So we skip this
+ section. */
+ ;
+ }
+#endif 0
+ }
+
+ current_objfile = NULL;
+
+ /* In a Solaris elf file, this variable, which comes from the
+ value of the N_SO symbol, will still be 0. Luckily, text_offset,
+ which comes from pst->textlow is correct. */
+ if (last_source_start_addr == 0)
+ last_source_start_addr = text_offset;
+ pst->symtab = end_symtab (text_offset + text_size, 0, 0, objfile,
+ SECT_OFF_TEXT);
+ end_stabs ();
+}
+
+
+/* This handles a single symbol from the symbol-file, building symbols
+ into a GDB symtab. It takes these arguments and an implicit argument.
+
+ TYPE is the type field of the ".stab" symbol entry.
+ DESC is the desc field of the ".stab" entry.
+ VALU is the value field of the ".stab" entry.
+ NAME is the symbol name, in our address space.
+ SECTION_OFFSETS is a set of amounts by which the sections of this object
+ file were relocated when it was loaded into memory.
+ All symbols that refer
+ to memory locations need to be offset by these amounts.
+ OBJFILE is the object file from which we are reading symbols.
+ It is used in end_symtab. */
+
+static void
+os9k_process_one_symbol (type, desc, valu, name, section_offsets, objfile)
+ int type, desc;
+ CORE_ADDR valu;
+ char *name;
+ struct section_offsets *section_offsets;
+ struct objfile *objfile;
+{
+ register struct context_stack *new;
+ /* The stab type used for the definition of the last function.
+ N_STSYM or N_GSYM for SunOS4 acc; N_FUN for other compilers. */
+ static int function_stab_type = 0;
+
+#if 0
+ /* Something is wrong if we see real data before
+ seeing a source file name. */
+ if (last_source_file == NULL && type != (unsigned char)N_SO)
+ {
+ /* Ignore any symbols which appear before an N_SO symbol. Currently
+ no one puts symbols there, but we should deal gracefully with the
+ case. A complain()t might be in order (if !IGNORE_SYMBOL (type)),
+ but this should not be an error (). */
+ return;
+ }
+#endif 0
+
+ switch (type)
+ {
+ case N_SYM_LBRAC:
+ /* On most machines, the block addresses are relative to the
+ N_SO, the linker did not relocate them (sigh). */
+ valu += last_source_start_addr;
+ new = push_context (desc, valu);
+ break;
+
+ case N_SYM_RBRAC:
+ valu += last_source_start_addr;
+ new = pop_context();
+
+#if !defined (VARIABLES_INSIDE_BLOCK)
+#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) 1
+#endif
+
+ if (!VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))
+ local_symbols = new->locals;
+
+ if (context_stack_depth > 1)
+ {
+ /* This is not the outermost LBRAC...RBRAC pair in the function,
+ its local symbols preceded it, and are the ones just recovered
+ from the context stack. Define the block for them (but don't
+ bother if the block contains no symbols. Should we complain
+ on blocks without symbols? I can't think of any useful purpose
+ for them). */
+ if (local_symbols != NULL)
+ {
+ /* Muzzle a compiler bug that makes end < start. (which
+ compilers? Is this ever harmful?). */
+ if (new->start_addr > valu)
+ {
+ complain (&lbrac_rbrac_complaint);
+ new->start_addr = valu;
+ }
+ /* Make a block for the local symbols within. */
+ finish_block (0, &local_symbols, new->old_blocks,
+ new->start_addr, valu, objfile);
+ }
+ }
+ else
+ {
+ if (context_stack_depth == 0)
+ {
+ within_function = 0;
+ /* Make a block for the local symbols within. */
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr, valu, objfile);
+ }
+ else
+ {
+ /* attach local_symbols to the end of new->locals */
+ if (!new->locals) new->locals = local_symbols;
+ else {
+ struct pending *p;
+
+ p = new->locals;
+ while (p->next) p = p->next;
+ p->next = local_symbols;
+ }
+ }
+ }
+
+ if (VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))
+ /* Now pop locals of block just finished. */
+ local_symbols = new->locals;
+ break;
+
+
+ case N_SYM_SLINE:
+ /* This type of "symbol" really just records
+ one line-number -- core-address correspondence.
+ Enter it in the line list for this symbol table. */
+ /* Relocate for dynamic loading and for ELF acc fn-relative syms. */
+ valu += last_source_start_addr;
+ record_line (current_subfile, (int)name, valu);
+ break;
+
+ /* The following symbol types need to have the appropriate offset added
+ to their value; then we process symbol definitions in the name. */
+ case N_SYM_SYM:
+
+ if (name)
+ {
+ char deftype;
+ char *dirn, *n;
+ char *p = strchr (name, ':');
+ if (p == NULL)
+ deftype = '\0';
+ else
+ deftype = p[1];
+
+
+ switch (deftype)
+ {
+ case 'S':
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ n = strrchr(name, '/');
+ if (n != NULL) {
+ *n = '\0';
+ n++;
+ dirn = name;
+ } else {
+ n = name;
+ dirn = NULL;
+ }
+ *p = '\0';
+ if (symfile_depth++ == 0) {
+ if (last_source_file) {
+ end_symtab (valu, 0, 0, objfile, SECT_OFF_TEXT);
+ end_stabs ();
+ }
+ start_stabs ();
+ start_symtab (n, dirn, valu);
+ } else {
+ push_subfile();
+ start_subfile (n, dirn!=NULL ? dirn : current_subfile->dirname);
+ }
+ break;
+
+ case 'f':
+ case 'F':
+ valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+ function_stab_type = type;
+
+ within_function = 1;
+ new = push_context (0, valu);
+ new->name = os9k_define_symbol (valu, name, desc, type, objfile);
+ break;
+
+ case 'V':
+ case 'v':
+ valu += ANOFFSET (section_offsets, SECT_OFF_DATA);
+ os9k_define_symbol (valu, name, desc, type, objfile);
+ break;
+
+ default:
+ os9k_define_symbol (valu, name, desc, type, objfile);
+ break;
+ }
+ }
+ break;
+
+ case N_SYM_SE:
+ if (--symfile_depth != 0)
+ start_subfile(pop_subfile(), current_subfile->dirname);
+ break;
+
+ default:
+ complain (&unknown_symtype_complaint,
+ local_hex_string((unsigned long) type));
+ /* FALLTHROUGH */
+ break;
+
+ case N_SYM_CMPLR:
+ break;
+ }
+ previous_stab_code = type;
+}
+
+/* Parse the user's idea of an offset for dynamic linking, into our idea
+ of how to represent it for fast symbol reading. */
+
+static struct section_offsets *
+os9k_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ objfile->num_sections = SECT_OFF_MAX;
+ section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile -> psymbol_obstack,
+ sizeof (struct section_offsets)
+ + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ ANOFFSET (section_offsets, i) = addr;
+
+ return section_offsets;
+}
+
+static struct sym_fns os9k_sym_fns =
+{
+ bfd_target_os9k_flavour,
+ os9k_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ os9k_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ os9k_symfile_read, /* sym_read: read a symbol file into symtab */
+ os9k_symfile_finish, /* sym_finish: finished with file, cleanup */
+ os9k_symfile_offsets, /* sym_offsets: parse user's offsets to internal form*/
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_os9kread ()
+{
+ add_symtab_fns(&os9k_sym_fns);
+}
diff --git a/gdb/os9kstab.c b/gdb/os9kstab.c
new file mode 100644
index 0000000..828ac8f
--- /dev/null
+++ b/gdb/os9kstab.c
@@ -0,0 +1,2024 @@
+/* Support routines for decoding "stabs" debugging information format.
+ Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993
+ Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Support routines for reading and decoding debugging information in
+ the "stabs" format. This format is used with many systems that use
+ the a.out object file format, as well as some systems that use
+ COFF or ELF where the stabs data is placed in a special section.
+ Avoid placing any object file format specific code in this file. */
+
+#include "defs.h"
+#include "bfd.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "aout/stab_gnu.h" /* We always use GNU stabs, not native */
+#include "buildsym.h"
+#include "complaints.h"
+#include "demangle.h"
+
+#include <ctype.h>
+
+/* Ask stabsread.h to define the vars it normally declares `extern'. */
+#define EXTERN /**/
+#include "stabsread.h" /* Our own declarations */
+#undef EXTERN
+
+/* The routines that read and process a complete stabs for a C struct or
+ C++ class pass lists of data member fields and lists of member function
+ fields in an instance of a field_info structure, as defined below.
+ This is part of some reorganization of low level C++ support and is
+ expected to eventually go away... (FIXME) */
+
+struct field_info
+{
+ struct nextfield
+ {
+ struct nextfield *next;
+
+ /* This is the raw visibility from the stab. It is not checked
+ for being one of the visibilities we recognize, so code which
+ examines this field better be able to deal. */
+ int visibility;
+
+ struct field field;
+ } *list;
+ struct next_fnfieldlist
+ {
+ struct next_fnfieldlist *next;
+ struct fn_fieldlist fn_fieldlist;
+ } *fnlist;
+};
+
+static struct type *
+dbx_alloc_type PARAMS ((int [2], struct objfile *));
+
+static long read_huge_number PARAMS ((char **, int, int *));
+
+static struct type *error_type PARAMS ((char **));
+
+static int
+read_type_number PARAMS ((char **, int *));
+
+static struct type *
+read_range_type PARAMS ((char **, int [2], struct objfile *));
+
+static struct type *
+os9k_read_type PARAMS ((char **, struct objfile *));
+
+static struct type *
+os9k_read_enum_type PARAMS ((char **, struct type *, struct objfile *));
+
+static int
+read_struct_fields PARAMS ((struct field_info *, char **, struct type *,
+ struct objfile *));
+
+static int
+attach_fields_to_type PARAMS ((struct field_info *, struct type *,
+ struct objfile *));
+
+static struct type *
+os9k_read_array_type PARAMS ((char **, struct type *, struct objfile *));
+
+extern struct complaint error_type_complaint;
+extern struct complaint stabs_general_complaint;
+extern struct complaint range_type_base_complaint;
+extern struct complaint reg_value_complaint;
+
+/* Define this as 1 if a pcc declaration of a char or short argument
+ gives the correct address. Otherwise assume pcc gives the
+ address of the corresponding int, which is not the same on a
+ big-endian machine. */
+
+#ifndef BELIEVE_PCC_PROMOTION
+#define BELIEVE_PCC_PROMOTION 0
+#endif
+
+/* Make a list of forward references which haven't been defined. */
+
+static struct type **undef_types;
+static int undef_types_allocated;
+static int undef_types_length;
+
+/* Check for and handle cretinous stabs symbol name continuation! */
+#define STABS_CONTINUE(pp) \
+ do { \
+ if (**(pp) == '\\') *(pp) = next_symbol_text (); \
+ } while (0)
+
+
+static struct type **init_type_vector[] = {
+ 0,
+ &builtin_type_int,
+ &builtin_type_char,
+ &builtin_type_long,
+ &builtin_type_short,
+ &builtin_type_unsigned_char,
+ &builtin_type_unsigned_short,
+ &builtin_type_unsigned_long,
+ &builtin_type_unsigned_int,
+ &builtin_type_float,
+ &builtin_type_double,
+ &builtin_type_void,
+ &builtin_type_long_double
+};
+
+static void
+os9k_init_type_vector(tv)
+ struct type **tv;
+{
+ int i;
+ for (i=0; i<sizeof(init_type_vector)/sizeof(struct type **); i++)
+ tv[i] = (init_type_vector[i] == 0 ? 0 : *(init_type_vector[i]));
+}
+
+/* Look up a dbx type-number pair. Return the address of the slot
+ where the type for that number-pair is stored.
+ The number-pair is in TYPENUMS.
+
+ This can be used for finding the type associated with that pair
+ or for associating a new type with the pair. */
+
+static struct type **
+dbx_lookup_type (typenums)
+ int typenums[2];
+{
+ register int filenum = typenums[0];
+ register int index = typenums[1];
+ unsigned old_len;
+ register int real_filenum;
+ register struct header_file *f;
+ int f_orig_length;
+
+ if (filenum == -1) /* -1,-1 is for temporary types. */
+ return 0;
+
+ if (filenum < 0 || filenum >= n_this_object_header_files)
+ {
+ static struct complaint msg = {"\
+Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.",
+ 0, 0};
+ complain (&msg, filenum, index, symnum);
+ goto error_return;
+ }
+
+ if (filenum == 0)
+ {
+ /* Type is defined outside of header files.
+ Find it in this object file's type vector. */
+ if (index >= type_vector_length)
+ {
+ old_len = type_vector_length;
+ if (old_len == 0)
+ {
+ type_vector_length = INITIAL_TYPE_VECTOR_LENGTH;
+ type_vector = (struct type **)
+ malloc (type_vector_length * sizeof (struct type *));
+ }
+ while (index >= type_vector_length)
+ {
+ type_vector_length *= 2;
+ }
+ type_vector = (struct type **)
+ xrealloc ((char *) type_vector,
+ (type_vector_length * sizeof (struct type *)));
+ memset (&type_vector[old_len], 0,
+ (type_vector_length - old_len) * sizeof (struct type *));
+ os9k_init_type_vector(type_vector);
+ }
+ return (&type_vector[index]);
+ }
+ else
+ {
+ real_filenum = this_object_header_files[filenum];
+
+ if (real_filenum >= n_header_files)
+ {
+ struct type *temp_type;
+ struct type **temp_type_p;
+
+ warning ("GDB internal error: bad real_filenum");
+
+ error_return:
+ temp_type = init_type (TYPE_CODE_ERROR, 0, 0, NULL, NULL);
+ temp_type_p = (struct type **) xmalloc (sizeof (struct type *));
+ *temp_type_p = temp_type;
+ return temp_type_p;
+ }
+
+ f = &header_files[real_filenum];
+
+ f_orig_length = f->length;
+ if (index >= f_orig_length)
+ {
+ while (index >= f->length)
+ {
+ f->length *= 2;
+ }
+ f->vector = (struct type **)
+ xrealloc ((char *) f->vector, f->length * sizeof (struct type *));
+ memset (&f->vector[f_orig_length], 0,
+ (f->length - f_orig_length) * sizeof (struct type *));
+ }
+ return (&f->vector[index]);
+ }
+}
+
+/* Make sure there is a type allocated for type numbers TYPENUMS
+ and return the type object.
+ This can create an empty (zeroed) type object.
+ TYPENUMS may be (-1, -1) to return a new type object that is not
+ put into the type vector, and so may not be referred to by number. */
+
+static struct type *
+dbx_alloc_type (typenums, objfile)
+ int typenums[2];
+ struct objfile *objfile;
+{
+ register struct type **type_addr;
+
+ if (typenums[0] == -1)
+ {
+ return (alloc_type (objfile));
+ }
+
+ type_addr = dbx_lookup_type (typenums);
+
+ /* If we are referring to a type not known at all yet,
+ allocate an empty type for it.
+ We will fill it in later if we find out how. */
+ if (*type_addr == 0)
+ {
+ *type_addr = alloc_type (objfile);
+ }
+
+ return (*type_addr);
+}
+
+
+/* Read a number by which a type is referred to in dbx data,
+ or perhaps read a pair (FILENUM, TYPENUM) in parentheses.
+ Just a single number N is equivalent to (0,N).
+ Return the two numbers by storing them in the vector TYPENUMS.
+ TYPENUMS will then be used as an argument to dbx_lookup_type.
+
+ Returns 0 for success, -1 for error. */
+
+static int
+read_type_number (pp, typenums)
+ register char **pp;
+ register int *typenums;
+{
+ int nbits;
+ if (**pp == '(')
+ {
+ (*pp)++;
+ typenums[0] = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0) return -1;
+ typenums[1] = read_huge_number (pp, ')', &nbits);
+ if (nbits != 0) return -1;
+ }
+ else
+ {
+ typenums[0] = 0;
+ typenums[1] = read_huge_number (pp, 0, &nbits);
+ if (nbits != 0) return -1;
+ }
+ return 0;
+}
+
+
+/* Skip rest of this symbol and return an error type.
+
+ General notes on error recovery: error_type always skips to the
+ end of the symbol (modulo cretinous dbx symbol name continuation).
+ Thus code like this:
+
+ if (*(*pp)++ != ';')
+ return error_type (pp);
+
+ is wrong because if *pp starts out pointing at '\0' (typically as the
+ result of an earlier error), it will be incremented to point to the
+ start of the next symbol, which might produce strange results, at least
+ if you run off the end of the string table. Instead use
+
+ if (**pp != ';')
+ return error_type (pp);
+ ++*pp;
+
+ or
+
+ if (**pp != ';')
+ foo = error_type (pp);
+ else
+ ++*pp;
+
+ And in case it isn't obvious, the point of all this hair is so the compiler
+ can define new types and new syntaxes, and old versions of the
+ debugger will be able to read the new symbol tables. */
+
+static struct type *
+error_type (pp)
+ char **pp;
+{
+ complain (&error_type_complaint);
+ while (1)
+ {
+ /* Skip to end of symbol. */
+ while (**pp != '\0')
+ {
+ (*pp)++;
+ }
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if ((*pp)[-1] == '\\')
+ {
+ *pp = next_symbol_text ();
+ }
+ else
+ {
+ break;
+ }
+ }
+ return (builtin_type_error);
+}
+
+/* This page contains subroutines of read_type. */
+
+#define VISIBILITY_PRIVATE '0' /* Stabs character for private field */
+#define VISIBILITY_PROTECTED '1' /* Stabs character for protected fld */
+#define VISIBILITY_PUBLIC '2' /* Stabs character for public field */
+#define VISIBILITY_IGNORE '9' /* Optimized out or zero length */
+
+static void
+read_one_struct_field (fip, pp, p, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ char *p;
+ struct type *type;
+ struct objfile *objfile;
+{
+ fip -> list -> field.name =
+ obsavestring (*pp, p - *pp, &objfile -> type_obstack);
+ *pp = p + 1;
+
+ fip -> list -> visibility = VISIBILITY_PUBLIC;
+ fip -> list -> field.type = os9k_read_type (pp, objfile);
+ if (**pp == ':')
+ {
+ p = ++(*pp);
+#if 0
+ /* Possible future hook for nested types. */
+ if (**pp == '!')
+ {
+ fip -> list -> field.bitpos = (long)-2; /* nested type */
+ p = ++(*pp);
+ }
+ else
+#endif
+ {
+ /* Static class member. */
+ fip -> list -> field.bitpos = (long) -1;
+ }
+ while (*p != ';')
+ {
+ p++;
+ }
+ fip -> list -> field.bitsize = (long) savestring (*pp, p - *pp);
+ *pp = p + 1;
+ return;
+ }
+ else if (**pp != ',')
+ {
+ /* Bad structure-type format. */
+ complain (&stabs_general_complaint, "bad structure-type format");
+ return;
+ }
+
+ (*pp)++; /* Skip the comma. */
+
+ {
+ int nbits;
+ fip -> list -> field.bitpos = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ {
+ complain (&stabs_general_complaint, "bad structure-type format");
+ return;
+ }
+ fip -> list -> field.bitsize = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ {
+ complain (&stabs_general_complaint, "bad structure-type format");
+ return;
+ }
+ }
+
+ if (fip -> list -> field.bitpos == 0 && fip -> list -> field.bitsize == 0)
+ {
+ /* This can happen in two cases: (1) at least for gcc 2.4.5 or so,
+ it is a field which has been optimized out. The correct stab for
+ this case is to use VISIBILITY_IGNORE, but that is a recent
+ invention. (2) It is a 0-size array. For example
+ union { int num; char str[0]; } foo. Printing "<no value>" for
+ str in "p foo" is OK, since foo.str (and thus foo.str[3])
+ will continue to work, and a 0-size array as a whole doesn't
+ have any contents to print.
+
+ I suspect this probably could also happen with gcc -gstabs (not
+ -gstabs+) for static fields, and perhaps other C++ extensions.
+ Hopefully few people use -gstabs with gdb, since it is intended
+ for dbx compatibility. */
+
+ /* Ignore this field. */
+ fip -> list-> visibility = VISIBILITY_IGNORE;
+ }
+ else
+ {
+ /* Detect an unpacked field and mark it as such.
+ dbx gives a bit size for all fields.
+ Note that forward refs cannot be packed,
+ and treat enums as if they had the width of ints. */
+
+ if (TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_INT
+ && TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_ENUM)
+ {
+ fip -> list -> field.bitsize = 0;
+ }
+ if ((fip -> list -> field.bitsize
+ == TARGET_CHAR_BIT * TYPE_LENGTH (fip -> list -> field.type)
+ || (TYPE_CODE (fip -> list -> field.type) == TYPE_CODE_ENUM
+ && (fip -> list -> field.bitsize
+ == TARGET_INT_BIT)
+ )
+ )
+ &&
+ fip -> list -> field.bitpos % 8 == 0)
+ {
+ fip -> list -> field.bitsize = 0;
+ }
+ }
+}
+
+
+/* Read struct or class data fields. They have the form:
+
+ NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
+
+ At the end, we see a semicolon instead of a field.
+
+ In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
+ a static field.
+
+ The optional VISIBILITY is one of:
+
+ '/0' (VISIBILITY_PRIVATE)
+ '/1' (VISIBILITY_PROTECTED)
+ '/2' (VISIBILITY_PUBLIC)
+ '/9' (VISIBILITY_IGNORE)
+
+ or nothing, for C style fields with public visibility.
+
+ Returns 1 for success, 0 for failure. */
+
+static int
+read_struct_fields (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ register char *p;
+ struct nextfield *new;
+
+ /* We better set p right now, in case there are no fields at all... */
+
+ p = *pp;
+
+ /* Read each data member type until we find the terminating ';' at the end of
+ the data member list, or break for some other reason such as finding the
+ start of the member function list. */
+
+ while (**pp != ';' && **pp != '\0')
+ {
+ STABS_CONTINUE (pp);
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) xmalloc (sizeof (struct nextfield));
+ make_cleanup (free, new);
+ memset (new, 0, sizeof (struct nextfield));
+ new -> next = fip -> list;
+ fip -> list = new;
+
+ /* Get the field name. */
+ p = *pp;
+
+ /* Look for the ':' that separates the field name from the field
+ values. Data members are delimited by a single ':', while member
+ functions are delimited by a pair of ':'s. When we hit the member
+ functions (if any), terminate scan loop and return. */
+
+ while (*p != ':' && *p != '\0')
+ {
+ p++;
+ }
+ if (*p == '\0')
+ return 0;
+
+ /* Check to see if we have hit the member functions yet. */
+ if (p[1] == ':')
+ {
+ break;
+ }
+ read_one_struct_field (fip, pp, p, type, objfile);
+ }
+ if (p[0] == ':' && p[1] == ':')
+ {
+ /* chill the list of fields: the last entry (at the head) is a
+ partially constructed entry which we now scrub. */
+ fip -> list = fip -> list -> next;
+ }
+ return 1;
+}
+
+/* Create the vector of fields, and record how big it is.
+ We need this info to record proper virtual function table information
+ for this class's virtual functions. */
+
+static int
+attach_fields_to_type (fip, type, objfile)
+ struct field_info *fip;
+ register struct type *type;
+ struct objfile *objfile;
+{
+ register int nfields = 0;
+ register int non_public_fields = 0;
+ register struct nextfield *scan;
+
+ /* Count up the number of fields that we have, as well as taking note of
+ whether or not there are any non-public fields, which requires us to
+ allocate and build the private_field_bits and protected_field_bits
+ bitfields. */
+
+ for (scan = fip -> list; scan != NULL; scan = scan -> next)
+ {
+ nfields++;
+ if (scan -> visibility != VISIBILITY_PUBLIC)
+ {
+ non_public_fields++;
+ }
+ }
+
+ /* Now we know how many fields there are, and whether or not there are any
+ non-public fields. Record the field count, allocate space for the
+ array of fields, and create blank visibility bitfields if necessary. */
+
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nfields);
+ memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields);
+
+ /* Copy the saved-up fields into the field vector. Start from the head
+ of the list, adding to the tail of the field array, so that they end
+ up in the same order in the array in which they were added to the list. */
+
+ while (nfields-- > 0)
+ {
+ TYPE_FIELD (type, nfields) = fip -> list -> field;
+ fip -> list = fip -> list -> next;
+ }
+ return 1;
+}
+
+/* Read the description of a structure (or union type) and return an object
+ describing the type.
+
+ PP points to a character pointer that points to the next unconsumed token
+ in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;",
+ *PP will point to "4a:1,0,32;;".
+
+ TYPE points to an incomplete type that needs to be filled in.
+
+ OBJFILE points to the current objfile from which the stabs information is
+ being read. (Note that it is redundant in that TYPE also contains a pointer
+ to this same objfile, so it might be a good idea to eliminate it. FIXME).
+ */
+
+static struct type *
+read_struct_type (pp, type, objfile)
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ struct cleanup *back_to;
+ struct field_info fi;
+
+ fi.list = NULL;
+ fi.fnlist = NULL;
+
+ back_to = make_cleanup (null_cleanup, 0);
+
+ INIT_CPLUS_SPECIFIC (type);
+ TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
+
+ /* First comes the total size in bytes. */
+
+ {
+ int nbits;
+ TYPE_LENGTH (type) = read_huge_number (pp, 0, &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+ }
+
+ /* Now read the baseclasses, if any, read the regular C struct or C++
+ class member fields, attach the fields to the type, read the C++
+ member functions, attach them to the type, and then read any tilde
+ field (baseclass specifier for the class holding the main vtable). */
+
+ if (!read_struct_fields (&fi, pp, type, objfile)
+ || !attach_fields_to_type (&fi, type, objfile)
+ )
+ {
+ do_cleanups (back_to);
+ return (error_type (pp));
+ }
+
+ do_cleanups (back_to);
+ return (type);
+}
+
+static long
+read_huge_number (pp, end, bits)
+ char **pp;
+ int end;
+ int *bits;
+{
+ char *p = *pp;
+ int sign = 1;
+ long n = 0;
+ int radix = 10;
+ char overflow = 0;
+ int nbits = 0;
+ int c;
+ long upper_limit;
+
+ if (*p == '-')
+ {
+ sign = -1;
+ p++;
+ }
+
+ /* Leading zero means octal. GCC uses this to output values larger
+ than an int (because that would be hard in decimal). */
+ if (*p == '0')
+ {
+ radix = 8;
+ p++;
+ }
+
+ upper_limit = LONG_MAX / radix;
+ while ((c = *p++) >= '0' && c < ('0' + radix))
+ {
+ if (n <= upper_limit)
+ {
+ n *= radix;
+ n += c - '0'; /* FIXME this overflows anyway */
+ }
+ else
+ overflow = 1;
+
+ /* This depends on large values being output in octal, which is
+ what GCC does. */
+ if (radix == 8)
+ {
+ if (nbits == 0)
+ {
+ if (c == '0')
+ /* Ignore leading zeroes. */
+ ;
+ else if (c == '1')
+ nbits = 1;
+ else if (c == '2' || c == '3')
+ nbits = 2;
+ else
+ nbits = 3;
+ }
+ else
+ nbits += 3;
+ }
+ }
+ if (end)
+ {
+ if (c && c != end)
+ {
+ if (bits != NULL)
+ *bits = -1;
+ return 0;
+ }
+ }
+ else
+ --p;
+
+ *pp = p;
+ if (overflow)
+ {
+ if (nbits == 0)
+ {
+ /* Large decimal constants are an error (because it is hard to
+ count how many bits are in them). */
+ if (bits != NULL)
+ *bits = -1;
+ return 0;
+ }
+
+ /* -0x7f is the same as 0x80. So deal with it by adding one to
+ the number of bits. */
+ if (sign == -1)
+ ++nbits;
+ if (bits)
+ *bits = nbits;
+ }
+ else
+ {
+ if (bits)
+ *bits = 0;
+ return n * sign;
+ }
+ /* It's *BITS which has the interesting information. */
+ return 0;
+}
+
+static struct type *
+read_range_type (pp, typenums, objfile)
+ char **pp;
+ int typenums[2];
+ struct objfile *objfile;
+{
+ int rangenums[2];
+ long n2, n3;
+ int n2bits, n3bits;
+ int self_subrange;
+ struct type *result_type;
+ struct type *index_type;
+
+ /* First comes a type we are a subrange of.
+ In C it is usually 0, 1 or the type being defined. */
+ /* FIXME: according to stabs.texinfo and AIX doc, this can be a type-id
+ not just a type number. */
+ if (read_type_number (pp, rangenums) != 0)
+ return error_type (pp);
+ self_subrange = (rangenums[0] == typenums[0] &&
+ rangenums[1] == typenums[1]);
+
+ /* A semicolon should now follow; skip it. */
+ if (**pp == ';')
+ (*pp)++;
+
+ /* The remaining two operands are usually lower and upper bounds
+ of the range. But in some special cases they mean something else. */
+ n2 = read_huge_number (pp, ';', &n2bits);
+ n3 = read_huge_number (pp, ';', &n3bits);
+
+ if (n2bits == -1 || n3bits == -1)
+ return error_type (pp);
+
+ /* If limits are huge, must be large integral type. */
+ if (n2bits != 0 || n3bits != 0)
+ {
+ char got_signed = 0;
+ char got_unsigned = 0;
+ /* Number of bits in the type. */
+ int nbits = 0;
+
+ /* Range from 0 to <large number> is an unsigned large integral type. */
+ if ((n2bits == 0 && n2 == 0) && n3bits != 0)
+ {
+ got_unsigned = 1;
+ nbits = n3bits;
+ }
+ /* Range from <large number> to <large number>-1 is a large signed
+ integral type. Take care of the case where <large number> doesn't
+ fit in a long but <large number>-1 does. */
+ else if ((n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1)
+ || (n2bits != 0 && n3bits == 0
+ && (n2bits == sizeof (long) * HOST_CHAR_BIT)
+ && n3 == LONG_MAX))
+ {
+ got_signed = 1;
+ nbits = n2bits;
+ }
+
+ if (got_signed || got_unsigned)
+ {
+ return init_type (TYPE_CODE_INT, nbits / TARGET_CHAR_BIT,
+ got_unsigned ? TYPE_FLAG_UNSIGNED : 0, NULL,
+ objfile);
+ }
+ else
+ return error_type (pp);
+ }
+
+ /* A type defined as a subrange of itself, with bounds both 0, is void. */
+ if (self_subrange && n2 == 0 && n3 == 0)
+ return init_type (TYPE_CODE_VOID, 0, 0, NULL, objfile);
+
+ /* If n3 is zero and n2 is not, we want a floating type,
+ and n2 is the width in bytes.
+
+ Fortran programs appear to use this for complex types also,
+ and they give no way to distinguish between double and single-complex!
+
+ GDB does not have complex types.
+
+ Just return the complex as a float of that size. It won't work right
+ for the complex values, but at least it makes the file loadable. */
+
+ if (n3 == 0 && n2 > 0)
+ {
+ return init_type (TYPE_CODE_FLT, n2, 0, NULL, objfile);
+ }
+
+ /* If the upper bound is -1, it must really be an unsigned int. */
+
+ else if (n2 == 0 && n3 == -1)
+ {
+ /* It is unsigned int or unsigned long. */
+ /* GCC 2.3.3 uses this for long long too, but that is just a GDB 3.5
+ compatibility hack. */
+ return init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ TYPE_FLAG_UNSIGNED, NULL, objfile);
+ }
+
+ /* Special case: char is defined (Who knows why) as a subrange of
+ itself with range 0-127. */
+ else if (self_subrange && n2 == 0 && n3 == 127)
+ return init_type (TYPE_CODE_INT, 1, 0, NULL, objfile);
+
+ /* We used to do this only for subrange of self or subrange of int. */
+ else if (n2 == 0)
+ {
+ if (n3 < 0)
+ /* n3 actually gives the size. */
+ return init_type (TYPE_CODE_INT, - n3, TYPE_FLAG_UNSIGNED,
+ NULL, objfile);
+ if (n3 == 0xff)
+ return init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, NULL, objfile);
+ if (n3 == 0xffff)
+ return init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, NULL, objfile);
+
+ /* -1 is used for the upper bound of (4 byte) "unsigned int" and
+ "unsigned long", and we already checked for that,
+ so don't need to test for it here. */
+ }
+ /* I think this is for Convex "long long". Since I don't know whether
+ Convex sets self_subrange, I also accept that particular size regardless
+ of self_subrange. */
+ else if (n3 == 0 && n2 < 0
+ && (self_subrange
+ || n2 == - TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT))
+ return init_type (TYPE_CODE_INT, - n2, 0, NULL, objfile);
+ else if (n2 == -n3 -1)
+ {
+ if (n3 == 0x7f)
+ return init_type (TYPE_CODE_INT, 1, 0, NULL, objfile);
+ if (n3 == 0x7fff)
+ return init_type (TYPE_CODE_INT, 2, 0, NULL, objfile);
+ if (n3 == 0x7fffffff)
+ return init_type (TYPE_CODE_INT, 4, 0, NULL, objfile);
+ }
+
+ /* We have a real range type on our hands. Allocate space and
+ return a real pointer. */
+
+ /* At this point I don't have the faintest idea how to deal with
+ a self_subrange type; I'm going to assume that this is used
+ as an idiom, and that all of them are special cases. So . . . */
+ if (self_subrange)
+ return error_type (pp);
+
+ index_type = *dbx_lookup_type (rangenums);
+ if (index_type == NULL)
+ {
+ /* Does this actually ever happen? Is that why we are worrying
+ about dealing with it rather than just calling error_type? */
+
+ static struct type *range_type_index;
+
+ complain (&range_type_base_complaint, rangenums[1]);
+ if (range_type_index == NULL)
+ range_type_index =
+ init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "range type index type", NULL);
+ index_type = range_type_index;
+ }
+
+ result_type = create_range_type ((struct type *) NULL, index_type, n2, n3);
+ return (result_type);
+}
+
+#if !defined (REG_STRUCT_HAS_ADDR)
+#define REG_STRUCT_HAS_ADDR(gcc_p) 0
+#endif
+
+static char *type_synonym_name = NULL;
+
+struct symbol *
+os9k_define_symbol (valu, string, desc, type, objfile)
+ CORE_ADDR valu;
+ char *string;
+ int desc;
+ int type;
+ struct objfile *objfile;
+{
+ register struct symbol *sym;
+ char *p = (char *) strchr (string, ':');
+ int deftype;
+ int synonym = 0;
+ register int i;
+
+ /* We would like to eliminate nameless symbols, but keep their types.
+ E.g. stab entry ":t10=*2" should produce a type 10, which is a pointer
+ to type 2, but, should not create a symbol to address that type. Since
+ the symbol will be nameless, there is no way any user can refer to it. */
+
+ int nameless;
+
+ /* Ignore syms with empty names. */
+ if (string[0] == 0)
+ return 0;
+
+ /* Ignore old-style symbols from cc -go */
+ if (p == 0)
+ return 0;
+
+ while (p[1] == ':')
+ {
+ p += 2;
+ p = strchr(p, ':');
+ }
+
+ /* If a nameless stab entry, all we need is the type, not the symbol.
+ e.g. ":t10=*2" or a nameless enum like " :T16=ered:0,green:1,blue:2,;" */
+ nameless = (p == string || ((string[0] == ' ') && (string[1] == ':')));
+
+ sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+
+ if (processing_gcc_compilation)
+ {
+ /* GCC 2.x puts the line number in desc. SunOS apparently puts in the
+ number of bytes occupied by a type or object, which we ignore. */
+ SYMBOL_LINE(sym) = desc;
+ }
+ else
+ {
+ SYMBOL_LINE(sym) = 0; /* unknown */
+ }
+
+ {
+ SYMBOL_LANGUAGE (sym) = current_subfile -> language;
+ SYMBOL_NAME (sym) = (char *)
+ obstack_alloc (&objfile -> symbol_obstack, ((p - string) + 1));
+ /* Open-coded memcpy--saves function call time. */
+ /* FIXME: Does it really? Try replacing with simple strcpy and
+ try it on an executable with a large symbol table. */
+ /* FIXME: considering that gcc can open code memcpy anyway, I
+ doubt it. xoxorich. */
+ {
+ register char *p1 = string;
+ register char *p2 = SYMBOL_NAME (sym);
+ while (p1 != p)
+ {
+ *p2++ = *p1++;
+ }
+ *p2++ = '\0';
+ }
+
+ /* If this symbol is from a C++ compilation, then attempt to cache the
+ demangled form for future reference. This is a typical time versus
+ space tradeoff, that was decided in favor of time because it sped up
+ C++ symbol lookups by a factor of about 20. */
+
+ SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile->symbol_obstack);
+ }
+ p++;
+
+ /* Determine the type of name being defined. */
+#if 0
+ /* Getting GDB to correctly skip the symbol on an undefined symbol
+ descriptor and not ever dump core is a very dodgy proposition if
+ we do things this way. I say the acorn RISC machine can just
+ fix their compiler. */
+ /* The Acorn RISC machine's compiler can put out locals that don't
+ start with "234=" or "(3,4)=", so assume anything other than the
+ deftypes we know how to handle is a local. */
+ if (!strchr ("cfFGpPrStTvVXCR", *p))
+#else
+ if (isdigit (*p) || *p == '(' || *p == '-')
+#endif
+ deftype = 'l';
+ else
+ deftype = *p++;
+
+ switch (deftype)
+ {
+ case 'c':
+ /* c is a special case, not followed by a type-number.
+ SYMBOL:c=iVALUE for an integer constant symbol.
+ SYMBOL:c=rVALUE for a floating constant symbol.
+ SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
+ e.g. "b:c=e6,0" for "const b = blob1"
+ (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */
+ if (*p != '=')
+ {
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = error_type (&p);
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ return sym;
+ }
+ ++p;
+ switch (*p++)
+ {
+ case 'r':
+ {
+ double d = atof (p);
+ char *dbl_valu;
+
+ /* FIXME-if-picky-about-floating-accuracy: Should be using
+ target arithmetic to get the value. real.c in GCC
+ probably has the necessary code. */
+
+ /* FIXME: lookup_fundamental_type is a hack. We should be
+ creating a type especially for the type of float constants.
+ Problem is, what type should it be?
+
+ Also, what should the name of this type be? Should we
+ be using 'S' constants (see stabs.texinfo) instead? */
+
+ SYMBOL_TYPE (sym) = lookup_fundamental_type (objfile,
+ FT_DBL_PREC_FLOAT);
+ dbl_valu = (char *)
+ obstack_alloc (&objfile -> symbol_obstack,
+ TYPE_LENGTH (SYMBOL_TYPE (sym)));
+ store_floating (dbl_valu, TYPE_LENGTH (SYMBOL_TYPE (sym)), d);
+ SYMBOL_VALUE_BYTES (sym) = dbl_valu;
+ SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+ }
+ break;
+ case 'i':
+ {
+ /* Defining integer constants this way is kind of silly,
+ since 'e' constants allows the compiler to give not
+ only the value, but the type as well. C has at least
+ int, long, unsigned int, and long long as constant
+ types; other languages probably should have at least
+ unsigned as well as signed constants. */
+
+ /* We just need one int constant type for all objfiles.
+ It doesn't depend on languages or anything (arguably its
+ name should be a language-specific name for a type of
+ that size, but I'm inclined to say that if the compiler
+ wants a nice name for the type, it can use 'e'). */
+ static struct type *int_const_type;
+
+ /* Yes, this is as long as a *host* int. That is because we
+ use atoi. */
+ if (int_const_type == NULL)
+ int_const_type =
+ init_type (TYPE_CODE_INT,
+ sizeof (int) * HOST_CHAR_BIT / TARGET_CHAR_BIT, 0,
+ "integer constant",
+ (struct objfile *)NULL);
+ SYMBOL_TYPE (sym) = int_const_type;
+ SYMBOL_VALUE (sym) = atoi (p);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ }
+ break;
+ case 'e':
+ /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value
+ can be represented as integral.
+ e.g. "b:c=e6,0" for "const b = blob1"
+ (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */
+ {
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+
+ if (*p != ',')
+ {
+ SYMBOL_TYPE (sym) = error_type (&p);
+ break;
+ }
+ ++p;
+
+ /* If the value is too big to fit in an int (perhaps because
+ it is unsigned), or something like that, we silently get
+ a bogus value. The type and everything else about it is
+ correct. Ideally, we should be using whatever we have
+ available for parsing unsigned and long long values,
+ however. */
+ SYMBOL_VALUE (sym) = atoi (p);
+ }
+ break;
+ default:
+ {
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_TYPE (sym) = error_type (&p);
+ }
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ return sym;
+
+ case 'C':
+ /* The name of a caught exception. */
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_LABEL;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE_ADDRESS (sym) = valu;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'f':
+ /* A static function definition. */
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ /* fall into process_function_types. */
+
+ process_function_types:
+ /* Function result types are described as the result type in stabs.
+ We need to convert this to the function-returning-type-X type
+ in GDB. E.g. "int" is converted to "function returning int". */
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_FUNC)
+ {
+#if 0
+ /* This code doesn't work -- it needs to realloc and can't. */
+ /* Attempt to set up to record a function prototype... */
+ struct type *new = alloc_type (objfile);
+
+ /* Generate a template for the type of this function. The
+ types of the arguments will be added as we read the symbol
+ table. */
+ *new = *lookup_function_type (SYMBOL_TYPE(sym));
+ SYMBOL_TYPE(sym) = new;
+ TYPE_OBJFILE (new) = objfile;
+ in_function_type = new;
+#else
+ SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym));
+#endif
+ }
+ /* fall into process_prototype_types */
+
+ process_prototype_types:
+ /* Sun acc puts declared types of arguments here. We don't care
+ about their actual types (FIXME -- we should remember the whole
+ function prototype), but the list may define some new types
+ that we have to remember, so we must scan it now. */
+ while (*p == ';') {
+ p++;
+ os9k_read_type (&p, objfile);
+ }
+ break;
+
+ case 'F':
+ /* A global function definition. */
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &global_symbols);
+ goto process_function_types;
+
+ case 'V':
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+ SYMBOL_VALUE_ADDRESS (sym) = valu;
+/*
+ i = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i];
+ global_sym_chain[i] = sym;
+*/
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ /* This case is faked by a conditional above,
+ when there is no code letter in the dbx data.
+ Dbx data never actually contains 'l'. */
+ case 'l':
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'p':
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+
+ /* Normally this is a parameter, a LOC_ARG. On the i960, it
+ can also be a LOC_LOCAL_ARG depending on symbol type. */
+#ifndef DBX_PARM_SYMBOL_CLASS
+#define DBX_PARM_SYMBOL_CLASS(type) LOC_ARG
+#endif
+
+ SYMBOL_CLASS (sym) = DBX_PARM_SYMBOL_CLASS (type);
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+#if 0
+ /* This doesn't work yet. */
+ add_param_to_type (&in_function_type, sym);
+#endif
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'P':
+ /* acc seems to use P to delare the prototypes of functions that
+ are referenced by this file. gdb is not prepared to deal
+ with this extra information. FIXME, it ought to. */
+ if (type == N_FUN)
+ {
+ os9k_read_type (&p, objfile);
+ goto process_prototype_types;
+ }
+ /*FALLTHROUGH*/
+
+ case 'R':
+#if 0
+ /* Parameter which is in a register. */
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+ if (SYMBOL_VALUE (sym) >= NUM_REGS)
+ {
+ complain (&reg_value_complaint, SYMBOL_SOURCE_NAME (sym));
+ SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+#endif 0
+ case 'r':
+ /* Register variable (either global or local). */
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+ if (SYMBOL_VALUE (sym) >= NUM_REGS)
+ {
+ complain (&reg_value_complaint, SYMBOL_SOURCE_NAME (sym));
+ SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ if (within_function)
+ {
+ /* Sun cc uses a pair of symbols, one 'p' and one 'r' with the same
+ name to represent an argument passed in a register.
+ GCC uses 'P' for the same case. So if we find such a symbol pair
+ we combine it into one 'P' symbol.
+
+ But we only do this in the REG_STRUCT_HAS_ADDR case, so that
+ we can still get information about what is going on with the
+ stack (VAX for computing args_printed, using stack slots instead
+ of saved registers in backtraces, etc.).
+
+ Note that this code illegally combines
+ main(argc) struct foo argc; { register struct foo argc; }
+ but this case is considered pathological and causes a warning
+ from a decent compiler. */
+
+ if (local_symbols
+ && local_symbols->nsyms > 0
+ && REG_STRUCT_HAS_ADDR (processing_gcc_compilation)
+ && (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION))
+ {
+ struct symbol *prev_sym;
+ prev_sym = local_symbols->symbol[local_symbols->nsyms - 1];
+ if (SYMBOL_CLASS (prev_sym) == LOC_ARG
+ && STREQ (SYMBOL_NAME (prev_sym), SYMBOL_NAME(sym)))
+ {
+ SYMBOL_CLASS (prev_sym) = LOC_REGPARM;
+ /* Use the type from the LOC_REGISTER; that is the type
+ that is actually in that register. */
+ SYMBOL_TYPE (prev_sym) = SYMBOL_TYPE (sym);
+ SYMBOL_VALUE (prev_sym) = SYMBOL_VALUE (sym);
+ sym = prev_sym;
+ break;
+ }
+ }
+ add_symbol_to_list (sym, &local_symbols);
+ }
+ else
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 't':
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+
+ /* For a nameless type, we don't want a create a symbol, thus we
+ did not use `sym'. Return without further processing. */
+ if (nameless) return NULL;
+
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == NULL)
+ {
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR
+ || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FUNC)
+ {
+ /* If we are giving a name to a type such as "pointer to
+ foo" or "function returning foo", we better not set
+ the TYPE_NAME. If the program contains "typedef char
+ *caddr_t;", we don't want all variables of type char
+ * to print as caddr_t. This is not just a
+ consequence of GDB's type management; PCC and GCC (at
+ least through version 2.4) both output variables of
+ either type char * or caddr_t with the type number
+ defined in the 't' symbol for caddr_t. If a future
+ compiler cleans this up it GDB is not ready for it
+ yet, but if it becomes ready we somehow need to
+ disable this check (without breaking the PCC/GCC2.4
+ case).
+
+ Sigh.
+
+ Fortunately, this check seems not to be necessary
+ for anything except pointers or functions. */
+ }
+ else
+ TYPE_NAME (SYMBOL_TYPE (sym)) = SYMBOL_NAME (sym);
+ }
+
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'T':
+ /* Struct, union, or enum tag. For GNU C++, this can be be followed
+ by 't' which means we are typedef'ing it as well. */
+ synonym = *p == 't';
+
+ if (synonym)
+ {
+ p++;
+ type_synonym_name = obsavestring (SYMBOL_NAME (sym),
+ strlen (SYMBOL_NAME (sym)),
+ &objfile -> symbol_obstack);
+ }
+ /* The semantics of C++ state that "struct foo { ... }" also defines
+ a typedef for "foo". Unfortunately, cfront never makes the typedef
+ when translating C++ into C. We make the typedef here so that
+ "ptype foo" works as expected for cfront translated code. */
+ else if (current_subfile->language == language_cplus)
+ {
+ synonym = 1;
+ type_synonym_name = obsavestring (SYMBOL_NAME (sym),
+ strlen (SYMBOL_NAME (sym)),
+ &objfile -> symbol_obstack);
+ }
+
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+
+ /* For a nameless type, we don't want a create a symbol, thus we
+ did not use `sym'. Return without further processing. */
+ if (nameless) return NULL;
+
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+ if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0)
+ TYPE_TAG_NAME (SYMBOL_TYPE (sym))
+ = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym));
+ add_symbol_to_list (sym, &file_symbols);
+
+ if (synonym)
+ {
+ /* Clone the sym and then modify it. */
+ register struct symbol *typedef_sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ *typedef_sym = *sym;
+ SYMBOL_CLASS (typedef_sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (typedef_sym) = valu;
+ SYMBOL_NAMESPACE (typedef_sym) = VAR_NAMESPACE;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym))
+ = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym));
+ add_symbol_to_list (typedef_sym, &file_symbols);
+ }
+ break;
+
+ case 'v':
+ /* Static symbol at top level of file */
+ SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE_ADDRESS (sym) = valu;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ default:
+ SYMBOL_TYPE (sym) = error_type (&p);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_VALUE (sym) = 0;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+ }
+
+ /* When passing structures to a function, some systems sometimes pass
+ the address in a register, not the structure itself.
+
+ If REG_STRUCT_HAS_ADDR yields non-zero we have to convert LOC_REGPARM
+ to LOC_REGPARM_ADDR for structures and unions. */
+
+ if (SYMBOL_CLASS (sym) == LOC_REGPARM
+ && REG_STRUCT_HAS_ADDR (processing_gcc_compilation)
+ && ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT)
+ || (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)))
+ SYMBOL_CLASS (sym) = LOC_REGPARM_ADDR;
+
+ return sym;
+}
+
+
+/* Read type information or a type definition; return the type. Even
+ though this routine accepts either type information or a type
+ definition, the distinction is relevant--some parts of stabsread.c
+ assume that type information starts with a digit, '-', or '(' in
+ deciding whether to call read_type. */
+
+static struct type *
+os9k_read_type (pp, objfile)
+ register char **pp;
+ struct objfile *objfile;
+{
+ register struct type *type = 0;
+ struct type *type1;
+ int typenums[2];
+ int xtypenums[2];
+ char type_descriptor;
+
+ /* Size in bits of type if specified by a type attribute, or -1 if
+ there is no size attribute. */
+ int type_size = -1;
+
+ /* Used to distinguish string and bitstring from char-array and set. */
+ int is_string = 0;
+
+ /* Read type number if present. The type number may be omitted.
+ for instance in a two-dimensional array declared with type
+ "ar1;1;10;ar1;1;10;4". */
+ if ((**pp >= '0' && **pp <= '9')
+ || **pp == '('
+ || **pp == '-')
+ {
+ if (read_type_number (pp, typenums) != 0)
+ return error_type (pp);
+
+ /* Type is not being defined here. Either it already exists,
+ or this is a forward reference to it. dbx_alloc_type handles
+ both cases. */
+ if (**pp != '=')
+ return dbx_alloc_type (typenums, objfile);
+
+ /* Type is being defined here. */
+ /* Skip the '='. */
+ ++(*pp);
+
+ while (**pp == '@')
+ {
+ char *p = *pp + 1;
+ /* It might be a type attribute or a member type. */
+ if (isdigit (*p) || *p == '(' || *p == '-')
+ /* Member type. */
+ break;
+ else
+ {
+ /* Type attributes. */
+ char *attr = p;
+
+ /* Skip to the semicolon. */
+ while (*p != ';' && *p != '\0')
+ ++p;
+ *pp = p;
+ if (*p == '\0')
+ return error_type (pp);
+ else
+ /* Skip the semicolon. */
+ ++*pp;
+
+ switch (*attr)
+ {
+ case 's':
+ type_size = atoi (attr + 1);
+ if (type_size <= 0)
+ type_size = -1;
+ break;
+
+ case 'S':
+ is_string = 1;
+ break;
+
+ default:
+ /* Ignore unrecognized type attributes, so future compilers
+ can invent new ones. */
+ break;
+ }
+ }
+ }
+ /* Skip the type descriptor, we get it below with (*pp)[-1]. */
+ ++(*pp);
+ }
+ else
+ {
+ /* 'typenums=' not present, type is anonymous. Read and return
+ the definition, but don't put it in the type vector. */
+ typenums[0] = typenums[1] = -1;
+ (*pp)++;
+ }
+
+ type_descriptor = (*pp)[-1];
+ switch (type_descriptor)
+ {
+ case 'x':
+ {
+ enum type_code code;
+
+ /* Used to index through file_symbols. */
+ struct pending *ppt;
+ int i;
+
+ /* Name including "struct", etc. */
+ char *type_name;
+
+ {
+ char *from, *to, *p, *q1, *q2;
+
+ /* Set the type code according to the following letter. */
+ switch ((*pp)[0])
+ {
+ case 's':
+ code = TYPE_CODE_STRUCT;
+ break;
+ case 'u':
+ code = TYPE_CODE_UNION;
+ break;
+ case 'e':
+ code = TYPE_CODE_ENUM;
+ break;
+ default:
+ {
+ /* Complain and keep going, so compilers can invent new
+ cross-reference types. */
+ static struct complaint msg =
+ {"Unrecognized cross-reference type `%c'", 0, 0};
+ complain (&msg, (*pp)[0]);
+ code = TYPE_CODE_STRUCT;
+ break;
+ }
+ }
+
+ q1 = strchr(*pp, '<');
+ p = strchr(*pp, ':');
+ if (p == NULL)
+ return error_type (pp);
+ while (q1 && p > q1 && p[1] == ':')
+ {
+ q2 = strchr(q1, '>');
+ if (!q2 || q2 < p)
+ break;
+ p += 2;
+ p = strchr(p, ':');
+ if (p == NULL)
+ return error_type (pp);
+ }
+ to = type_name =
+ (char *)obstack_alloc (&objfile->type_obstack, p - *pp + 1);
+
+ /* Copy the name. */
+ from = *pp + 1;
+ while (from < p)
+ *to++ = *from++;
+ *to = '\0';
+
+ /* Set the pointer ahead of the name which we just read, and
+ the colon. */
+ *pp = from + 1;
+ }
+
+ /* Now check to see whether the type has already been
+ declared. This was written for arrays of cross-referenced
+ types before we had TYPE_CODE_TARGET_STUBBED, so I'm pretty
+ sure it is not necessary anymore. But it might be a good
+ idea, to save a little memory. */
+
+ for (ppt = file_symbols; ppt; ppt = ppt->next)
+ for (i = 0; i < ppt->nsyms; i++)
+ {
+ struct symbol *sym = ppt->symbol[i];
+
+ if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
+ && (TYPE_CODE (SYMBOL_TYPE (sym)) == code)
+ && STREQ (SYMBOL_NAME (sym), type_name))
+ {
+ obstack_free (&objfile -> type_obstack, type_name);
+ type = SYMBOL_TYPE (sym);
+ return type;
+ }
+ }
+
+ /* Didn't find the type to which this refers, so we must
+ be dealing with a forward reference. Allocate a type
+ structure for it, and keep track of it so we can
+ fill in the rest of the fields when we get the full
+ type. */
+ type = dbx_alloc_type (typenums, objfile);
+ TYPE_CODE (type) = code;
+ TYPE_TAG_NAME (type) = type_name;
+ TYPE_NAME(type) = NULL;
+ INIT_CPLUS_SPECIFIC(type);
+ TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+
+ add_undefined_type (type);
+ return type;
+ }
+
+ case '-': /* RS/6000 built-in type */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '(':
+
+ {
+ char *pp_saved;
+
+ (*pp)--;
+ pp_saved = *pp;
+
+ /* Peek ahead at the number to detect void. */
+ if (read_type_number (pp, xtypenums) != 0)
+ return error_type (pp);
+
+ if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1])
+ /* It's being defined as itself. That means it is "void". */
+ type = init_type (TYPE_CODE_VOID, 0, 0, NULL, objfile);
+ else
+ {
+ struct type *xtype;
+
+ /* Go back to the number and have read_type get it. This means
+ that we can deal with something like t(1,2)=(3,4)=... which
+ the Lucid compiler uses. */
+ *pp = pp_saved;
+ xtype = os9k_read_type (pp, objfile);
+
+ /* The type is being defined to another type. So we copy the type.
+ This loses if we copy a C++ class and so we lose track of how
+ the names are mangled (but g++ doesn't output stabs like this
+ now anyway). */
+
+ type = alloc_type (objfile);
+ memcpy (type, xtype, sizeof (struct type));
+
+ /* The idea behind clearing the names is that the only purpose
+ for defining a type to another type is so that the name of
+ one can be different. So we probably don't need to worry much
+ about the case where the compiler doesn't give a name to the
+ new type. */
+ TYPE_NAME (type) = NULL;
+ TYPE_TAG_NAME (type) = NULL;
+ }
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+ }
+
+ /* In the following types, we must be sure to overwrite any existing
+ type that the typenums refer to, rather than allocating a new one
+ and making the typenums point to the new one. This is because there
+ may already be pointers to the existing type (if it had been
+ forward-referenced), and we must change it to a pointer, function,
+ reference, or whatever, *in-place*. */
+
+ case '*':
+ type1 = os9k_read_type (pp, objfile);
+ type = make_pointer_type (type1, dbx_lookup_type (typenums));
+ break;
+
+ case '&': /* Reference to another type */
+ type1 = os9k_read_type (pp, objfile);
+ type = make_reference_type (type1, dbx_lookup_type (typenums));
+ break;
+
+ case 'f': /* Function returning another type */
+ if (**pp == '(') {
+ while (**pp != ')') ++*pp; /* skip os9000 function prototype */
+ ++*pp;
+ }
+ type1 = os9k_read_type (pp, objfile);
+ type = make_function_type (type1, dbx_lookup_type (typenums));
+ break;
+
+ case 'c': /* Const qualifier on some type (Sun) */
+ type = os9k_read_type (pp, objfile);
+ /* FIXME! For now, we ignore const and volatile qualifiers. */
+ break;
+
+ case 'b': /* Const volatile */
+ case 'i': /* Volatile qual on some type (Sun) */
+ type = os9k_read_type (pp, objfile);
+ /* FIXME! For now, we ignore const and volatile qualifiers. */
+ break;
+
+/* FIXME -- we should be doing smash_to_XXX types here. */
+ case '@': /* Member (class & variable) type */
+ {
+ struct type *domain = os9k_read_type (pp, objfile);
+ struct type *memtype;
+
+ if (**pp != ',')
+ /* Invalid member type data format. */
+ return error_type (pp);
+ ++*pp;
+
+ memtype = os9k_read_type (pp, objfile);
+ type = dbx_alloc_type (typenums, objfile);
+ smash_to_member_type (type, domain, memtype);
+ }
+ break;
+
+ case 'r': /* Range type */
+ type = read_range_type (pp, typenums, objfile);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 'e': /* Enumeration type */
+ type = dbx_alloc_type (typenums, objfile);
+ type = os9k_read_enum_type (pp, type, objfile);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 's': /* Struct type */
+ case 'u': /* Union type */
+ type = dbx_alloc_type (typenums, objfile);
+ if (!TYPE_NAME (type))
+ {
+ TYPE_NAME (type) = type_synonym_name;
+ }
+ type_synonym_name = NULL;
+ switch (type_descriptor)
+ {
+ case 's':
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ break;
+ case 'u':
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ break;
+ }
+ type = read_struct_type (pp, type, objfile);
+ break;
+
+ case 'a': /* Array type */
+ if (**pp == 'r')
+ ++*pp;
+
+ type = dbx_alloc_type (typenums, objfile);
+ type = os9k_read_array_type (pp, type, objfile);
+ if (is_string)
+ TYPE_CODE (type) = TYPE_CODE_STRING;
+ break;
+
+ case 'S':
+ type1 = os9k_read_type (pp, objfile);
+ type = create_set_type ((struct type*) NULL, type1);
+ if (is_string)
+ TYPE_CODE (type) = TYPE_CODE_BITSTRING;
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ default:
+ --*pp; /* Go back to the symbol in error */
+ /* Particularly important if it was \0! */
+ return error_type (pp);
+ }
+
+ if (type == 0)
+ {
+ warning ("GDB internal error, type is NULL in stabsread.c\n");
+ return error_type (pp);
+ }
+
+ /* Size specified in a type attribute overrides any other size. */
+ if (type_size != -1)
+ TYPE_LENGTH (type) = type_size / TARGET_CHAR_BIT;
+
+ return type;
+}
+
+/* Read a definition of an array type,
+ and create and return a suitable type object.
+ Also creates a range type which represents the bounds of that
+ array. */
+
+static struct type *
+os9k_read_array_type (pp, type, objfile)
+ register char **pp;
+ register struct type *type;
+ struct objfile *objfile;
+{
+ struct type *index_type, *element_type, *range_type;
+ int lower, upper;
+ int adjustable = 0;
+ int nbits;
+
+ /* Format of an array type:
+ "arlower,upper;<array_contents_type>". Put code in
+ to handle this.
+
+ Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
+ for these, produce a type like float[][]. */
+
+ index_type = builtin_type_int;
+
+ if (!(**pp >= '0' && **pp <= '9') && **pp != '-')
+ {
+ (*pp)++;
+ adjustable = 1;
+ }
+ lower = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ if (!(**pp >= '0' && **pp <= '9') && **pp != '-')
+ {
+ (*pp)++;
+ adjustable = 1;
+ }
+ upper = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ element_type = os9k_read_type (pp, objfile);
+
+ if (adjustable)
+ {
+ lower = 0;
+ upper = -1;
+ }
+
+ range_type =
+ create_range_type ((struct type *) NULL, index_type, lower, upper);
+ type = create_array_type (type, element_type, range_type);
+
+ /* If we have an array whose element type is not yet known, but whose
+ bounds *are* known, record it to be adjusted at the end of the file. */
+ /* FIXME: Why check for zero length rather than TYPE_FLAG_STUB? I think
+ the two have the same effect except that the latter is cleaner and the
+ former would be wrong for types which really are zero-length (if we
+ have any). */
+
+ if (TYPE_LENGTH (element_type) == 0 && !adjustable)
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_TARGET_STUB;
+ add_undefined_type (type);
+ }
+
+ return type;
+}
+
+
+/* Read a definition of an enumeration type,
+ and create and return a suitable type object.
+ Also defines the symbols that represent the values of the type. */
+
+static struct type *
+os9k_read_enum_type (pp, type, objfile)
+ register char **pp;
+ register struct type *type;
+ struct objfile *objfile;
+{
+ register char *p;
+ char *name;
+ register long n;
+ register struct symbol *sym;
+ int nsyms = 0;
+ struct pending **symlist;
+ struct pending *osyms, *syms;
+ int o_nsyms;
+ int size;
+ int nbits;
+
+#if 0
+ /* FIXME! The stabs produced by Sun CC merrily define things that ought
+ to be file-scope, between N_FN entries, using N_LSYM. What's a mother
+ to do? For now, force all enum values to file scope. */
+ if (within_function)
+ symlist = &local_symbols;
+ else
+#endif
+ symlist = &file_symbols;
+ osyms = *symlist;
+ o_nsyms = osyms ? osyms->nsyms : 0;
+
+ /* Read the value-names and their values.
+ The input syntax is NAME:VALUE,NAME:VALUE, and so on.
+ A semicolon or comma instead of a NAME means the end. */
+
+ size = read_huge_number(pp, 0, &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+ while (**pp && **pp != ';' && **pp != ',')
+ {
+ STABS_CONTINUE (pp);
+ p = *pp;
+ while (*p != ':') p++;
+ name = obsavestring (*pp, p - *pp, &objfile -> symbol_obstack);
+ *pp = p + 1;
+ n = read_huge_number (pp, ',', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = name;
+ SYMBOL_LANGUAGE (sym) = current_subfile -> language;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE (sym) = n;
+ add_symbol_to_list (sym, symlist);
+ nsyms++;
+ }
+
+ if (**pp == ';')
+ (*pp)++; /* Skip the semicolon. */
+
+ /* Now fill in the fields of the type-structure. */
+
+ TYPE_LENGTH (type) = TARGET_INT_BIT / HOST_CHAR_BIT;
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *)
+ TYPE_ALLOC (type, sizeof (struct field) * nsyms);
+ memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nsyms);
+
+ /* Find the symbols for the values and put them into the type.
+ The symbols can be found in the symlist that we put them on
+ to cause them to be defined. osyms contains the old value
+ of that symlist; everything up to there was defined by us. */
+ /* Note that we preserve the order of the enum constants, so
+ that in something like "enum {FOO, LAST_THING=FOO}" we print
+ FOO, not LAST_THING. */
+
+ for (syms = *symlist, n = 0; syms; syms = syms->next)
+ {
+ int j = 0;
+ if (syms == osyms)
+ j = o_nsyms;
+ for (; j < syms->nsyms; j++,n++)
+ {
+ struct symbol *xsym = syms->symbol[j];
+ SYMBOL_TYPE (xsym) = type;
+ TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym);
+ TYPE_FIELD_VALUE (type, n) = 0;
+ TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym);
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ }
+ if (syms == osyms)
+ break;
+ }
+
+ return type;
+}
diff --git a/gdb/remote-os9k.c b/gdb/remote-os9k.c
new file mode 100644
index 0000000..855ea4f
--- /dev/null
+++ b/gdb/remote-os9k.c
@@ -0,0 +1,1181 @@
+ /* Remote debugging interface for boot monitors, for GDB.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file was derived from remote-eb.c, which did a similar job, but for
+ an AMD-29K running EBMON. That file was in turn derived from remote.c
+ as mentioned in the following comment (left in for comic relief):
+
+ "This is like remote.c but is for a different situation--
+ having a PC running os9000 hook up with a unix machine with
+ a serial line, and running ctty com2 on the PC. os9000 has a debug
+ monitor called ROMBUG running. Not to mention that the PC
+ has PC/NFS, so it can access the same executables that gdb can,
+ over the net in real time."
+
+ In reality, this module talks to a debug monitor called 'ROMBUG', which
+ We communicate with ROMBUG via a direct serial line, the network version
+ of ROMBUG is not available yet.
+*/
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "wait.h"
+#include <varargs.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include "command.h"
+#include "serial.h"
+#include "monitor.h"
+#include "remote-utils.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+
+#ifdef HAVE_TERMIO
+# define TERMINAL struct termios
+#else
+# define TERMINAL struct sgttyb
+#endif
+
+struct monitor_ops *current_monitor;
+struct cmd_list_element *showlist;
+extern struct target_ops rombug_ops; /* Forward declaration */
+extern struct monitor_ops rombug_cmds; /* Forward declaration */
+extern struct cmd_list_element *setlist;
+extern struct cmd_list_element *unsetlist;
+extern int attach_flag;
+
+static void rombug_close();
+static void rombug_fetch_register();
+static void rombug_fetch_registers();
+static void rombug_store_register();
+#if 0
+static int sr_get_debug(); /* flag set by "set remotedebug" */
+#endif
+static int hashmark; /* flag set by "set hash" */
+static int rombug_is_open = 0;
+
+/* FIXME: Replace with sr_get_debug (). */
+#define LOG_FILE "monitor.log"
+#if defined (LOG_FILE)
+FILE *log_file;
+#endif
+
+static int timeout = 5;
+static int is_trace_mode = 0;
+/* Descriptor for I/O to remote machine. Initialize it to NULL*/
+static serial_t monitor_desc = NULL;
+
+/* Send data to monitor. Works just like printf. */
+static void
+printf_monitor(va_alist)
+ va_dcl
+{
+ va_list args;
+ char *pattern;
+ char buf[200];
+ int i;
+
+ va_start(args);
+
+ pattern = va_arg(args, char *);
+
+ vsprintf(buf, pattern, args);
+
+ if (SERIAL_WRITE(monitor_desc, buf, strlen(buf)))
+ fprintf(stderr, "SERIAL_WRITE failed: %s\n", safe_strerror(errno));
+}
+
+/* Read a character from the remote system, doing all the fancy timeout stuff*/
+static int
+readchar(timeout)
+ int timeout;
+{
+ int c;
+
+ c = SERIAL_READCHAR(monitor_desc, timeout);
+
+ if (sr_get_debug())
+ putchar(c & 0x7f);
+
+#ifdef LOG_FILE
+ if (isascii (c))
+ putc(c & 0x7f, log_file);
+#endif
+
+ if (c >= 0)
+ return c & 0x7f;
+
+ if (c == SERIAL_TIMEOUT)
+ {
+ if (timeout == 0)
+ return c; /* Polls shouldn't generate timeout errors */
+
+ error("Timeout reading from remote system.");
+ }
+
+ perror_with_name("remote-monitor");
+}
+
+/* Scan input from the remote system, until STRING is found. If DISCARD is
+ non-zero, then discard non-matching input, else print it out.
+ Let the user break out immediately. */
+static void
+expect(string, discard)
+ char *string;
+ int discard;
+{
+ char *p = string;
+ int c;
+
+ if (sr_get_debug())
+ printf ("Expecting \"%s\"\n", string);
+
+ immediate_quit = 1;
+ while (1)
+ {
+ c = readchar(timeout);
+ if (!isascii (c))
+ continue;
+ if (c == *p++)
+ {
+ if (*p == '\0')
+ {
+ immediate_quit = 0;
+ if (sr_get_debug())
+ printf ("\nMatched\n");
+ return;
+ }
+ }
+ else
+ {
+ if (!discard)
+ {
+ fwrite(string, 1, (p - 1) - string, stdout);
+ putchar((char)c);
+ fflush(stdout);
+ }
+ p = string;
+ }
+ }
+}
+
+/* Keep discarding input until we see the ROMBUG prompt.
+
+ The convention for dealing with the prompt is that you
+ o give your command
+ o *then* wait for the prompt.
+
+ Thus the last thing that a procedure does with the serial line
+ will be an expect_prompt(). Exception: rombug_resume does not
+ wait for the prompt, because the terminal is being handed over
+ to the inferior. However, the next thing which happens after that
+ is a rombug_wait which does wait for the prompt.
+ Note that this includes abnormal exit, e.g. error(). This is
+ necessary to prevent getting into states from which we can't
+ recover. */
+static void
+expect_prompt(discard)
+ int discard;
+{
+#if defined (LOG_FILE)
+ /* This is a convenient place to do this. The idea is to do it often
+ enough that we never lose much data if we terminate abnormally. */
+ fflush(log_file);
+#endif
+ if (is_trace_mode) {
+ expect("trace", discard);
+ is_trace_mode = 0;
+ } else {
+ expect (PROMPT, discard);
+ }
+}
+
+/* Get a hex digit from the remote system & return its value.
+ If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */
+static int
+get_hex_digit(ignore_space)
+ int ignore_space;
+{
+ int ch;
+ while (1)
+ {
+ ch = readchar(timeout);
+ if (ch >= '0' && ch <= '9')
+ return ch - '0';
+ else if (ch >= 'A' && ch <= 'F')
+ return ch - 'A' + 10;
+ else if (ch >= 'a' && ch <= 'f')
+ return ch - 'a' + 10;
+ else if (ch == ' ' && ignore_space)
+ ;
+ else
+ {
+ expect_prompt(1);
+ error("Invalid hex digit from remote system.");
+ }
+ }
+}
+
+/* Get a byte from monitor and put it in *BYT. Accept any number
+ leading spaces. */
+static void
+get_hex_byte (byt)
+ char *byt;
+{
+ int val;
+
+ val = get_hex_digit (1) << 4;
+ val |= get_hex_digit (0);
+ *byt = val;
+}
+
+/* Get N 32-bit words from remote, each preceded by a space,
+ and put them in registers starting at REGNO. */
+static void
+get_hex_regs (n, regno)
+ int n;
+ int regno;
+{
+ long val;
+ int i;
+ unsigned char b;
+
+ for (i = 0; i < n; i++)
+ {
+ int j;
+
+ val = 0;
+ for (j = 0; j < 4; j++)
+ {
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ get_hex_byte(&b);
+ val = (val << 8) + b;
+#else
+ get_hex_byte(&b);
+ val = val + (b << (j*8));
+#endif
+ }
+ supply_register (regno++, (char *) &val);
+ }
+}
+
+/* This is called not only when we first attach, but also when the
+ user types "run" after having attached. */
+static void
+rombug_create_inferior (execfile, args, env)
+ char *execfile;
+ char *args;
+ char **env;
+{
+ int entry_pt;
+
+ if (args && *args)
+ error("Can't pass arguments to remote ROMBUG process");
+
+ if (execfile == 0 || exec_bfd == 0)
+ error("No exec file specified");
+
+ entry_pt = (int) bfd_get_start_address (exec_bfd);
+
+#ifdef LOG_FILE
+ fputs ("\nIn Create_inferior()", log_file);
+#endif
+
+/* The "process" (board) is already stopped awaiting our commands, and
+ the program is already downloaded. We just set its PC and go. */
+
+ init_wait_for_inferior ();
+ proceed ((CORE_ADDR)entry_pt, TARGET_SIGNAL_DEFAULT, 0);
+}
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+static int baudrate = 9600;
+static char dev_name[100];
+
+static void
+rombug_open(args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (args == NULL)
+ error ("Use `target RomBug DEVICE-NAME' to use a serial port, or \n\
+`target RomBug HOST-NAME:PORT-NUMBER' to use a network connection.");
+
+ target_preopen(from_tty);
+
+ if (rombug_is_open)
+ unpush_target(&rombug_ops);
+
+ strcpy(dev_name, args);
+ monitor_desc = SERIAL_OPEN(dev_name);
+ if (monitor_desc == NULL)
+ perror_with_name(dev_name);
+
+ /* The baud rate was specified when GDB was started. ***
+ if (SERIAL_SETBAUDRATE (monitor_desc, sr_get_baud_rate()))
+ {
+ SERIAL_CLOSE (monitor_desc);
+ perror_with_name ("RomBug");
+ }
+ */
+ SERIAL_RAW(monitor_desc);
+ rombug_is_open = 1;
+
+#if defined (LOG_FILE)
+ log_file = fopen (LOG_FILE, "w");
+ if (log_file == NULL)
+ perror_with_name (LOG_FILE);
+#endif
+
+ push_monitor (&rombug_cmds);
+
+ printf_monitor("\r"); /* CR wakes up monitor */
+ expect_prompt(1);
+
+ push_target (&rombug_ops);
+ if (from_tty)
+ printf("Remote %s connected to %s\n", target_shortname,
+ dev_name);
+
+ attach_flag = 1;
+ rombug_fetch_registers();
+}
+
+/*
+ * Close out all files and local state before this target loses control.
+ */
+
+static void
+rombug_close (quitting)
+ int quitting;
+{
+ if (rombug_is_open) {
+ SERIAL_CLOSE(monitor_desc);
+ monitor_desc = NULL;
+ rombug_is_open = 0;
+ }
+
+#if defined (LOG_FILE)
+ if (log_file) {
+ if (ferror(log_file))
+ fprintf(stderr, "Error writing log file.\n");
+ if (fclose(log_file) != 0)
+ fprintf(stderr, "Error closing log file.\n");
+ log_file = 0;
+ }
+#endif
+}
+
+int
+rombug_link(mod_name, text_reloc)
+ char *mod_name;
+ CORE_ADDR *text_reloc;
+{
+ int i, j;
+ unsigned long val;
+ unsigned char b;
+
+ printf_monitor("l %s \r", mod_name);
+ expect_prompt(1);
+ printf_monitor(".r \r");
+ expect(REG_DELIM, 1);
+ for (i=0; i <= 7; i++)
+ {
+ val = 0;
+ for (j = 0; j < 4; j++)
+ {
+ get_hex_byte(&b);
+ val = (val << 8) + b;
+ }
+ }
+ expect_prompt(1);
+ *text_reloc = val;
+ return 1;
+}
+
+/* Terminate the open connection to the remote debugger.
+ Use this when you want to detach and do something else
+ with your gdb. */
+static void
+rombug_detach (from_tty)
+ int from_tty;
+{
+ if (attach_flag) {
+ printf_monitor (GO_CMD);
+ attach_flag = 0;
+ }
+ pop_target(); /* calls rombug_close to do the real work */
+ if (from_tty)
+ printf ("Ending remote %s debugging\n", target_shortname);
+}
+
+/*
+ * Tell the remote machine to resume.
+ */
+static void
+rombug_resume (pid, step, sig)
+ int pid, step;
+ enum target_signal sig;
+{
+#ifdef LOG_FILE
+ fprintf (log_file, "\nIn Resume (step=%d, sig=%d)\n", step, sig);
+#endif
+
+ if (step)
+ {
+ is_trace_mode = 1;
+ printf_monitor (STEP_CMD);
+ /* wait for the echo. */
+ expect (STEP_CMD, 1);
+ }
+ else
+ {
+ printf_monitor (GO_CMD);
+ /* swallow the echo. */
+ expect (GO_CMD, 1);
+ }
+}
+
+/*
+ * Wait until the remote machine stops, then return,
+ * storing status in status just as `wait' would.
+ */
+
+static int
+rombug_wait (pid, status)
+ int pid;
+ struct target_waitstatus *status;
+{
+ int old_timeout = timeout;
+ struct section_offsets *offs;
+ CORE_ADDR addr, pc;
+ struct objfile *obj;
+
+#ifdef LOG_FILE
+ fputs ("\nIn wait ()", log_file);
+#endif
+
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0;
+
+ timeout = 0; /* Don't time out -- user program is running. */
+ expect_prompt(1); /* Wait for prompt, outputting extraneous text */
+
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ timeout = old_timeout;
+ rombug_fetch_registers();
+ pc = read_register(PC_REGNUM);
+ addr = read_register(DATABASE_REG);
+ obj = find_pc_objfile(pc);
+ if (obj != NULL)
+ new_symfile_objfile(obj, 1, 0);
+ offs = ((struct section_offsets *)
+ alloca (sizeof (struct section_offsets)
+ + (symfile_objfile->num_sections * sizeof (offs->offsets))));
+ memcpy (offs, symfile_objfile->section_offsets,
+ (sizeof (struct section_offsets) +
+ (symfile_objfile->num_sections * sizeof (offs->offsets))));
+ ANOFFSET (offs, SECT_OFF_DATA) = addr;
+ ANOFFSET (offs, SECT_OFF_BSS) = addr;
+
+ objfile_relocate_data(symfile_objfile, offs);
+
+ return 0;
+}
+
+/* Return the name of register number regno in the form input and output by
+ monitor. Currently, register_names just happens to contain exactly what
+ monitor wants. Lets take advantage of that just as long as possible! */
+
+static char *
+get_reg_name (regno)
+ int regno;
+{
+ static char buf[50];
+ char *p;
+ char *b;
+
+ b = buf;
+
+ if (regno < 0)
+ return ("");
+/*
+ for (p = reg_names[regno]; *p; p++)
+ *b++ = toupper(*p);
+ *b = '\000';
+*/
+ p = (char *)reg_names[regno];
+ return p;
+/*
+ return buf;
+*/
+}
+
+/* read the remote registers into the block regs. */
+
+static void
+rombug_fetch_registers ()
+{
+ int regno, j, i;
+ long val;
+ unsigned char b;
+
+ printf_monitor (GET_REG);
+ expect("eax:", 1);
+ expect("\n", 1);
+ get_hex_regs(1, 0);
+ get_hex_regs(1, 3);
+ get_hex_regs(1, 1);
+ get_hex_regs(1, 2);
+ get_hex_regs(1, 6);
+ get_hex_regs(1, 7);
+ get_hex_regs(1, 5);
+ get_hex_regs(1, 4);
+ for (regno = 8; regno <= 15; regno++)
+ {
+ expect(REG_DELIM, 1);
+ if (regno >= 8 && regno <= 13)
+ {
+ val = 0;
+ for (j = 0; j < 2; j++)
+ {
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ get_hex_byte(&b);
+ val = (val << 8) + b;
+#else
+ get_hex_byte(&b);
+ val = val + (b << (j*8));
+#endif
+ }
+
+ if (regno == 8) i = 10;
+ if (regno >= 9 && regno <= 12) i = regno + 3;
+ if (regno == 13) i = 11;
+ supply_register (i, (char *) &val);
+ }
+ else if (regno == 14)
+ {
+ get_hex_regs(1, PC_REGNUM);
+ }
+ else if (regno == 15)
+ {
+ get_hex_regs(1, 9);
+ }
+ else
+ {
+ val = 0;
+ supply_register(regno, (char *) &val);
+ }
+ }
+ expect_prompt (1);
+}
+
+/* Fetch register REGNO, or all registers if REGNO is -1.
+ Returns errno value. */
+static void
+rombug_fetch_register (regno)
+ int regno;
+{
+ int val, j;
+ unsigned char b;
+
+#ifdef LOG_FILE
+ fprintf (log_file, "\nIn Fetch Register (reg=%s)\n", get_reg_name (regno));
+ fflush (log_file);
+#endif
+
+ if (regno < 0)
+ {
+ rombug_fetch_registers ();
+ }
+ else
+ {
+ char *name = get_reg_name (regno);
+ printf_monitor (GET_REG);
+ if (regno >= 10 && regno <= 15)
+ {
+ expect ("\n", 1);
+ expect ("\n", 1);
+ expect (name, 1);
+ expect (REG_DELIM, 1);
+ val = 0;
+ for (j = 0; j < 2; j++)
+ {
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ get_hex_byte(&b);
+ val = (val << 8) + b;
+#else
+ get_hex_byte(&b);
+ val = val + (b << (j*8));
+#endif
+ }
+ supply_register (regno, (char *) &val);
+ }
+ else if (regno == 8 || regno == 9)
+ {
+ expect ("\n", 1);
+ expect ("\n", 1);
+ expect ("\n", 1);
+ expect (name, 1);
+ expect (REG_DELIM, 1);
+ get_hex_regs (1, regno);
+ }
+ else
+ {
+ expect (name, 1);
+ expect (REG_DELIM, 1);
+ expect("\n", 1);
+ get_hex_regs(1, 0);
+ get_hex_regs(1, 3);
+ get_hex_regs(1, 1);
+ get_hex_regs(1, 2);
+ get_hex_regs(1, 6);
+ get_hex_regs(1, 7);
+ get_hex_regs(1, 5);
+ get_hex_regs(1, 4);
+ }
+ expect_prompt (1);
+ }
+ return;
+}
+
+/* Store the remote registers from the contents of the block REGS. */
+
+static void
+rombug_store_registers ()
+{
+ int regno;
+
+ for (regno = 0; regno <= PC_REGNUM; regno++)
+ rombug_store_register(regno);
+
+ registers_changed ();
+}
+
+/* Store register REGNO, or all if REGNO == 0.
+ return errno value. */
+static void
+rombug_store_register (regno)
+ int regno;
+{
+char *name;
+
+#ifdef LOG_FILE
+ fprintf (log_file, "\nIn Store_register (regno=%d)\n", regno);
+#endif
+ if (regno == -1)
+ rombug_store_registers ();
+ else
+ {
+ if (sr_get_debug())
+ printf ("Setting register %s to 0x%x\n", get_reg_name (regno), read_register (regno));
+
+ name = get_reg_name(regno);
+ if (name == 0) return;
+ printf_monitor (SET_REG, name, read_register (regno));
+
+ expect_prompt (1);
+ }
+}
+
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On machines
+ which store all the registers in one fell swoop, this makes sure
+ that registers contains all the registers from the program being
+ debugged. */
+
+static void
+rombug_prepare_to_store ()
+{
+ /* Do nothing, since we can store individual regs */
+}
+
+static void
+rombug_files_info ()
+{
+ printf ("\tAttached to %s at %d baud.\n",
+ dev_name, baudrate);
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+ to inferior's memory at MEMADDR. Returns length moved. */
+static int
+rombug_write_inferior_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ unsigned char *myaddr;
+ int len;
+{
+ int i;
+ char buf[10];
+
+#ifdef LOG_FILE
+ fprintf (log_file, "\nIn Write_inferior_memory (memaddr=%x, len=%d)\n", memaddr, len);
+#endif
+ printf_monitor (MEM_SET_CMD, memaddr + i);
+ for (i = 0; i < len; i++)
+ {
+ expect (CMD_DELIM, 1);
+ printf_monitor ("%x", myaddr[i]);
+ if (sr_get_debug())
+ printf ("\nSet 0x%x to 0x%x\n", memaddr + i, myaddr[i]);
+ }
+ if (CMD_END)
+ printf_monitor (CMD_END);
+ expect_prompt (1);
+
+ return len;
+}
+
+/* Read LEN bytes from inferior memory at MEMADDR. Put the result
+ at debugger address MYADDR. Returns length moved. */
+static int
+rombug_read_inferior_memory(memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ int i, j;
+ char buf[20];
+
+ /* Number of bytes read so far. */
+ int count;
+
+ /* Starting address of this pass. */
+ unsigned long startaddr;
+
+ /* Number of bytes to read in this pass. */
+ int len_this_pass;
+
+#ifdef LOG_FILE
+ fprintf (log_file, "\nIn Read_inferior_memory (memaddr=%x, len=%d)\n", memaddr, len);
+#endif
+
+ /* Note that this code works correctly if startaddr is just less
+ than UINT_MAX (well, really CORE_ADDR_MAX if there was such a
+ thing). That is, something like
+ rombug_read_bytes (CORE_ADDR_MAX - 4, foo, 4)
+ works--it never adds len To memaddr and gets 0. */
+ /* However, something like
+ rombug_read_bytes (CORE_ADDR_MAX - 3, foo, 4)
+ doesn't need to work. Detect it and give up if there's an attempt
+ to do that. */
+ if (((memaddr - 1) + len) < memaddr) {
+ errno = EIO;
+ return 0;
+ }
+
+ startaddr = memaddr;
+ count = 0;
+ while (count < len)
+ {
+ len_this_pass = 16;
+ if ((startaddr % 16) != 0)
+ len_this_pass -= startaddr % 16;
+ if (len_this_pass > (len - count))
+ len_this_pass = (len - count);
+ if (sr_get_debug())
+ printf ("\nDisplay %d bytes at %x\n", len_this_pass, startaddr);
+
+ printf_monitor (MEM_DIS_CMD, startaddr, 16);
+ expect ("- ", 1);
+ for (i = 0; i < len_this_pass; i++)
+ {
+ get_hex_byte (&myaddr[count++]);
+ if (sr_get_debug())
+ printf ("\nRead a 0x%x from 0x%x\n", myaddr[count-1], startaddr);
+ startaddr += 1;
+ }
+ expect(CMD_DELIM, 1);
+ }
+ if (CMD_END)
+ printf_monitor (CMD_END);
+ expect_prompt (1);
+
+ return len;
+}
+
+/* FIXME-someday! merge these two. */
+static int
+rombug_xfer_inferior_memory (memaddr, myaddr, len, write, target)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int write;
+ struct target_ops *target; /* ignored */
+{
+ if (write)
+ return rombug_write_inferior_memory (memaddr, myaddr, len);
+ else
+ return rombug_read_inferior_memory (memaddr, myaddr, len);
+}
+
+static void
+rombug_kill (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ return; /* ignore attempts to kill target system */
+}
+
+/* Clean up when a program exits.
+ The program actually lives on in the remote processor's RAM, and may be
+ run again without a download. Don't leave it full of breakpoint
+ instructions. */
+
+static void
+rombug_mourn_inferior ()
+{
+ remove_breakpoints ();
+ generic_mourn_inferior (); /* Do all the proper things now */
+}
+
+#define MAX_MONITOR_BREAKPOINTS 16
+
+extern int memory_breakpoint_size;
+static CORE_ADDR breakaddr[MAX_MONITOR_BREAKPOINTS] = {0};
+
+static int
+rombug_insert_breakpoint (addr, shadow)
+ CORE_ADDR addr;
+ char *shadow;
+{
+ int i;
+
+#ifdef LOG_FILE
+ fprintf (log_file, "\nIn Insert_breakpoint (addr=%x)\n", addr);
+#endif
+ for (i = 0; i <= MAX_MONITOR_BREAKPOINTS; i++)
+ if (breakaddr[i] == 0)
+ {
+ breakaddr[i] = addr;
+ if (sr_get_debug())
+ printf ("Breakpoint at %x\n", addr);
+ rombug_read_inferior_memory(addr, shadow, memory_breakpoint_size);
+ printf_monitor(SET_BREAK_CMD, addr);
+ expect_prompt(1);
+ return 0;
+ }
+
+ fprintf(stderr, "Too many breakpoints (> 16) for monitor\n");
+ return 1;
+}
+
+/*
+ * _remove_breakpoint -- Tell the monitor to remove a breakpoint
+ */
+static int
+rombug_remove_breakpoint (addr, shadow)
+ CORE_ADDR addr;
+ char *shadow;
+{
+ int i;
+
+#ifdef LOG_FILE
+ fprintf (log_file, "\nIn Remove_breakpoint (addr=%x)\n", addr);
+#endif
+ for (i = 0; i < MAX_MONITOR_BREAKPOINTS; i++)
+ if (breakaddr[i] == addr)
+ {
+ breakaddr[i] = 0;
+ /* some monitors remove breakpoints based on the address */
+ if (strcasecmp (target_shortname, "bug") == 0)
+ printf_monitor(CLR_BREAK_CMD, addr);
+ else
+ printf_monitor(CLR_BREAK_CMD, i);
+ expect_prompt(1);
+ return 0;
+ }
+
+ fprintf(stderr, "Can't find breakpoint associated with 0x%x\n", addr);
+ return 1;
+}
+
+/* Load a file. This is usually an srecord, which is ascii. No
+ protocol, just sent line by line. */
+
+#define DOWNLOAD_LINE_SIZE 100
+static void
+rombug_load (arg)
+ char *arg;
+{
+/* this part comment out for os9* */
+#if 0
+ FILE *download;
+ char buf[DOWNLOAD_LINE_SIZE];
+ int i, bytes_read;
+
+ if (sr_get_debug())
+ printf ("Loading %s to monitor\n", arg);
+
+ download = fopen (arg, "r");
+ if (download == NULL)
+ {
+ error (sprintf (buf, "%s Does not exist", arg));
+ return;
+ }
+
+ printf_monitor (LOAD_CMD);
+/* expect ("Waiting for S-records from host... ", 1); */
+
+ while (!feof (download))
+ {
+ bytes_read = fread (buf, sizeof (char), DOWNLOAD_LINE_SIZE, download);
+ if (hashmark)
+ {
+ putchar ('.');
+ fflush (stdout);
+ }
+
+ if (SERIAL_WRITE(monitor_desc, buf, bytes_read)) {
+ fprintf(stderr, "SERIAL_WRITE failed: (while downloading) %s\n", safe_strerror(errno));
+ break;
+ }
+ i = 0;
+ while (i++ <=200000) {} ; /* Ugly HACK, probably needs flow control */
+ if (bytes_read < DOWNLOAD_LINE_SIZE)
+ {
+ if (!feof (download))
+ error ("Only read %d bytes\n", bytes_read);
+ break;
+ }
+ }
+
+ if (hashmark)
+ {
+ putchar ('\n');
+ }
+ if (!feof (download))
+ error ("Never got EOF while downloading");
+ fclose (download);
+#endif 0
+}
+
+/* Put a command string, in args, out to MONITOR.
+ Output from MONITOR is placed on the users terminal until the prompt
+ is seen. */
+
+static void
+rombug_command (args, fromtty)
+ char *args;
+ int fromtty;
+{
+#ifdef LOG_FILE
+ fprintf (log_file, "\nIn command (args=%s)\n", args);
+#endif
+ if (monitor_desc == NULL)
+ error("monitor target not open.");
+
+ if (!args)
+ error("Missing command.");
+
+ printf_monitor("%s\r", args);
+ expect_prompt(0);
+}
+
+#if 0
+/* Connect the user directly to MONITOR. This command acts just like the
+ 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
+
+static struct ttystate ttystate;
+
+static void
+cleanup_tty()
+{ printf("\r\n[Exiting connect mode]\r\n");
+ /*SERIAL_RESTORE(0, &ttystate);*/
+}
+
+static void
+connect_command (args, fromtty)
+ char *args;
+ int fromtty;
+{
+ fd_set readfds;
+ int numfds;
+ int c;
+ char cur_esc = 0;
+
+ dont_repeat();
+
+ if (monitor_desc == NULL)
+ error("monitor target not open.");
+
+ if (args)
+ fprintf("This command takes no args. They have been ignored.\n");
+
+ printf("[Entering connect mode. Use ~. or ~^D to escape]\n");
+
+ serial_raw(0, &ttystate);
+
+ make_cleanup(cleanup_tty, 0);
+
+ FD_ZERO(&readfds);
+
+ while (1)
+ {
+ do
+ {
+ FD_SET(0, &readfds);
+ FD_SET(monitor_desc, &readfds);
+ numfds = select(sizeof(readfds)*8, &readfds, 0, 0, 0);
+ }
+ while (numfds == 0);
+
+ if (numfds < 0)
+ perror_with_name("select");
+
+ if (FD_ISSET(0, &readfds))
+ { /* tty input, send to monitor */
+ c = getchar();
+ if (c < 0)
+ perror_with_name("connect");
+
+ printf_monitor("%c", c);
+ switch (cur_esc)
+ {
+ case 0:
+ if (c == '\r')
+ cur_esc = c;
+ break;
+ case '\r':
+ if (c == '~')
+ cur_esc = c;
+ else
+ cur_esc = 0;
+ break;
+ case '~':
+ if (c == '.' || c == '\004')
+ return;
+ else
+ cur_esc = 0;
+ }
+ }
+
+ if (FD_ISSET(monitor_desc, &readfds))
+ {
+ while (1)
+ {
+ c = readchar(0);
+ if (c < 0)
+ break;
+ putchar(c);
+ }
+ fflush(stdout);
+ }
+ }
+}
+#endif
+
+/*
+ * Define the monitor command strings. Since these are passed directly
+ * through to a printf style function, we need can include formatting
+ * strings. We also need a CR or LF on the end.
+ */
+struct monitor_ops rombug_cmds = {
+ "g \r", /* execute or usually GO command */
+ "g \r", /* continue command */
+ "gs \r", /* single step */
+ "b %x\r", /* set a breakpoint */
+ "k %x\r", /* clear a breakpoint */
+ "c %x\r", /* set memory to a value */
+ "d %x %d\r", /* display memory */
+ "$%08X", /* prompt memory commands use */
+ ".%s %x\r", /* set a register */
+ ":", /* delimiter between registers */
+ ". \r", /* read a register */
+ "mf \r", /* download command */
+ "RomBug: ", /* monitor command prompt */
+ ": ", /* end-of-command delimitor */
+ ".\r" /* optional command terminator */
+};
+
+struct target_ops rombug_ops = {
+ "rombug",
+ "Microware's ROMBUG debug monitor",
+ "Use a remote computer running the ROMBUG debug monitor.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).",
+ rombug_open,
+ rombug_close,
+ 0,
+ rombug_detach,
+ rombug_resume,
+ rombug_wait,
+ rombug_fetch_register,
+ rombug_store_register,
+ rombug_prepare_to_store,
+ rombug_xfer_inferior_memory,
+ rombug_files_info,
+ rombug_insert_breakpoint,
+ rombug_remove_breakpoint, /* Breakpoints */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, /* Terminal handling */
+ rombug_kill,
+ rombug_load, /* load */
+ rombug_link, /* lookup_symbol */
+ rombug_create_inferior,
+ rombug_mourn_inferior,
+ 0, /* can_run */
+ 0, /* notice_signals */
+ process_stratum,
+ 0, /* next */
+ 1,
+ 1,
+ 1,
+ 1,
+ 1, /* has execution */
+ 0,
+ 0, /* Section pointers */
+ OPS_MAGIC, /* Always the last thing */
+};
+
+void
+_initialize_remote_os9k ()
+{
+ add_target (&rombug_ops);
+
+ add_show_from_set (
+ add_set_cmd ("hash", no_class, var_boolean, (char *)&hashmark,
+ "Set display of activity while downloading a file.\nWhen enabled, a period \'.\' is displayed.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("timeout", no_class, var_zinteger,
+ (char *) &timeout,
+ "Set timeout in seconds for remote MIPS serial I/O.",
+ &setlist),
+ &showlist);
+
+
+ add_com ("rombug <command>", class_obscure, rombug_command,
+ "Send a command to the debug monitor.");
+#if 0
+ add_com ("connect", class_obscure, connect_command,
+ "Connect the terminal directly up to a serial based command monitor.\nUse <CR>~. or <CR>~^D to break out.");
+#endif
+}
diff --git a/gdb/symfile.c b/gdb/symfile.c
index a0d7095..cb998bf 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -48,7 +48,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#endif
/* Global variables owned by this file */
-
+CORE_ADDR text_relocation = 0; /* text_relocation */
int readnow_symbol_files; /* Read full symbols immediately */
struct complaint oldsyms_complaint = {
@@ -675,7 +675,23 @@ symbol_file_command (args, from_tty)
}
else
{
+ char *p;
+
name = *argv;
+
+ /* this is for rombug remote only, to get the text relocation by
+ using link command */
+ p = strrchr(name, '/');
+ if (p != NULL) p++;
+ else p = name;
+
+ target_link(p, &text_relocation);
+
+ if (text_relocation)
+ symbol_file_add (name, from_tty, (CORE_ADDR)text_relocation, 0, mapped, readnow);
+ else
+ symbol_file_add (name, from_tty, (CORE_ADDR)0, 1, mapped, readnow);
+ set_initial_language ();
}
argv++;
}
@@ -684,11 +700,6 @@ symbol_file_command (args, from_tty)
{
error ("no symbol file name was specified");
}
- else
- {
- symbol_file_add (name, from_tty, (CORE_ADDR)0, 1, mapped, readnow);
- set_initial_language ();
- }
do_cleanups (cleanups);
}
}
@@ -972,14 +983,23 @@ add_symbol_file_command (args, from_tty)
left pointing at the remainder of the command line, which should
be the address expression to evaluate. */
- if ((name == NULL) || (*args == '\000') )
+ if (name == NULL)
{
- error ("add-symbol-file takes a file name and an address");
+ error ("add-symbol-file takes a file name");
}
name = tilde_expand (name);
make_cleanup (free, name);
- text_addr = parse_and_eval_address (args);
+ if (*args != '\000')
+ {
+ text_addr = parse_and_eval_address (args);
+ }
+ else
+ {
+ target_link(name, &text_addr);
+ if (text_addr == (CORE_ADDR)-1)
+ error("Don't know how to get text start location for this file");
+ }
/* FIXME-32x64: Assumes text_addr fits in a long. */
if (!query ("add symbol table from file \"%s\" at text_addr = %s?\n",
@@ -1078,10 +1098,12 @@ reread_symbols ()
if (objfile->global_psymbols.list)
mfree (objfile->md, objfile->global_psymbols.list);
objfile->global_psymbols.list = NULL;
+ objfile->global_psymbols.next = NULL;
objfile->global_psymbols.size = 0;
if (objfile->static_psymbols.list)
mfree (objfile->md, objfile->static_psymbols.list);
objfile->static_psymbols.list = NULL;
+ objfile->static_psymbols.next = NULL;
objfile->static_psymbols.size = 0;
/* Free the obstacks for non-reusable objfiles */
diff --git a/gdb/target.c b/gdb/target.c
index 038ca0d..456fffd 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -710,6 +710,19 @@ target_detach (args, from_tty)
(current_target->to_detach) (args, from_tty);
}
+void
+target_link (modname, t_reloc)
+ char *modname;
+ CORE_ADDR *t_reloc;
+{
+ if (STREQ(current_target->to_shortname, "rombug"))
+ {
+ (current_target->to_lookup_symbol) (modname, t_reloc);
+ }
+ else
+ *t_reloc = (CORE_ADDR)-1;
+}
+
/* Look through the list of possible targets for a target that can
execute a run or attach command without any other data. This is
used to locate the default process stratum.