/* stabs.c -- Parse stabs debugging information
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GNU Binutils.
#include "aout/aout64.h"
#include "aout/stab_gnu.h"
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
/* The number of predefined XCOFF types. */
#define XCOFF_TYPE_COUNT 34
boolean n_opt_found;
/* The main file name. */
char *main_filename;
- /* A stack of N_BINCL files. */
+ /* A stack of unfinished N_BINCL files. */
struct bincl_file *bincl_stack;
+ /* A list of finished N_BINCL files. */
+ struct bincl_file *bincl_list;
/* Whether we are inside a function or not. */
boolean within_function;
/* The address of the end of the function, used if we have seen an
debug_type xcoff_types[XCOFF_TYPE_COUNT];
/* Undefined tags. */
struct stab_tag *tags;
+ /* Set by parse_stab_type if it sees a structure defined as a cross
+ reference to itself. Reset by parse_stab_type otherwise. */
+ boolean self_crossref;
};
/* A list of these structures is used to hold pending variable
debug_type *, boolean *));
static debug_type parse_stab_array_type
PARAMS ((PTR, struct stab_handle *, const char **, boolean));
-static void push_bincl PARAMS ((struct stab_handle *, const char *));
+static void push_bincl PARAMS ((struct stab_handle *, const char *, bfd_vma));
static const char *pop_bincl PARAMS ((struct stab_handle *));
+static boolean find_excl
+ PARAMS ((struct stab_handle *, const char *, bfd_vma));
static boolean stab_record_variable
PARAMS ((PTR, struct stab_handle *, const char *, debug_type,
enum debug_var_kind, bfd_vma));
errno = 0;
ul = strtoul (*pp, (char **) pp, 0);
if (ul + 1 != 0 || errno == 0)
- return (bfd_vma) ul;
+ {
+ /* If bfd_vma is larger than unsigned long, and the number is
+ meant to be negative, we have to make sure that we sign
+ extend properly. */
+ if (*orig == '-')
+ return (bfd_vma) (bfd_signed_vma) (long) ul;
+ return (bfd_vma) ul;
+ }
/* Note that even though strtoul overflowed, it should have set *pp
to the end of the number, which is where we want it. */
if (poverflow != NULL)
*poverflow = true;
else
- warn_stab (orig, "numeric overflow");
+ warn_stab (orig, _("numeric overflow"));
return 0;
}
bad_stab (p)
const char *p;
{
- fprintf (stderr, "Bad stab: %s\n", p);
+ fprintf (stderr, _("Bad stab: %s\n"), p);
}
/* Warn about something in a stab string. */
const char *p;
const char *err;
{
- fprintf (stderr, "Warning: %s: %s\n", err, p);
+ fprintf (stderr, _("Warning: %s: %s\n"), err, p);
}
/* Create a handle to parse stabs symbols with. */
if (! info->within_function)
{
- fprintf (stderr, "N_LBRAC not within function\n");
+ fprintf (stderr, _("N_LBRAC not within function\n"));
return false;
}
--info->block_depth;
if (info->block_depth < 0)
{
- fprintf (stderr, "Too many N_RBRACs\n");
+ fprintf (stderr, _("Too many N_RBRACs\n"));
return false;
}
break;
return true;
/* Just accumulate strings until we see a non N_SO symbol. If
- the string starts with '/', we discard the previously
+ the string starts with a directory separator or some other
+ form of absolute path specification, we discard the previously
accumulated strings. */
if (info->so_string == NULL)
info->so_string = xstrdup (string);
char *f;
f = info->so_string;
- if (*string == '/')
+
+ if ( (string[0] == '/')
+ || (string[0] == DIR_SEPARATOR)
+ || ( (DIR_SEPARATOR == '\\')
+ && (string[1] == ':')
+ && ( (string[2] == DIR_SEPARATOR)
+ || (string[2] == '/'))))
info->so_string = xstrdup (string);
else
info->so_string = concat (info->so_string, string,
case N_BINCL:
/* Start an include file which may be replaced. */
- push_bincl (info, string);
+ push_bincl (info, string, value);
if (! debug_start_source (dhandle, string))
return false;
break;
case N_EXCL:
/* This is a duplicate of a header file named by N_BINCL which
was eliminated by the linker. */
- ++info->files;
- info->file_types = ((struct stab_types **)
- xrealloc ((PTR) info->file_types,
- (info->files
- * sizeof *info->file_types)));
- info->file_types[info->files - 1] = NULL;
+ if (! find_excl (info, string, value))
+ return false;
break;
case N_SLINE:
int type;
debug_type dtype;
boolean synonym;
+ boolean self_crossref;
unsigned int lineno;
debug_type *slot;
/* SunPRO (3.0 at least) static variable encoding. */
break;
default:
- warn_stab (string, "unknown C++ encoded name");
+ warn_stab (string, _("unknown C++ encoded name"));
break;
}
}
if (name == NULL)
return true;
+ /* INFO->SELF_CROSSREF is set by parse_stab_type if this type is
+ a cross reference to itself. These are generated by some
+ versions of g++. */
+ self_crossref = info->self_crossref;
+
dtype = debug_tag_type (dhandle, name, dtype);
if (dtype == DEBUG_TYPE_NULL)
return false;
*slot = dtype;
/* See if we have a cross reference to this tag which we can now
- fill in. */
- {
- register struct stab_tag **pst;
+ fill in. Avoid filling in a cross reference to ourselves,
+ because that would lead to circular debugging information. */
+ if (! self_crossref)
+ {
+ register struct stab_tag **pst;
- for (pst = &info->tags; *pst != NULL; pst = &(*pst)->next)
- {
- if ((*pst)->name[0] == name[0]
- && strcmp ((*pst)->name, name) == 0)
- {
- (*pst)->slot = dtype;
- *pst = (*pst)->next;
- break;
- }
- }
- }
+ for (pst = &info->tags; *pst != NULL; pst = &(*pst)->next)
+ {
+ if ((*pst)->name[0] == name[0]
+ && strcmp ((*pst)->name, name) == 0)
+ {
+ (*pst)->slot = dtype;
+ *pst = (*pst)->next;
+ break;
+ }
+ }
+ }
if (synonym)
{
size = -1;
stringp = false;
+ info->self_crossref = false;
+
/* 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". */
default:
/* Complain and keep going, so compilers can invent new
cross-reference types. */
- warn_stab (orig, "unrecognized cross reference type");
+ warn_stab (orig, _("unrecognized cross reference type"));
code = DEBUG_KIND_STRUCT;
break;
}
}
}
+ /* Some versions of g++ can emit stabs like
+ fleep:T20=xsfleep:
+ which define structures in terms of themselves. We need to
+ tell the caller to avoid building a circular structure. */
+ if (typename != NULL
+ && strncmp (typename, *pp, p - *pp) == 0
+ && typename[p - *pp] == '\0')
+ info->self_crossref = true;
+
dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code);
*pp = p + 1;
return debug_make_int_type (dhandle, 8, true);
}
- warn_stab (orig, "numeric overflow");
+ warn_stab (orig, _("numeric overflow"));
}
if (index_type == DEBUG_TYPE_NULL)
{
/* Does this actually ever happen? Is that why we are worrying
about dealing with it rather than just calling error_type? */
- warn_stab (orig, "missing index type");
+ warn_stab (orig, _("missing index type"));
index_type = debug_make_int_type (dhandle, 4, false);
}
virtual = true;
break;
default:
- warn_stab (orig, "unknown virtual character for baseclass");
+ warn_stab (orig, _("unknown virtual character for baseclass"));
virtual = false;
break;
}
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
default:
- warn_stab (orig, "unknown visibility character for baseclass");
+ warn_stab (orig, _("unknown visibility character for baseclass"));
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
}
typename = debug_get_type_name (dhandle, context);
if (typename == NULL)
{
- warn_stab (orig, "unnamed $vb type");
+ warn_stab (orig, _("unnamed $vb type"));
typename = "FOO";
}
name = concat ("_vb$", typename, (const char *) NULL);
break;
default:
- warn_stab (orig, "unrecognized C++ abbreviation");
+ warn_stab (orig, _("unrecognized C++ abbreviation"));
name = "INVALID_CPLUSPLUS_ABBREV";
break;
}
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
default:
- warn_stab (orig, "unknown visibility character for field");
+ warn_stab (orig, _("unknown visibility character for field"));
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
}
/* File compiled with g++ version 1; no information. */
break;
default:
- warn_stab (orig, "const/volatile indicator missing");
+ warn_stab (orig, _("const/volatile indicator missing"));
break;
}
opname = cplus_mangle_opname (fieldname + 3, 0);
if (opname == NULL)
{
- fprintf (stderr, "No mangling for \"%s\"\n", fieldname);
+ fprintf (stderr, _("No mangling for \"%s\"\n"), fieldname);
return DEBUG_TYPE_NULL;
}
mangled_name_len += strlen (opname);
*pphysname = physname;
}
- if (*argtypes == '\0')
+ if (*argtypes == '\0' || is_destructor)
{
args = (debug_type *) xmalloc (sizeof *args);
*args = NULL;
upper, stringp);
}
-/* Keep a stack of N_BINCL include files. */
+/* This struct holds information about files we have seen using
+ N_BINCL. */
struct bincl_file
{
+ /* The next N_BINCL file. */
struct bincl_file *next;
+ /* The next N_BINCL on the stack. */
+ struct bincl_file *next_stack;
+ /* The file name. */
const char *name;
+ /* The hash value. */
+ bfd_vma hash;
+ /* The file index. */
+ unsigned int file;
+ /* The list of types defined in this file. */
+ struct stab_types *file_types;
};
/* Start a new N_BINCL file, pushing it onto the stack. */
static void
-push_bincl (info, name)
+push_bincl (info, name, hash)
struct stab_handle *info;
const char *name;
+ bfd_vma hash;
{
struct bincl_file *n;
n = (struct bincl_file *) xmalloc (sizeof *n);
- n->next = info->bincl_stack;
+ n->next = info->bincl_list;
+ n->next_stack = info->bincl_stack;
n->name = name;
+ n->hash = hash;
+ n->file = info->files;
+ n->file_types = NULL;
+ info->bincl_list = n;
info->bincl_stack = n;
++info->files;
xrealloc ((PTR) info->file_types,
(info->files
* sizeof *info->file_types)));
- info->file_types[info->files - 1] = NULL;
+ info->file_types[n->file] = NULL;
}
/* Finish an N_BINCL file, at an N_EINCL, popping the name off the
o = info->bincl_stack;
if (o == NULL)
return info->main_filename;
- info->bincl_stack = o->next;
- free (o);
+ info->bincl_stack = o->next_stack;
+
+ o->file_types = info->file_types[o->file];
+
if (info->bincl_stack == NULL)
return info->main_filename;
return info->bincl_stack->name;
}
+/* Handle an N_EXCL: get the types from the corresponding N_BINCL. */
+
+static boolean
+find_excl (info, name, hash)
+ struct stab_handle *info;
+ const char *name;
+ bfd_vma hash;
+{
+ struct bincl_file *l;
+
+ ++info->files;
+ info->file_types = ((struct stab_types **)
+ xrealloc ((PTR) info->file_types,
+ (info->files
+ * sizeof *info->file_types)));
+
+ for (l = info->bincl_list; l != NULL; l = l->next)
+ if (l->hash == hash && strcmp (l->name, name) == 0)
+ break;
+ if (l == NULL)
+ {
+ warn_stab (name, _("Undefined N_EXCL"));
+ info->file_types[info->files - 1] = NULL;
+ return true;
+ }
+
+ info->file_types[info->files - 1] = l->file_types;
+
+ return true;
+}
+
/* Handle a variable definition. gcc emits variable definitions for a
block before the N_LBRAC, so we must hold onto them until we see
it. The SunPRO compiler emits variable definitions after the
if (filenum < 0 || (unsigned int) filenum >= info->files)
{
- fprintf (stderr, "Type file number %d out of range\n", filenum);
+ fprintf (stderr, _("Type file number %d out of range\n"), filenum);
return NULL;
}
if (index < 0)
{
- fprintf (stderr, "Type index number %d out of range\n", index);
+ fprintf (stderr, _("Type index number %d out of range\n"), index);
return NULL;
}
if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT)
{
- fprintf (stderr, "Unrecognized XCOFF type %d\n", typenum);
+ fprintf (stderr, _("Unrecognized XCOFF type %d\n"), typenum);
return DEBUG_TYPE_NULL;
}
if (info->xcoff_types[-typenum] != NULL)
stab_bad_demangle (s)
const char *s;
{
- fprintf (stderr, "bad mangled name `%s'\n", s);
+ fprintf (stderr, _("bad mangled name `%s'\n"), s);
}
/* Get a count from a stab string. */
minfo.typestrings = NULL;
if (minfo.args == NULL)
- fprintf (stderr, "no argument types in mangled string\n");
+ fprintf (stderr, _("no argument types in mangled string\n"));
*pvarargs = minfo.varargs;
return minfo.args;