/* 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)
return debug_make_int_type (dhandle, 1, true);
else if (n3 == 0xffff)
return debug_make_int_type (dhandle, 2, true);
- /* -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. */
+ else if (n3 == 0xffffffff)
+ return debug_make_int_type (dhandle, 4, true);
+#ifdef BFD64
+ else if (n3 == (((bfd_vma) 0xffffffff) << 32) | 0xffffffff)
+ return debug_make_int_type (dhandle, 8, true);
+#endif
}
else if (n3 == 0
&& n2 < 0
&& (self_subrange || n2 == -8))
return debug_make_int_type (dhandle, - n2, true);
- else if (n2 == - n3 - 1)
+ else if (n2 == - n3 - 1 || n2 == n3 + 1)
{
if (n3 == 0x7f)
return debug_make_int_type (dhandle, 1, false);
return debug_make_int_type (dhandle, 2, false);
else if (n3 == 0x7fffffff)
return debug_make_int_type (dhandle, 4, false);
+#ifdef BFD64
+ else if (n3 == (((bfd_vma) 0x7fffffff) << 32) | 0xffffffff)
+ return debug_make_int_type (dhandle, 8, false);
+#endif
}
}
{
/* 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)
static boolean stab_demangle_qualified
PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
static boolean stab_demangle_template
- PARAMS ((struct stab_demangle_info *, const char **));
+ PARAMS ((struct stab_demangle_info *, const char **, char **));
static boolean stab_demangle_class
PARAMS ((struct stab_demangle_info *, const char **, const char **));
static boolean stab_demangle_args
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;
/* Template. */
if (hold == NULL)
hold = *pp;
- if (! stab_demangle_template (minfo, pp)
+ if (! stab_demangle_template (minfo, pp, (char **) NULL)
|| ! stab_demangle_remember_type (minfo, hold, *pp - hold))
return false;
hold = NULL;
++*pp;
if (**pp == 't')
{
- /* FIXME: I don't know how to handle the ptype != NULL case
- here. */
- if (! stab_demangle_template (minfo, pp))
+ char *name;
+
+ if (! stab_demangle_template (minfo, pp,
+ ptype != NULL ? &name : NULL))
return false;
+
+ if (ptype != NULL)
+ {
+ context = stab_find_tagged_type (minfo->dhandle, minfo->info,
+ name, strlen (name),
+ DEBUG_KIND_CLASS);
+ free (name);
+ if (context == DEBUG_TYPE_NULL)
+ return false;
+ }
}
else
{
if (context == DEBUG_TYPE_NULL)
{
- /* We have to fall back on finding the type by name.
+ /* We have to fall back on finding the type by name.
If there are more types to come, then this must
be a class. Otherwise, it could be anything. */
return true;
}
-/* Demangle a template. */
+/* Demangle a template. If PNAME is not NULL, this sets *PNAME to a
+ string representation of the template. */
static boolean
-stab_demangle_template (minfo, pp)
+stab_demangle_template (minfo, pp, pname)
struct stab_demangle_info *minfo;
const char **pp;
+ char **pname;
{
const char *orig;
unsigned int r, i;
}
}
+ /* We can translate this to a string fairly easily by invoking the
+ regular demangling routine. */
+ if (pname != NULL)
+ {
+ char *s1, *s2, *s3, *s4;
+
+ s1 = savestring (orig, *pp - orig);
+
+ s2 = concat ("NoSuchStrinG__", s1, (const char *) NULL);
+
+ free (s1);
+
+ s3 = cplus_demangle (s2, DMGL_ANSI);
+
+ free (s2);
+
+ if (s3 != NULL)
+ s4 = strstr (s3, "::NoSuchStrinG");
+ if (s3 == NULL || s4 == NULL)
+ {
+ stab_bad_demangle (orig);
+ if (s3 != NULL)
+ free (s3);
+ return false;
+ }
+
+ *pname = savestring (s3, s4 - s3);
+
+ free (s3);
+ }
+
return true;
}
name = savestring (hold, *pp - hold);
*ptype = debug_find_named_type (minfo->dhandle, name);
+ free (name);
if (*ptype == DEBUG_TYPE_NULL)
{
/* FIXME: It is probably incorrect to assume that
*ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
hold, *pp - hold,
DEBUG_KIND_ILLEGAL);
+ if (*ptype == DEBUG_TYPE_NULL)
+ return false;
}
- free (name);
}
}
break;
case 't':
- if (! stab_demangle_template (minfo, pp))
- return false;
- if (ptype != NULL)
- {
- debug_type t;
-
- /* FIXME: I really don't know how a template should be
- represented in the current type system. Perhaps the
- template should be demangled into a string, and the type
- should be represented as a named type. However, I don't
- know what the base type of the named type should be. */
- t = debug_make_void_type (minfo->dhandle);
- t = debug_make_pointer_type (minfo->dhandle, t);
- t = debug_name_type (minfo->dhandle, "TEMPLATE", t);
- *ptype = t;
- }
+ {
+ char *name;
+
+ if (! stab_demangle_template (minfo, pp,
+ ptype != NULL ? &name : NULL))
+ return false;
+ if (ptype != NULL)
+ {
+ *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
+ name, strlen (name),
+ DEBUG_KIND_CLASS);
+ free (name);
+ if (*ptype == DEBUG_TYPE_NULL)
+ return false;
+ }
+ }
break;
default: