📄 stabs.c
字号:
/* stabs.c -- Parse stabs debugging information
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 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., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* This file contains code which parses stabs debugging information.
The organization of this code is based on the gdb stabs reading
code. The job it does is somewhat different, because it is not
trying to identify the correct address for anything. */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <bfd.h>
#include "bucomm.h"
#include <libiberty.h>
#include "demangle.h"
#include "debug.h"
#include "budbg.h"
#include "filenames.h"
/* Meaningless definition needs by aout64.h. FIXME. */
#define BYTES_IN_WORD 4
#include <stab.h>
#include "aout64.h"
//#include "aout/aout64.h"
//#include "aout/stab_gnu.h"
/* The number of predefined XCOFF types. */
#define XCOFF_TYPE_COUNT 34
/* This structure is used as a handle so that the stab parsing doesn't
need to use any static variables. */
struct stab_handle
{
/* The BFD. */
bfd *abfd;
/* True if this is stabs in sections. */
bfd_boolean sections;
/* The symbol table. */
asymbol **syms;
/* The number of symbols. */
long symcount;
/* The hashtable of symbols */
struct bfd_hash_table table;
/* The accumulated file name string. */
char *so_string;
/* The value of the last N_SO symbol. */
bfd_vma so_value;
/* The value of the start of the file, so that we can handle file
relative N_LBRAC and N_RBRAC symbols. */
bfd_vma file_start_offset;
/* The offset of the start of the function, so that we can handle
function relative N_LBRAC and N_RBRAC symbols. */
bfd_vma function_start_offset;
/* The version number of gcc which compiled the current compilation
unit, 0 if not compiled by gcc. */
int gcc_compiled;
/* Whether an N_OPT symbol was seen that was not generated by gcc,
so that we can detect the SunPRO compiler. */
bfd_boolean n_opt_found;
/* The main file name. */
char *main_filename;
/* 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. */
bfd_boolean within_function;
/* The address of the end of the function, used if we have seen an
N_FUN symbol while in a function. This is -1 if we have not seen
an N_FUN (the normal case). */
bfd_vma function_end;
/* The depth of block nesting. */
int block_depth;
/* List of pending variable definitions. */
struct stab_pending_var *pending;
/* Number of files for which we have types. */
unsigned int files;
/* Lists of types per file. */
struct stab_types **file_types;
/* Predefined XCOFF types. */
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. */
bfd_boolean self_crossref;
};
/* A list of these structures is used to hold pending variable
definitions seen before the N_LBRAC of a block. */
struct stab_pending_var
{
/* Next pending variable definition. */
struct stab_pending_var *next;
/* Name. */
const char *name;
/* Type. */
debug_type type;
/* Kind. */
enum debug_var_kind kind;
/* Value. */
bfd_vma val;
};
/* A list of these structures is used to hold the types for a single
file. */
struct stab_types
{
/* Next set of slots for this file. */
struct stab_types *next;
/* Types indexed by type number. */
#define STAB_TYPES_SLOTS (16)
debug_type types[STAB_TYPES_SLOTS];
};
/* We keep a list of undefined tags that we encounter, so that we can
fill them in if the tag is later defined. */
struct stab_tag
{
/* Next undefined tag. */
struct stab_tag *next;
/* Tag name. */
const char *name;
/* Type kind. */
enum debug_type_kind kind;
/* Slot to hold real type when we discover it. If we don't, we fill
in an undefined tag type. */
debug_type slot;
/* Indirect type we have created to point at slot. */
debug_type type;
};
static char *savestring PARAMS ((const char *, int));
static bfd_vma parse_number PARAMS ((const char **, bfd_boolean *));
static void bad_stab PARAMS ((const char *));
static void warn_stab PARAMS ((const char *, const char *));
static bfd_boolean parse_stab_string
PARAMS ((PTR, struct stab_handle *, int, int, bfd_vma, const char *));
static debug_type parse_stab_type
PARAMS ((PTR, struct stab_handle *, const char *, const char **,
debug_type **));
static bfd_boolean parse_stab_type_number
PARAMS ((const char **, int *));
static debug_type parse_stab_range_type
PARAMS ((PTR, struct stab_handle *, const char *, const char **,
const int *));
static debug_type parse_stab_sun_builtin_type PARAMS ((PTR, const char **));
static debug_type parse_stab_sun_floating_type
PARAMS ((PTR, const char **));
static debug_type parse_stab_enum_type PARAMS ((PTR, const char **));
static debug_type parse_stab_struct_type
PARAMS ((PTR, struct stab_handle *, const char *, const char **, bfd_boolean,
const int *));
static bfd_boolean parse_stab_baseclasses
PARAMS ((PTR, struct stab_handle *, const char **, debug_baseclass **));
static bfd_boolean parse_stab_struct_fields
PARAMS ((PTR, struct stab_handle *, const char **, debug_field **,
bfd_boolean *));
static bfd_boolean parse_stab_cpp_abbrev
PARAMS ((PTR, struct stab_handle *, const char **, debug_field *));
static bfd_boolean parse_stab_one_struct_field
PARAMS ((PTR, struct stab_handle *, const char **, const char *,
debug_field *, bfd_boolean *));
static bfd_boolean parse_stab_members
PARAMS ((PTR, struct stab_handle *, const char *, const char **,
const int *, debug_method **));
static debug_type parse_stab_argtypes
PARAMS ((PTR, struct stab_handle *, debug_type, const char *, const char *,
debug_type, const char *, bfd_boolean, bfd_boolean, const char **));
static bfd_boolean parse_stab_tilde_field
PARAMS ((PTR, struct stab_handle *, const char **, const int *,
debug_type *, bfd_boolean *));
static debug_type parse_stab_array_type
PARAMS ((PTR, struct stab_handle *, const char **, bfd_boolean));
static void push_bincl PARAMS ((struct stab_handle *, const char *, bfd_vma));
static const char *pop_bincl PARAMS ((struct stab_handle *));
static bfd_boolean find_excl
PARAMS ((struct stab_handle *, const char *, bfd_vma));
static bfd_boolean stab_record_variable
PARAMS ((PTR, struct stab_handle *, const char *, debug_type,
enum debug_var_kind, bfd_vma));
static bfd_boolean stab_emit_pending_vars PARAMS ((PTR, struct stab_handle *));
static debug_type *stab_find_slot
PARAMS ((struct stab_handle *, const int *));
static debug_type stab_find_type
PARAMS ((PTR, struct stab_handle *, const int *));
static bfd_boolean stab_record_type
PARAMS ((PTR, struct stab_handle *, const int *, debug_type));
static debug_type stab_xcoff_builtin_type
PARAMS ((PTR, struct stab_handle *, int));
static debug_type stab_find_tagged_type
PARAMS ((PTR, struct stab_handle *, const char *, int,
enum debug_type_kind));
static debug_type *stab_demangle_argtypes
PARAMS ((PTR, struct stab_handle *, const char *, bfd_boolean *));
/* Save a string in memory. */
static char *
savestring (start, len)
const char *start;
int len;
{
char *ret;
ret = (char *) xmalloc (len + 1);
memcpy (ret, start, len);
ret[len] = '\0';
return ret;
}
/* Read a number from a string. */
static bfd_vma
parse_number (pp, poverflow)
const char **pp;
bfd_boolean *poverflow;
{
unsigned long ul;
const char *orig;
if (poverflow != NULL)
*poverflow = false;
orig = *pp;
errno = 0;
ul = strtoul (*pp, (char **) pp, 0);
if (ul + 1 != 0 || errno == 0)
{
/* 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 (sizeof (bfd_vma) > sizeof (unsigned long))
{
const char *p;
bfd_boolean neg;
int base;
bfd_vma over, lastdig;
bfd_boolean overflow;
bfd_vma v;
/* Our own version of strtoul, for a bfd_vma. */
p = orig;
neg = false;
if (*p == '+')
++p;
else if (*p == '-')
{
neg = true;
++p;
}
base = 10;
if (*p == '0')
{
if (p[1] == 'x' || p[1] == 'X')
{
base = 16;
p += 2;
}
else
{
base = 8;
++p;
}
}
over = ((bfd_vma) (bfd_signed_vma) -1) / (bfd_vma) base;
lastdig = ((bfd_vma) (bfd_signed_vma) -1) % (bfd_vma) base;
overflow = false;
v = 0;
while (1)
{
int d;
d = *p++;
if (isdigit ((unsigned char) d))
d -= '0';
else if (isupper ((unsigned char) d))
d -= 'A';
else if (islower ((unsigned char) d))
d -= 'a';
else
break;
if (d >= base)
break;
if (v > over || (v == over && (bfd_vma) d > lastdig))
{
overflow = true;
break;
}
}
if (! overflow)
{
if (neg)
v = - v;
return v;
}
}
/* If we get here, the number is too large to represent in a
bfd_vma. */
if (poverflow != NULL)
*poverflow = true;
else
warn_stab (orig, _("numeric overflow"));
return 0;
}
/* Give an error for a bad stab string. */
static void
bad_stab (p)
const char *p;
{
fprintf (stderr, _("Bad stab: %s\n"), p);
}
/* Warn about something in a stab string. */
static void
warn_stab (p, err)
const char *p;
const char *err;
{
fprintf (stderr, _("Warning: %s: %s\n"), err, p);
}
/* Create a handle to parse stabs symbols with. */
/*ARGSUSED*/
PTR
start_stab (dhandle, abfd, sections, syms, symcount)
PTR dhandle ATTRIBUTE_UNUSED;
bfd *abfd;
bfd_boolean sections;
asymbol **syms;
long symcount;
{
struct stab_handle *ret;
int i;
ret = (struct stab_handle *) xmalloc (sizeof *ret);
memset (ret, 0, sizeof *ret);
ret->abfd = abfd;
ret->sections = sections;
ret->syms = syms;
ret->symcount = symcount;
ret->files = 1;
ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types);
ret->file_types[0] = NULL;
ret->function_end = (bfd_vma) -1;
if (!bfd_hash_table_init(&ret->table, string_hash_newfunc)) {
non_fatal ("bfd_hash_table_init_failed: %s",
bfd_errmsg (bfd_get_error ()));
return NULL;
}
for (i = 0; i < symcount; i++) {
const char *strings = bfd_asymbol_name(syms[i]);
if (strings != NULL && *strings != 0) {
struct string_hash_entry *h;
h = (struct string_hash_entry*)bfd_hash_lookup(&ret->table,
strings, true, false);
if (h == NULL) {
non_fatal (_("string_hash_lookup failed: %s"),
bfd_errmsg (bfd_get_error ()));
return NULL;
} else {
h->address = bfd_asymbol_value(syms[i]);
h->name = strings;
}
}
}
return (PTR) ret;
}
/* When we have processed all the stabs information, we need to go
through and fill in all the undefined tags. */
bfd_boolean
finish_stab (dhandle, handle)
PTR dhandle;
PTR handle;
{
struct stab_handle *info = (struct stab_handle *) handle;
struct stab_tag *st;
if (info->within_function)
{
if (! stab_emit_pending_vars (dhandle, info)
|| ! debug_end_function (dhandle, info->function_end))
return false;
info->within_function = false;
info->function_end = (bfd_vma) -1;
}
for (st = info->tags; st != NULL; st = st->next)
{
enum debug_type_kind kind;
kind = st->kind;
if (kind == DEBUG_KIND_ILLEGAL)
kind = DEBUG_KIND_STRUCT;
st->slot = debug_make_undefined_tagged_type (dhandle, st->name, kind);
if (st->slot == DEBUG_TYPE_NULL)
return false;
}
return true;
}
/* Handle a single stabs symbol. */
bfd_boolean
parse_stab (dhandle, handle, type, desc, value, string)
PTR dhandle;
PTR handle;
int type;
int desc;
bfd_vma value;
const char *string;
{
struct stab_handle *info = (struct stab_handle *) handle;
/* gcc will emit two N_SO strings per compilation unit, one for the
directory name and one for the file name. We just collect N_SO
strings as we see them, and start the new compilation unit when
we see a non N_SO symbol. */
if (info->so_string != NULL
&& (type != N_SO || *string == '\0' || value != info->so_value))
{
if (! debug_set_filename (dhandle, info->so_string))
return false;
info->main_filename = info->so_string;
info->gcc_compiled = 0;
info->n_opt_found = false;
/* Generally, for stabs in the symbol table, the N_LBRAC and
N_RBRAC symbols are relative to the N_SO symbol value. */
if (! info->sections)
info->file_start_offset = info->so_value;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -