stabs.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,559 行 · 第 1/5 页
C
2,559 行
/* 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 <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 "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. */ boolean sections; /* The symbol table. */ asymbol **syms; /* The number of symbols. */ long symcount; /* 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. */ 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. */ 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. */ 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 **, boolean *));static void bad_stab PARAMS ((const char *));static void warn_stab PARAMS ((const char *, const char *));static 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 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 **, boolean, const int *));static boolean parse_stab_baseclasses PARAMS ((PTR, struct stab_handle *, const char **, debug_baseclass **));static boolean parse_stab_struct_fields PARAMS ((PTR, struct stab_handle *, const char **, debug_field **, boolean *));static boolean parse_stab_cpp_abbrev PARAMS ((PTR, struct stab_handle *, const char **, debug_field *));static boolean parse_stab_one_struct_field PARAMS ((PTR, struct stab_handle *, const char **, const char *, debug_field *, boolean *));static 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 *, boolean, boolean, const char **));static boolean parse_stab_tilde_field PARAMS ((PTR, struct stab_handle *, const char **, const int *, 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 *, 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));static 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 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 *, 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_vmaparse_number (pp, poverflow) const char **pp; 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; boolean neg; int base; bfd_vma over, lastdig; 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 voidbad_stab (p) const char *p;{ fprintf (stderr, _("Bad stab: %s\n"), p);}/* Warn about something in a stab string. */static voidwarn_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*/PTRstart_stab (dhandle, abfd, sections, syms, symcount) PTR dhandle ATTRIBUTE_UNUSED; bfd *abfd; boolean sections; asymbol **syms; long symcount;{ struct stab_handle *ret; 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; return (PTR) ret;}/* When we have processed all the stabs information, we need to go through and fill in all the undefined tags. */booleanfinish_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. */booleanparse_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; /* We need to reset the mapping from type numbers to types. We can't free the old mapping, because of the use of debug_make_indirect_type. */ info->files = 1; info->file_types = ((struct stab_types **) xmalloc (sizeof *info->file_types)); info->file_types[0] = NULL; info->so_string = NULL; /* Now process whatever type we just got. */ } switch (type) { case N_FN: case N_FN_SEQ: break; case N_LBRAC: /* Ignore extra outermost context from SunPRO cc and acc. */ if (info->n_opt_found && desc == 1) break; if (! info->within_function) { fprintf (stderr, _("N_LBRAC not within function\n")); return false; } /* Start an inner lexical block. */ if (! debug_start_block (dhandle, (value + info->file_start_offset + info->function_start_offset))) return false; /* Emit any pending variable definitions. */ if (! stab_emit_pending_vars (dhandle, info)) return false; ++info->block_depth; break; case N_RBRAC: /* Ignore extra outermost context from SunPRO cc and acc. */ if (info->n_opt_found && desc == 1) break; /* We shouldn't have any pending variable definitions here, but, if we do, we probably need to emit them before closing the block. */ if (! stab_emit_pending_vars (dhandle, info))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?