📄 stabs.c
字号:
/* 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))
return false;
/* End an inner lexical block. */
if (! debug_end_block (dhandle,
(value
+ info->file_start_offset
+ info->function_start_offset)))
return false;
--info->block_depth;
if (info->block_depth < 0)
{
fprintf (stderr, _("Too many N_RBRACs\n"));
return false;
}
break;
case N_SO:
/* This always ends a function. */
if (info->within_function)
{
bfd_vma endval;
endval = value;
if (*string != '\0'
&& info->function_end != (bfd_vma) -1
&& info->function_end < endval)
endval = info->function_end;
if (! stab_emit_pending_vars (dhandle, info)
|| ! debug_end_function (dhandle, endval))
return false;
info->within_function = false;
info->function_end = (bfd_vma) -1;
}
/* An empty string is emitted by gcc at the end of a compilation
unit. */
if (*string == '\0')
return true;
/* Just accumulate strings until we see a non N_SO symbol. If
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);
else
{
char *f;
f = info->so_string;
if (IS_ABSOLUTE_PATH (string))
info->so_string = xstrdup (string);
else
info->so_string = concat (info->so_string, string,
(const char *) NULL);
free (f);
}
info->so_value = value;
break;
case N_SOL:
/* Start an include file. */
if (! debug_start_source (dhandle, string))
return false;
break;
case N_BINCL:
/* Start an include file which may be replaced. */
push_bincl (info, string, value);
if (! debug_start_source (dhandle, string))
return false;
break;
case N_EINCL:
/* End an N_BINCL include. */
if (! debug_start_source (dhandle, pop_bincl (info)))
return false;
break;
case N_EXCL:
/* This is a duplicate of a header file named by N_BINCL which
was eliminated by the linker. */
if (! find_excl (info, string, value))
return false;
break;
case N_SLINE:
if (! debug_record_line (dhandle, desc,
value + info->function_start_offset))
return false;
break;
case N_BCOMM:
if (! debug_start_common_block (dhandle, string))
return false;
break;
case N_ECOMM:
if (! debug_end_common_block (dhandle, string))
return false;
break;
case N_FUN:
if (*string == '\0')
{
if (info->within_function)
{
/* This always marks the end of a function; we don't
need to worry about info->function_end. */
if (info->sections)
value += info->function_start_offset;
if (! stab_emit_pending_vars (dhandle, info)
|| ! debug_end_function (dhandle, value))
return false;
info->within_function = false;
info->function_end = (bfd_vma) -1;
}
break;
}
/* A const static symbol in the .text section will have an N_FUN
entry. We need to use these to mark the end of the function,
in case we are looking at gcc output before it was changed to
always emit an empty N_FUN. We can't call debug_end_function
here, because it might be a local static symbol. */
if (info->within_function
&& (info->function_end == (bfd_vma) -1
|| value < info->function_end))
info->function_end = value;
/* Fall through. */
/* FIXME: gdb checks the string for N_STSYM, N_LCSYM or N_ROSYM
symbols, and if it does not start with :S, gdb relocates the
value to the start of the section. gcc always seems to use
:S, so we don't worry about this. */
/* Fall through. */
default:
{
const char *colon;
colon = strchr (string, ':');
if (colon != NULL
&& (colon[1] == 'f' || colon[1] == 'F'))
{
if (info->within_function)
{
bfd_vma endval;
endval = value;
if (info->function_end != (bfd_vma) -1
&& info->function_end < endval)
endval = info->function_end;
if (! stab_emit_pending_vars (dhandle, info)
|| ! debug_end_function (dhandle, endval))
return false;
info->function_end = (bfd_vma) -1;
}
/* For stabs in sections, line numbers and block addresses
are offsets from the start of the function. */
if (info->sections)
info->function_start_offset = value;
info->within_function = true;
}
if (! parse_stab_string (dhandle, info, type, desc, value, string))
return false;
}
break;
case N_OPT:
if (string != NULL && strcmp (string, "gcc2_compiled.") == 0)
info->gcc_compiled = 2;
else if (string != NULL && strcmp (string, "gcc_compiled.") == 0)
info->gcc_compiled = 1;
else
info->n_opt_found = true;
break;
case N_OBJ:
// case N_ENDM:
case N_MAIN:
case N_WARNING:
break;
}
return true;
}
/* Parse the stabs string. */
static bfd_boolean
parse_stab_string (dhandle, info, stabtype, desc, value, string)
PTR dhandle;
struct stab_handle *info;
int stabtype;
int desc;
bfd_vma value;
const char *string;
{
const char *p;
char *name;
int type;
debug_type dtype;
bfd_boolean synonym;
bfd_boolean self_crossref;
unsigned int lineno;
debug_type *slot;
p = strchr (string, ':');
if (p == NULL)
return true;
while (p[1] == ':')
{
p += 2;
p = strchr (p, ':');
if (p == NULL)
{
bad_stab (string);
return false;
}
}
/* 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. */
if (info->gcc_compiled >= 2)
lineno = desc;
else
lineno = 0;
/* FIXME: Sometimes the special C++ names start with '.'. */
name = NULL;
if (string[0] == '$')
{
switch (string[1])
{
case 't':
name = "this";
break;
case 'v':
/* Was: name = "vptr"; */
break;
case 'e':
name = "eh_throw";
break;
case '_':
/* This was an anonymous type that was never fixed up. */
break;
case 'X':
/* SunPRO (3.0 at least) static variable encoding. */
break;
default:
warn_stab (string, _("unknown C++ encoded name"));
break;
}
}
if (name == NULL)
{
if (p == string || (string[0] == ' ' && p == string + 1))
name = NULL;
else
name = savestring (string, p - string);
}
++p;
if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-')
type = 'l';
else
type = *p++;
switch (type)
{
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 != '=')
{
bad_stab (string);
return false;
}
++p;
switch (*p++)
{
case 'r':
/* Floating point constant. */
if (! debug_record_float_const (dhandle, name, atof (p)))
return false;
break;
case 'i':
/* Integer constant. */
/* 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. */
if (! debug_record_int_const (dhandle, name, atoi (p)))
return false;
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,;"). */
dtype = parse_stab_type (dhandle, info, (const char *) NULL,
&p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (*p != ',')
{
bad_stab (string);
return false;
}
if (! debug_record_typed_const (dhandle, name, dtype, atoi (p)))
return false;
break;
default:
bad_stab (string);
return false;
}
break;
case 'C':
/* The name of a caught exception. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL,
&p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! debug_record_label (dhandle, name, dtype, value))
return false;
break;
case 'f':
case 'F':
/* A function definition. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! debug_record_function (dhandle, name, dtype, type == 'F', value))
return false;
/* 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;
if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL)
== DEBUG_TYPE_NULL)
return false;
}
break;
case 'G':
{
char leading;
long c;
asymbol **ps;
/* A global symbol. The value must be extracted from the
symbol table. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
leading = bfd_get_symbol_leading_char (info->abfd);
for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
{
const char *n;
n = bfd_asymbol_name (*ps);
if (leading != '\0' && *n == leading)
++n;
if (*n == *name && strcmp (n, name) == 0)
break;
}
if (c > 0)
value = bfd_asymbol_value (*ps);
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
value))
return false;
}
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':
case 's':
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
value))
return false;
break;
case 'p':
/* A function parameter. */
if (*p != 'F')
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
else
{
/* pF is a two-letter code that means a function parameter in
Fortran. The type-number specifies the type of the return
value. Translate it into a pointer-to-function type. */
++p;
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype != DEBUG_TYPE_NULL)
{
debug_type ftype;
ftype = debug_make_function_type (dhandle, dtype,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -