old-cross-binutils/binutils/stabs.c
Ian Lance Taylor e1c145993e Implement generic debugging support. Implement a stabs reader and
a generic printer.
	* budbg.h, debug.c, debug.h, prdbg.c, rddbg.c, stabs.c: New files.
	* objdump.c: Include "debug.h" and "budbg.h".
	(dump_debugging): New global variable.
	(usage): Mention --debugging.
	(long_options): Add "debugging".
	(display_bfd): Handle --debugging.
	* Makefile.in (OBJDUMP_OBJS): New variable.
	($(OBJDUMP_PROG)): Use $(OBJDUMP_OBJS).
	* binutils.texi, objdump.1: Document --debugging.
1996-01-02 22:48:58 +00:00

3174 lines
75 KiB
C

/* stabs.c -- Parse stabs debugging information
Copyright (C) 1995 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 "debug.h"
#include "budbg.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 type of the last stab symbol, so that we can detect N_SO
pairs. */
int last_type;
/* The offset of the start of the function, so that we can handle
function relative 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 N_BINCL files. */
struct bincl_file *bincl_stack;
/* Whether we are inside a function or not. */
boolean within_function;
/* 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;
};
/* 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 **, 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 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 **, 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 **, debug_method **));
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 *));
static const char *pop_bincl PARAMS ((struct stab_handle *));
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));
/* 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;
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)
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 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)
PTR dhandle;
{
struct stab_handle *ret;
ret = (struct stab_handle *) xmalloc (sizeof *ret);
memset (ret, 0, sizeof *ret);
ret->files = 1;
ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types);
ret->file_types[0] = NULL;
return (PTR) ret;
}
/* When we have processed all the stabs information, we need to go
through and fill in all the undefined tags. */
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 (! debug_end_function (dhandle, (bfd_vma) -1))
return false;
info->within_function = false;
}
for (st = info->tags; st != NULL; st = st->next)
{
st->slot = debug_make_undefined_tagged_type (dhandle, st->name,
st->kind);
if (st->slot == DEBUG_TYPE_NULL)
return false;
}
return true;
}
/* Handle a single stabs symbol. */
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;
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->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->function_start_offset))
return false;
--info->block_depth;
if (info->block_depth == 0)
{
info->within_function = false;
if (! debug_end_function (dhandle,
value + info->function_start_offset))
return false;
}
break;
case N_SO:
/* Start a file. If we get two in a row, the first is the
directory name. An empty string is emitted by gcc at the end
of a compilation unit. */
if (*string == '\0')
{
if (info->within_function)
{
if (! debug_end_function (dhandle, (bfd_vma) -1))
return false;
info->within_function = false;
}
return true;
}
info->gcc_compiled = 0;
info->n_opt_found = false;
if (info->last_type == N_SO)
{
char *o;
if (! debug_append_filename (dhandle, string))
return false;
o = info->main_filename;
info->main_filename = concat (o, string, (const char *) NULL);
free (o);
}
else
{
if (! debug_set_filename (dhandle, string))
return false;
if (info->main_filename != NULL)
free (info->main_filename);
info->main_filename = xstrdup (string);
/* 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;
}
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);
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. */
++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;
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;
/* 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. */
default:
{
const char *colon;
colon = strchr (string, ':');
if (colon != NULL
&& (colon[1] == 'f' || colon[1] == 'F'))
{
if (info->within_function)
{
if (! debug_end_function (dhandle, (bfd_vma) -1))
return false;
}
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:
break;
}
info->last_type = type;
return true;
}
/* Parse the stabs string. */
static 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;
boolean synonym;
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, &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, &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, &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, &p, (debug_type **) NULL)
== DEBUG_TYPE_NULL)
return false;
}
break;
case 'G':
/* A global symbol. The value must be extracted from the symbol
table. */
dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
(bfd_vma) -1))
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, &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, &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, &p, (debug_type **) NULL);
if (dtype != DEBUG_TYPE_NULL)
dtype = debug_make_pointer_type (dhandle,
debug_make_function_type (dhandle,
dtype));
}
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_STACK,
value))
return false;
/* FIXME: At this point gdb considers rearranging the parameter
address on a big endian machine if it is smaller than an int.
We have no way to do that, since we don't really know much
about the target. */
break;
case 'P':
if (stabtype == N_FUN)
{
/* Prototype of a function referenced by this file. */
while (*p == ';')
{
++p;
if (parse_stab_type (dhandle, info, &p, (debug_type **) NULL)
== DEBUG_TYPE_NULL)
return false;
}
break;
}
/* Fall through. */
case 'R':
/* Parameter which is in a register. */
dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG,
value))
return false;
break;
case 'r':
/* Register variable (either global or local). */
dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER,
value))
return false;
/* FIXME: At this point gdb checks to combine pairs of 'p' and
'r' stabs into a single 'P' stab. */
break;
case 'S':
/* Static symbol at top level of file */
dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC,
value))
return false;
break;
case 't':
/* A typedef. */
dtype = parse_stab_type (dhandle, info, &p, &slot);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (name == NULL)
{
/* A nameless type. Nothing to do. */
return true;
}
dtype = debug_name_type (dhandle, name, dtype);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (slot != NULL)
*slot = dtype;
break;
case 'T':
/* Struct, union, or enum tag. For GNU C++, this can be be followed
by 't' which means we are typedef'ing it as well. */
if (*p != 't')
{
synonym = false;
/* FIXME: gdb sets synonym to true if the current language
is C++. */
}
else
{
synonym = true;
++p;
}
dtype = parse_stab_type (dhandle, info, &p, &slot);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (name == NULL)
return true;
dtype = debug_tag_type (dhandle, name, dtype);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (slot != NULL)
*slot = dtype;
/* See if we have a cross reference to this tag which we can now
fill in. */
{
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;
}
}
}
if (synonym)
{
dtype = debug_name_type (dhandle, name, dtype);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (slot != NULL)
*slot = dtype;
}
break;
case 'V':
/* Static symbol of local scope */
dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
/* FIXME: gdb checks os9k_stabs here. */
if (! stab_record_variable (dhandle, info, name, dtype,
DEBUG_LOCAL_STATIC, value))
return false;
break;
case 'v':
/* Reference parameter. */
dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE,
value))
return false;
break;
case 'a':
/* Reference parameter which is in a register. */
dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG,
value))
return false;
break;
case 'X':
/* This is used by Sun FORTRAN for "function result value".
Sun claims ("dbx and dbxtool interfaces", 2nd ed)
that Pascal uses it too, but when I tried it Pascal used
"x:3" (local symbol) instead. */
dtype = parse_stab_type (dhandle, info, &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;
default:
bad_stab (string);
return false;
}
/* FIXME: gdb converts structure values to structure pointers in a
couple of cases, depending upon the target. */
return true;
}
/* Parse a stabs type. */
static debug_type
parse_stab_type (dhandle, info, pp, slotp)
PTR dhandle;
struct stab_handle *info;
const char **pp;
debug_type **slotp;
{
const char *orig;
int typenums[2];
int size;
boolean stringp;
int descriptor;
debug_type dtype;
if (slotp != NULL)
*slotp = NULL;
orig = *pp;
size = -1;
stringp = 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". */
if (! isdigit ((unsigned char) **pp) && **pp != '(' && **pp != '-')
{
/* 'typenums=' not present, type is anonymous. Read and return
the definition, but don't put it in the type vector. */
typenums[0] = typenums[1] = -1;
}
else
{
if (! parse_stab_type_number (pp, typenums))
return DEBUG_TYPE_NULL;
if (**pp != '=')
{
/* Type is not being defined here. Either it already
exists, or this is a forward reference to it. */
return stab_find_type (dhandle, info, typenums);
}
/* Only set the slot if the type is being defined. This means
that the mapping from type numbers to types will only record
the name of the typedef which defines a type. If we don't do
this, then something like
typedef int foo;
int i;
will record that i is of type foo. Unfortunately, stabs
information is ambiguous about variable types. For this code,
typedef int foo;
int i;
foo j;
the stabs information records both i and j as having the same
type. This could be fixed by patching the compiler. */
if (slotp != NULL && typenums[0] >= 0 && typenums[1] >= 0)
*slotp = stab_find_slot (info, typenums);
/* Type is being defined here. */
/* Skip the '='. */
++*pp;
while (**pp == '@')
{
const char *p = *pp + 1;
const char *attr;
if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-')
{
/* Member type. */
break;
}
/* Type attributes. */
attr = p;
for (; *p != ';'; ++p)
{
if (*p == '\0')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
}
*pp = p + 1;
switch (*attr)
{
case 's':
size = atoi (attr + 1);
if (size <= 0)
size = -1;
break;
case 'S':
stringp = true;
break;
default:
/* Ignore unrecognized type attributes, so future
compilers can invent new ones. */
break;
}
}
}
descriptor = **pp;
++*pp;
switch (descriptor)
{
case 'x':
{
enum debug_type_kind code;
const char *q1, *q2, *p;
char *name;
struct stab_tag *st;
/* A cross reference to another type. */
switch (**pp)
{
case 's':
code = DEBUG_KIND_STRUCT;
break;
case 'u':
code = DEBUG_KIND_UNION;
break;
case 'e':
code = DEBUG_KIND_ENUM;
break;
default:
/* Complain and keep going, so compilers can invent new
cross-reference types. */
warn_stab (orig, "unrecognized cross reference type");
code = DEBUG_KIND_STRUCT;
break;
}
++*pp;
q1 = strchr (*pp, '<');
p = strchr (*pp, ':');
if (p == NULL)
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
while (q1 != NULL && p > q1 && p[1] == ':')
{
q2 = strchr (q1, '>');
if (q2 == NULL || q2 < p)
break;
p += 2;
p = strchr (p, ':');
if (p == NULL)
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
}
name = savestring (*pp, p - *pp);
*pp = p + 1;
/* We pass DEBUG_KIND_VOID because we want all tags in the
same namespace. This is right for C, and I don't know how
to handle other languages. FIXME. */
dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_VOID);
if (dtype != DEBUG_TYPE_NULL)
{
free (name);
if (typenums[0] != -1)
{
if (! stab_record_type (dhandle, info, typenums, dtype))
return DEBUG_TYPE_NULL;
}
return dtype;
}
/* We need to allocate an entry on the undefined tag list. */
for (st = info->tags; st != NULL; st = st->next)
{
if (st->name[0] == name[0]
&& strcmp (st->name, name) == 0)
break;
}
if (st == NULL)
{
st = (struct stab_tag *) xmalloc (sizeof *st);
memset (st, 0, sizeof *st);
st->next = info->tags;
st->name = name;
st->kind = code;
st->slot = DEBUG_TYPE_NULL;
st->type = debug_make_indirect_type (dhandle, &st->slot, name);
info->tags = st;
}
dtype = st->type;
if (typenums[0] != -1)
{
if (! stab_record_type (dhandle, info, typenums, dtype))
return DEBUG_TYPE_NULL;
}
return dtype;
}
break;
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '(':
{
const char *hold;
int xtypenums[2];
/* This type is defined as another type. */
(*pp)--;
hold = *pp;
/* Peek ahead at the number to detect void. */
if (! parse_stab_type_number (pp, xtypenums))
return DEBUG_TYPE_NULL;
if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1])
{
/* This type is being defined as itself, which means that
it is void. */
dtype = debug_make_void_type (dhandle);
}
else
{
*pp = hold;
/* Go back to the number and have parse_stab_type get it.
This means that we can deal with something like
t(1,2)=(3,4)=... which the Lucid compiler uses. */
dtype = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
if (typenums[0] != -1)
{
if (! stab_record_type (dhandle, info, typenums, dtype))
return DEBUG_TYPE_NULL;
}
break;
}
case '*':
dtype = debug_make_pointer_type (dhandle,
parse_stab_type (dhandle, info, pp,
(debug_type **) NULL));
break;
case '&':
/* Reference to another type. */
dtype = (debug_make_reference_type
(dhandle,
parse_stab_type (dhandle, info, pp, (debug_type **) NULL)));
break;
case 'f':
/* Function returning another type. */
/* FIXME: gdb checks os9k_stabs here. */
dtype = (debug_make_function_type
(dhandle,
parse_stab_type (dhandle, info, pp, (debug_type **) NULL)));
break;
case 'k':
/* Const qualifier on some type (Sun). */
/* FIXME: gdb accepts 'c' here if os9k_stabs. */
dtype = debug_make_const_type (dhandle,
parse_stab_type (dhandle, info, pp,
(debug_type **) NULL));
break;
case 'B':
/* Volatile qual on some type (Sun). */
/* FIXME: gdb accepts 'i' here if os9k_stabs. */
dtype = (debug_make_volatile_type
(dhandle,
parse_stab_type (dhandle, info, pp, (debug_type **) NULL)));
break;
case '@':
/* Offset (class & variable) type. This is used for a pointer
relative to an object. */
{
debug_type domain;
debug_type memtype;
/* Member type. */
domain = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (domain == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
if (**pp != ',')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
memtype = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (memtype == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
dtype = debug_make_offset_type (dhandle, domain, memtype);
}
break;
case '#':
/* Method (class & fn) type. */
if (**pp == '#')
{
debug_type return_type;
++*pp;
return_type = parse_stab_type (dhandle, info, pp,
(debug_type **) NULL);
if (return_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
dtype = debug_make_method_type (dhandle, return_type,
DEBUG_TYPE_NULL, NULL);
}
else
{
debug_type domain;
debug_type return_type;
debug_type *args;
unsigned int n;
unsigned int alloc;
domain = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (domain == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
if (**pp != ',')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
return_type = parse_stab_type (dhandle, info, pp,
(debug_type **) NULL);
if (return_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
alloc = 10;
args = (debug_type *) xmalloc (alloc * sizeof *args);
n = 0;
while (**pp != ';')
{
if (**pp != ',')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
if (n + 1 >= alloc)
{
alloc += 10;
args = ((debug_type *)
xrealloc ((PTR) args, alloc * sizeof *args));
}
args[n] = parse_stab_type (dhandle, info, pp,
(debug_type **) NULL);
if (args[n] == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
++n;
}
++*pp;
args[n] = DEBUG_TYPE_NULL;
dtype = debug_make_method_type (dhandle, return_type, domain, args);
}
break;
case 'r':
/* Range type. */
dtype = parse_stab_range_type (dhandle, info, pp, typenums);
break;
case 'b':
/* FIXME: gdb checks os9k_stabs here. */
/* Sun ACC builtin int type. */
dtype = parse_stab_sun_builtin_type (dhandle, pp);
break;
case 'R':
/* Sun ACC builtin float type. */
dtype = parse_stab_sun_floating_type (dhandle, pp);
break;
case 'e':
/* Enumeration type. */
dtype = parse_stab_enum_type (dhandle, pp);
break;
case 's':
case 'u':
/* Struct or union type. */
dtype = parse_stab_struct_type (dhandle, info, pp,
descriptor == 's', typenums);
break;
case 'a':
/* Array type. */
if (**pp != 'r')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
dtype = parse_stab_array_type (dhandle, info, pp, stringp);
break;
case 'S':
dtype = debug_make_set_type (dhandle,
parse_stab_type (dhandle, info, pp,
(debug_type **) NULL),
stringp);
break;
default:
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
if (dtype == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
if (typenums[0] != -1)
{
if (! stab_record_type (dhandle, info, typenums, dtype))
return DEBUG_TYPE_NULL;
}
if (size != -1)
{
if (! debug_record_type_size (dhandle, dtype, (unsigned int) size))
return false;
}
return dtype;
}
/* Read a number by which a type is referred to in dbx data, or
perhaps read a pair (FILENUM, TYPENUM) in parentheses. Just a
single number N is equivalent to (0,N). Return the two numbers by
storing them in the vector TYPENUMS. */
static boolean
parse_stab_type_number (pp, typenums)
const char **pp;
int *typenums;
{
const char *orig;
orig = *pp;
if (**pp != '(')
{
typenums[0] = 0;
typenums[1] = (int) parse_number (pp, (boolean *) NULL);
}
else
{
++*pp;
typenums[0] = (int) parse_number (pp, (boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return false;
}
++*pp;
typenums[1] = (int) parse_number (pp, (boolean *) NULL);
if (**pp != ')')
{
bad_stab (orig);
return false;
}
++*pp;
}
return true;
}
/* Parse a range type. */
static debug_type
parse_stab_range_type (dhandle, info, pp, typenums)
PTR dhandle;
struct stab_handle *info;
const char **pp;
const int *typenums;
{
const char *orig;
int rangenums[2];
boolean self_subrange;
debug_type index_type;
const char *s2, *s3;
bfd_signed_vma n2, n3;
boolean ov2, ov3;
orig = *pp;
index_type = DEBUG_TYPE_NULL;
/* First comes a type we are a subrange of.
In C it is usually 0, 1 or the type being defined. */
if (! parse_stab_type_number (pp, rangenums))
return DEBUG_TYPE_NULL;
self_subrange = (rangenums[0] == typenums[0]
&& rangenums[1] == typenums[1]);
if (**pp == '=')
{
*pp = orig;
index_type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (index_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
if (**pp == ';')
++*pp;
/* The remaining two operands are usually lower and upper bounds of
the range. But in some special cases they mean something else. */
s2 = *pp;
n2 = parse_number (pp, &ov2);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
s3 = *pp;
n3 = parse_number (pp, &ov3);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
if (ov2 || ov3)
{
/* gcc will emit range stabs for long long types. Handle this
as a special case. FIXME: This needs to be more general. */
#define LLLOW "01000000000000000000000;"
#define LLHIGH "0777777777777777777777;"
#define ULLHIGH "01777777777777777777777;"
if (index_type == DEBUG_TYPE_NULL)
{
if (strncmp (s2, LLLOW, sizeof LLLOW - 1) == 0
&& strncmp (s3, LLHIGH, sizeof LLHIGH - 1) == 0)
return debug_make_int_type (dhandle, 8, false);
if (! ov2
&& n2 == 0
&& strncmp (s3, ULLHIGH, sizeof ULLHIGH - 1) == 0)
return debug_make_int_type (dhandle, 8, true);
}
warn_stab (orig, "numeric overflow");
}
if (index_type == DEBUG_TYPE_NULL)
{
/* A type defined as a subrange of itself, with both bounds 0,
is void. */
if (self_subrange && n2 == 0 && n3 == 0)
return debug_make_void_type (dhandle);
/* If n3 is zero and n2 is positive, this is a floating point
type, and n2 is the number of bytes. */
if (n3 == 0 && n2 > 0)
return debug_make_float_type (dhandle, n2);
/* If the upper bound is -1, this is an unsigned int. */
if (n2 == 0 && n3 == -1)
{
/* FIXME: The size here really depends upon the target. */
return debug_make_int_type (dhandle, 4, true);
}
/* A range of 0 to 127 is char. */
if (self_subrange && n2 == 0 && n3 == 127)
return debug_make_int_type (dhandle, 1, false);
/* FIXME: gdb checks for the language CHILL here. */
if (n2 == 0)
{
if (n3 < 0)
return debug_make_int_type (dhandle, - n3, true);
else if (n3 == 0xff)
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 == 0
&& n2 < 0
&& (self_subrange || n2 == -8))
return debug_make_int_type (dhandle, - n2, true);
else if (n2 == - n3 - 1)
{
if (n3 == 0x7f)
return debug_make_int_type (dhandle, 1, false);
else if (n3 == 0x7fff)
return debug_make_int_type (dhandle, 2, false);
else if (n3 == 0x7fffffff)
return debug_make_int_type (dhandle, 4, false);
}
}
/* At this point I don't have the faintest idea how to deal with a
self_subrange type; I'm going to assume that this is used as an
idiom, and that all of them are special cases. So . . . */
if (self_subrange)
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
index_type = stab_find_type (dhandle, info, rangenums);
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");
index_type = debug_make_int_type (dhandle, 4, false);
}
return debug_make_range_type (dhandle, index_type, n2, n3);
}
/* Sun's ACC uses a somewhat saner method for specifying the builtin
typedefs in every file (for int, long, etc):
type = b <signed> <width>; <offset>; <nbits>
signed = u or s. Possible c in addition to u or s (for char?).
offset = offset from high order bit to start bit of type.
width is # bytes in object of this type, nbits is # bits in type.
The width/offset stuff appears to be for small objects stored in
larger ones (e.g. `shorts' in `int' registers). We ignore it for now,
FIXME. */
static debug_type
parse_stab_sun_builtin_type (dhandle, pp)
PTR dhandle;
const char **pp;
{
const char *orig;
boolean unsignedp;
bfd_vma bits;
orig = *pp;
switch (**pp)
{
case 's':
unsignedp = false;
break;
case 'u':
unsignedp = true;
break;
default:
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
/* For some odd reason, all forms of char put a c here. This is strange
because no other type has this honor. We can safely ignore this because
we actually determine 'char'acterness by the number of bits specified in
the descriptor. */
if (**pp == 'c')
++*pp;
/* The first number appears to be the number of bytes occupied
by this type, except that unsigned short is 4 instead of 2.
Since this information is redundant with the third number,
we will ignore it. */
(void) parse_number (pp, (boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
/* The second number is always 0, so ignore it too. */
(void) parse_number (pp, (boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
/* The third number is the number of bits for this type. */
bits = parse_number (pp, (boolean *) NULL);
/* The type *should* end with a semicolon. If it are embedded
in a larger type the semicolon may be the only way to know where
the type ends. If this type is at the end of the stabstring we
can deal with the omitted semicolon (but we don't have to like
it). Don't bother to complain(), Sun's compiler omits the semicolon
for "void". */
if (**pp == ';')
++*pp;
if (bits == 0)
return debug_make_void_type (dhandle);
return debug_make_int_type (dhandle, bits / 8, unsignedp);
}
/* Parse a builtin floating type generated by the Sun compiler. */
static debug_type
parse_stab_sun_floating_type (dhandle, pp)
PTR dhandle;
const char **pp;
{
const char *orig;
bfd_vma details;
bfd_vma bytes;
orig = *pp;
/* The first number has more details about the type, for example
FN_COMPLEX. */
details = parse_number (pp, (boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
/* The second number is the number of bytes occupied by this type */
bytes = parse_number (pp, (boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
if (details == NF_COMPLEX
|| details == NF_COMPLEX16
|| details == NF_COMPLEX32)
return debug_make_complex_type (dhandle, bytes);
return debug_make_float_type (dhandle, bytes);
}
/* Handle an enum type. */
static debug_type
parse_stab_enum_type (dhandle, pp)
PTR dhandle;
const char **pp;
{
const char *orig;
const char **names;
bfd_signed_vma *values;
unsigned int n;
unsigned int alloc;
orig = *pp;
/* FIXME: gdb checks os9k_stabs here. */
/* The aix4 compiler emits an extra field before the enum members;
my guess is it's a type of some sort. Just ignore it. */
if (**pp == '-')
{
while (**pp != ':')
++*pp;
++*pp;
}
/* Read the value-names and their values.
The input syntax is NAME:VALUE,NAME:VALUE, and so on.
A semicolon or comma instead of a NAME means the end. */
alloc = 10;
names = (const char **) xmalloc (alloc * sizeof *names);
values = (bfd_signed_vma *) xmalloc (alloc * sizeof *values);
n = 0;
while (**pp != '\0' && **pp != ';' && **pp != ',')
{
const char *p;
char *name;
bfd_signed_vma val;
p = *pp;
while (*p != ':')
++p;
name = savestring (*pp, p - *pp);
*pp = p + 1;
val = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
if (n + 1 >= alloc)
{
alloc += 10;
names = ((const char **)
xrealloc ((PTR) names, alloc * sizeof *names));
values = ((bfd_signed_vma *)
xrealloc ((PTR) values, alloc * sizeof *values));
}
names[n] = name;
values[n] = val;
++n;
}
names[n] = NULL;
values[n] = 0;
if (**pp == ';')
++*pp;
return debug_make_enum_type (dhandle, names, values);
}
/* Read the description of a structure (or union type) and return an object
describing the type.
PP points to a character pointer that points to the next unconsumed token
in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;",
*PP will point to "4a:1,0,32;;". */
static debug_type
parse_stab_struct_type (dhandle, info, pp, structp, typenums)
PTR dhandle;
struct stab_handle *info;
const char **pp;
boolean structp;
const int *typenums;
{
const char *orig;
bfd_vma size;
debug_baseclass *baseclasses;
debug_field *fields;
boolean statics;
debug_method *methods;
debug_type vptrbase;
boolean ownvptr;
orig = *pp;
/* Get the size. */
size = parse_number (pp, (boolean *) NULL);
/* Get the other information. */
if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses)
|| ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics)
|| ! parse_stab_members (dhandle, info, pp, &methods)
|| ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase,
&ownvptr))
return DEBUG_TYPE_NULL;
if (! statics
&& baseclasses == NULL
&& methods == NULL
&& vptrbase == DEBUG_TYPE_NULL
&& ! ownvptr)
return debug_make_struct_type (dhandle, structp, size, fields);
return debug_make_object_type (dhandle, structp, size, fields, baseclasses,
methods, vptrbase, ownvptr);
}
/* The stabs for C++ derived classes contain baseclass information which
is marked by a '!' character after the total size. This function is
called when we encounter the baseclass marker, and slurps up all the
baseclass information.
Immediately following the '!' marker is the number of base classes that
the class is derived from, followed by information for each base class.
For each base class, there are two visibility specifiers, a bit offset
to the base class information within the derived class, a reference to
the type for the base class, and a terminating semicolon.
A typical example, with two base classes, would be "!2,020,19;0264,21;".
^^ ^ ^ ^ ^ ^ ^
Baseclass information marker __________________|| | | | | | |
Number of baseclasses __________________________| | | | | | |
Visibility specifiers (2) ________________________| | | | | |
Offset in bits from start of class _________________| | | | |
Type number for base class ___________________________| | | |
Visibility specifiers (2) _______________________________| | |
Offset in bits from start of class ________________________| |
Type number of base class ____________________________________|
Return true for success, false for failure. */
static boolean
parse_stab_baseclasses (dhandle, info, pp, retp)
PTR dhandle;
struct stab_handle *info;
const char **pp;
debug_baseclass **retp;
{
const char *orig;
unsigned int c, i;
debug_baseclass *classes;
*retp = NULL;
orig = *pp;
if (**pp != '!')
{
/* No base classes. */
return true;
}
++*pp;
c = (unsigned int) parse_number (pp, (boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return false;
}
++*pp;
classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp));
for (i = 0; i < c; i++)
{
boolean virtual;
enum debug_visibility visibility;
bfd_vma bitpos;
debug_type type;
switch (**pp)
{
case '0':
virtual = false;
break;
case '1':
virtual = true;
break;
default:
warn_stab (orig, "unknown virtual character for baseclass");
virtual = false;
break;
}
++*pp;
switch (**pp)
{
case '0':
visibility = DEBUG_VISIBILITY_PRIVATE;
break;
case '1':
visibility = DEBUG_VISIBILITY_PROTECTED;
break;
case '2':
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
default:
warn_stab (orig, "unknown visibility character for baseclass");
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
}
++*pp;
/* The remaining value is the bit offset of the portion of the
object corresponding to this baseclass. Always zero in the
absence of multiple inheritance. */
bitpos = parse_number (pp, (boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return false;
}
++*pp;
type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
return false;
classes[i] = debug_make_baseclass (dhandle, type, bitpos, virtual,
visibility);
if (classes[i] == DEBUG_BASECLASS_NULL)
return false;
if (**pp != ';')
return false;
++*pp;
}
classes[i] = DEBUG_BASECLASS_NULL;
*retp = classes;
return true;
}
/* Read struct or class data fields. They have the form:
NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
At the end, we see a semicolon instead of a field.
In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
a static field.
The optional VISIBILITY is one of:
'/0' (VISIBILITY_PRIVATE)
'/1' (VISIBILITY_PROTECTED)
'/2' (VISIBILITY_PUBLIC)
'/9' (VISIBILITY_IGNORE)
or nothing, for C style fields with public visibility.
Returns 1 for success, 0 for failure. */
static boolean
parse_stab_struct_fields (dhandle, info, pp, retp, staticsp)
PTR dhandle;
struct stab_handle *info;
const char **pp;
debug_field **retp;
boolean *staticsp;
{
const char *orig;
const char *p;
debug_field *fields;
unsigned int c;
unsigned int alloc;
*retp = NULL;
*staticsp = false;
orig = *pp;
c = 0;
alloc = 10;
fields = (debug_field *) xmalloc (alloc * sizeof *fields);
while (**pp != ';')
{
/* FIXME: gdb checks os9k_stabs here. */
p = *pp;
/* Add 1 to c to leave room for NULL pointer at end. */
if (c + 1 >= alloc)
{
alloc += 10;
fields = ((debug_field *)
xrealloc ((PTR) fields, alloc * sizeof *fields));
}
/* If it starts with CPLUS_MARKER it is a special abbreviation,
unless the CPLUS_MARKER is followed by an underscore, in
which case it is just the name of an anonymous type, which we
should handle like any other type name. We accept either '$'
or '.', because a field name can never contain one of these
characters except as a CPLUS_MARKER. */
if ((*p == '$' || *p == '.') && p[1] != '_')
{
++*pp;
if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c))
return false;
++c;
continue;
}
/* Look for the ':' that separates the field name from the field
values. Data members are delimited by a single ':', while member
functions are delimited by a pair of ':'s. When we hit the member
functions (if any), terminate scan loop and return. */
p = strchr (p, ':');
if (p == NULL)
{
bad_stab (orig);
return false;
}
if (p[1] == ':')
break;
if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c,
staticsp))
return false;
++c;
}
fields[c] = DEBUG_FIELD_NULL;
*retp = fields;
return true;
}
/* Special GNU C++ name. */
static boolean
parse_stab_cpp_abbrev (dhandle, info, pp, retp)
PTR dhandle;
struct stab_handle *info;
const char **pp;
debug_field *retp;
{
const char *orig;
int cpp_abbrev;
debug_type context;
const char *name;
const char *typename;
debug_type type;
bfd_vma bitpos;
*retp = DEBUG_FIELD_NULL;
orig = *pp;
if (**pp != 'v')
{
bad_stab (*pp);
return false;
}
++*pp;
cpp_abbrev = **pp;
++*pp;
/* At this point, *pp points to something like "22:23=*22...", where
the type number before the ':' is the "context" and everything
after is a regular type definition. Lookup the type, find it's
name, and construct the field name. */
context = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (context == DEBUG_TYPE_NULL)
return false;
switch (cpp_abbrev)
{
case 'f':
/* $vf -- a virtual function table pointer. */
name = "_vptr$";
break;
case 'b':
/* $vb -- a virtual bsomethingorother */
typename = debug_get_type_name (dhandle, context);
if (typename == NULL)
{
warn_stab (orig, "unnamed $vb type");
typename = "FOO";
}
name = concat ("_vb$", typename, (const char *) NULL);
break;
default:
warn_stab (orig, "unrecognized C++ abbreviation");
name = "INVALID_CPLUSPLUS_ABBREV";
break;
}
if (**pp != ':')
{
bad_stab (orig);
return false;
}
++*pp;
type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (**pp != ',')
{
bad_stab (orig);
return false;
}
++*pp;
bitpos = parse_number (pp, (boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return false;
}
++*pp;
*retp = debug_make_field (dhandle, name, type, bitpos, 0,
DEBUG_VISIBILITY_PRIVATE);
if (*retp == DEBUG_FIELD_NULL)
return false;
return true;
}
/* Parse a single field in a struct or union. */
static boolean
parse_stab_one_struct_field (dhandle, info, pp, p, retp, staticsp)
PTR dhandle;
struct stab_handle *info;
const char **pp;
const char *p;
debug_field *retp;
boolean *staticsp;
{
const char *orig;
char *name;
enum debug_visibility visibility;
debug_type type;
bfd_vma bitpos;
bfd_vma bitsize;
orig = *pp;
/* FIXME: gdb checks ARM_DEMANGLING here. */
name = savestring (*pp, p - *pp);
*pp = p + 1;
if (**pp != '/')
visibility = DEBUG_VISIBILITY_PUBLIC;
else
{
++*pp;
switch (**pp)
{
case '0':
visibility = DEBUG_VISIBILITY_PRIVATE;
break;
case '1':
visibility = DEBUG_VISIBILITY_PROTECTED;
break;
case '2':
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
default:
warn_stab (orig, "unknown visibility character for field");
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
}
++*pp;
}
type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
return false;
if (**pp == ':')
{
char *varname;
/* This is a static class member. */
++*pp;
p = strchr (*pp, ';');
if (p == NULL)
{
bad_stab (orig);
return false;
}
varname = savestring (*pp, p - *pp);
*pp = p + 1;
*retp = debug_make_static_member (dhandle, name, type, varname,
visibility);
*staticsp = true;
return true;
}
if (**pp != ',')
{
bad_stab (orig);
return false;
}
++*pp;
bitpos = parse_number (pp, (boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return false;
}
++*pp;
bitsize = parse_number (pp, (boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return false;
}
++*pp;
if (bitpos == 0 && bitsize == 0)
{
/* This can happen in two cases: (1) at least for gcc 2.4.5 or
so, it is a field which has been optimized out. The correct
stab for this case is to use VISIBILITY_IGNORE, but that is a
recent invention. (2) It is a 0-size array. For example
union { int num; char str[0]; } foo. Printing "<no value>"
for str in "p foo" is OK, since foo.str (and thus foo.str[3])
will continue to work, and a 0-size array as a whole doesn't
have any contents to print.
I suspect this probably could also happen with gcc -gstabs
(not -gstabs+) for static fields, and perhaps other C++
extensions. Hopefully few people use -gstabs with gdb, since
it is intended for dbx compatibility. */
visibility = DEBUG_VISIBILITY_IGNORE;
}
/* FIXME: gdb does some stuff here to mark fields as unpacked. */
*retp = debug_make_field (dhandle, name, type, bitpos, bitsize, visibility);
return true;
}
/* Read member function stabs info for C++ classes. The form of each member
function data is:
NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ;
An example with two member functions is:
afunc1::20=##15;:i;2A.;afunc2::20:i;2A.;
For the case of overloaded operators, the format is op$::*.funcs, where
$ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator
name (such as `+=') and `.' marks the end of the operator name. */
static boolean
parse_stab_members (dhandle, info, pp, retp)
PTR dhandle;
struct stab_handle *info;
const char **pp;
debug_method **retp;
{
const char *orig;
debug_method *methods;
unsigned int c;
unsigned int alloc;
*retp = NULL;
orig = *pp;
alloc = 0;
methods = NULL;
c = 0;
while (**pp != ';')
{
const char *p;
char *name;
debug_method_variant *variants;
unsigned int cvars;
unsigned int allocvars;
debug_type look_ahead_type;
p = strchr (*pp, ':');
if (p == NULL || p[1] != ':')
break;
/* FIXME: Some systems use something other than '$' here. */
if ((*pp)[0] != 'o' || (*pp)[1] != 'p' || (*pp)[2] != '$')
{
name = savestring (*pp, p - *pp);
*pp = p + 2;
}
else
{
/* This is a completely wierd case. In order to stuff in the
names that might contain colons (the usual name delimiter),
Mike Tiemann defined a different name format which is
signalled if the identifier is "op$". In that case, the
format is "op$::XXXX." where XXXX is the name. This is
used for names like "+" or "=". YUUUUUUUK! FIXME! */
*pp = p + 2;
for (p = *pp; *p != '.' && *p != '\0'; p++)
;
if (*p != '.')
{
bad_stab (orig);
return false;
}
name = savestring (*pp, p - *pp);
*pp = p + 1;
}
allocvars = 10;
variants = ((debug_method_variant *)
xmalloc (allocvars * sizeof *variants));
cvars = 0;
look_ahead_type = DEBUG_TYPE_NULL;
do
{
debug_type type;
char *argtypes;
enum debug_visibility visibility;
boolean constp, volatilep, staticp;
bfd_vma voffset;
debug_type context;
if (look_ahead_type != DEBUG_TYPE_NULL)
{
/* g++ version 1 kludge */
type = look_ahead_type;
look_ahead_type = DEBUG_TYPE_NULL;
}
else
{
type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
return false;
if (**pp != ':')
{
bad_stab (orig);
return false;
}
}
++*pp;
p = strchr (*pp, ';');
if (p == NULL)
{
bad_stab (orig);
return false;
}
/* FIXME: gdb sets is_stub here. */
argtypes = savestring (*pp, p - *pp);
*pp = p + 1;
switch (**pp)
{
case '0':
visibility = DEBUG_VISIBILITY_PRIVATE;
break;
case '1':
visibility = DEBUG_VISIBILITY_PROTECTED;
break;
default:
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
}
++*pp;
constp = false;
volatilep = false;
switch (**pp)
{
case 'A':
/* Normal function. */
++*pp;
break;
case 'B':
/* const member function. */
constp = true;
++*pp;
break;
case 'C':
/* volatile member function. */
volatilep = true;
++*pp;
break;
case 'D':
/* const volatile member function. */
constp = true;
volatilep = true;
++*pp;
break;
case '*':
case '?':
case '.':
/* File compiled with g++ version 1; no information. */
break;
default:
warn_stab (orig, "const/volatile indicator missing");
break;
}
staticp = false;
switch (**pp)
{
case '*':
/* virtual member function, followed by index. The sign
bit is set to distinguish pointers-to-methods from
virtual function indicies. Since the array is in
words, the quantity must be shifted left by 1 on 16
bit machine, and by 2 on 32 bit machine, forcing the
sign bit out, and usable as a valid index into the
array. Remove the sign bit here. */
++*pp;
voffset = parse_number (pp, (boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return false;
}
++*pp;
voffset &= 0x7fffffff;
voffset += 2;
if (**pp == ';' || *pp == '\0')
{
/* Must be g++ version 1. */
context = DEBUG_TYPE_NULL;
}
else
{
/* Figure out from whence this virtual function
came. It may belong to virtual function table of
one of its baseclasses. */
look_ahead_type = parse_stab_type (dhandle, info, pp,
(debug_type **) NULL);
if (**pp == ':')
{
/* g++ version 1 overloaded methods. */
}
else
{
context = look_ahead_type;
look_ahead_type = DEBUG_TYPE_NULL;
if (**pp != ';')
{
bad_stab (orig);
return false;
}
++*pp;
}
}
break;
case '?':
/* static member function. */
++*pp;
staticp = true;
voffset = 0;
/* FIXME: gdb sets is_stub here. */
context = DEBUG_TYPE_NULL;
break;
default:
warn_stab (orig, "member function type missing");
voffset = 0;
context = DEBUG_TYPE_NULL;
break;
case '.':
++*pp;
voffset = 0;
context = DEBUG_TYPE_NULL;
break;
}
if (cvars + 1 >= allocvars)
{
allocvars += 10;
variants = ((debug_method_variant *)
xrealloc ((PTR) variants,
allocvars * sizeof *variants));
}
if (! staticp)
variants[cvars] = debug_make_method_variant (dhandle, argtypes,
type, visibility,
constp, volatilep,
voffset, context);
else
variants[cvars] = debug_make_static_method_variant (dhandle,
argtypes,
type,
visibility,
constp,
volatilep);
if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL)
return false;
++cvars;
}
while (**pp != ';' && **pp != '\0');
variants[cvars] = DEBUG_METHOD_VARIANT_NULL;
if (**pp != '\0')
++*pp;
if (c + 1 >= alloc)
{
alloc += 10;
methods = ((debug_method *)
xrealloc ((PTR) methods, alloc * sizeof *methods));
}
methods[c] = debug_make_method (dhandle, name, variants);
++c;
}
if (methods != NULL)
methods[c] = DEBUG_METHOD_NULL;
*retp = methods;
return true;
}
/* The tail end of stabs for C++ classes that contain a virtual function
pointer contains a tilde, a %, and a type number.
The type number refers to the base class (possibly this class itself) which
contains the vtable pointer for the current class.
This function is called when we have parsed all the method declarations,
so we can look for the vptr base class info. */
static boolean
parse_stab_tilde_field (dhandle, info, pp, typenums, retvptrbase, retownvptr)
PTR dhandle;
struct stab_handle *info;
const char **pp;
const int *typenums;
debug_type *retvptrbase;
boolean *retownvptr;
{
const char *orig;
const char *hold;
int vtypenums[2];
*retvptrbase = DEBUG_TYPE_NULL;
*retownvptr = false;
orig = *pp;
/* If we are positioned at a ';', then skip it. */
if (**pp == ';')
++*pp;
if (**pp != '~')
return true;
++*pp;
if (**pp == '=' || **pp == '+' || **pp == '-')
{
/* Obsolete flags that used to indicate the presence of
constructors and/or destructors. */
++*pp;
}
if (**pp != '%')
return true;
++*pp;
hold = *pp;
/* The next number is the type number of the base class (possibly
our own class) which supplies the vtable for this class. */
if (! parse_stab_type_number (pp, vtypenums))
return false;
if (vtypenums[0] == typenums[0]
&& vtypenums[1] == typenums[1])
*retownvptr = true;
else
{
debug_type vtype;
const char *p;
*pp = hold;
vtype = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
for (p = *pp; *p != ';' && *p != '\0'; p++)
;
if (*p != ';')
{
bad_stab (orig);
return false;
}
*retvptrbase = vtype;
*pp = p + 1;
}
return true;
}
/* Read a definition of an array type. */
static debug_type
parse_stab_array_type (dhandle, info, pp, stringp)
PTR dhandle;
struct stab_handle *info;
const char **pp;
boolean stringp;
{
const char *orig;
debug_type index_type;
boolean adjustable;
bfd_signed_vma lower, upper;
debug_type element_type;
/* Format of an array type:
"ar<index type>;lower;upper;<array_contents_type>".
OS9000: "arlower,upper;<array_contents_type>".
Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
for these, produce a type like float[][]. */
orig = *pp;
/* FIXME: gdb checks os9k_stabs here. */
index_type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
adjustable = false;
if (! isdigit ((unsigned char) **pp) && **pp != '-')
{
++*pp;
adjustable = true;
}
lower = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return false;
}
++*pp;
if (! isdigit ((unsigned char) **pp) && **pp != '-')
{
++*pp;
adjustable = true;
}
upper = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return false;
}
++*pp;
element_type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
if (element_type == DEBUG_TYPE_NULL)
return false;
if (adjustable)
{
lower = 0;
upper = -1;
}
return debug_make_array_type (dhandle, element_type, index_type, lower,
upper, stringp);
}
/* Keep a stack of N_BINCL include files. */
struct bincl_file
{
struct bincl_file *next;
const char *name;
};
/* Start a new N_BINCL file, pushing it onto the stack. */
static void
push_bincl (info, name)
struct stab_handle *info;
const char *name;
{
struct bincl_file *n;
n = (struct bincl_file *) xmalloc (sizeof *n);
n->next = info->bincl_stack;
n->name = name;
info->bincl_stack = n;
++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;
}
/* Finish an N_BINCL file, at an N_EINCL, popping the name off the
stack. */
static const char *
pop_bincl (info)
struct stab_handle *info;
{
struct bincl_file *o;
o = info->bincl_stack;
if (o == NULL)
return info->main_filename;
info->bincl_stack = o->next;
free (o);
if (info->bincl_stack == NULL)
return info->main_filename;
return info->bincl_stack->name;
}
/* 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
N_LBRAC, so we can call debug_record_variable immediately. */
static boolean
stab_record_variable (dhandle, info, name, type, kind, val)
PTR dhandle;
struct stab_handle *info;
const char *name;
debug_type type;
enum debug_var_kind kind;
bfd_vma val;
{
struct stab_pending_var *v;
if (! info->within_function
|| (info->gcc_compiled == 0 && info->n_opt_found))
return debug_record_variable (dhandle, name, type, kind, val);
v = (struct stab_pending_var *) xmalloc (sizeof *v);
memset (v, 0, sizeof *v);
v->next = info->pending;
v->name = name;
v->type = type;
v->kind = kind;
v->val = val;
info->pending = v;
return true;
}
/* Emit pending variable definitions. This is called after we see the
N_LBRAC that starts the block. */
static boolean
stab_emit_pending_vars (dhandle, info)
PTR dhandle;
struct stab_handle *info;
{
struct stab_pending_var *v;
v = info->pending;
while (v != NULL)
{
struct stab_pending_var *next;
if (! debug_record_variable (dhandle, v->name, v->type, v->kind, v->val))
return false;
next = v->next;
free (v);
v = next;
}
info->pending = NULL;
return true;
}
/* Find the slot for a type in the database. */
static debug_type *
stab_find_slot (info, typenums)
struct stab_handle *info;
const int *typenums;
{
int filenum;
int index;
struct stab_types **ps;
filenum = typenums[0];
index = typenums[1];
if (filenum < 0 || (unsigned int) filenum >= info->files)
{
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);
return NULL;
}
ps = info->file_types + filenum;
while (index >= STAB_TYPES_SLOTS)
{
if (*ps == NULL)
{
*ps = (struct stab_types *) xmalloc (sizeof **ps);
memset (*ps, 0, sizeof **ps);
}
ps = &(*ps)->next;
index -= STAB_TYPES_SLOTS;
}
if (*ps == NULL)
{
*ps = (struct stab_types *) xmalloc (sizeof **ps);
memset (*ps, 0, sizeof **ps);
}
return (*ps)->types + index;
}
/* Find a type given a type number. If the type has not been
allocated yet, create an indirect type. */
static debug_type
stab_find_type (dhandle, info, typenums)
PTR dhandle;
struct stab_handle *info;
const int *typenums;
{
debug_type *slot;
if (typenums[0] == 0 && typenums[1] < 0)
{
/* A negative type number indicates an XCOFF builtin type. */
return stab_xcoff_builtin_type (dhandle, info, typenums[1]);
}
slot = stab_find_slot (info, typenums);
if (slot == NULL)
return DEBUG_TYPE_NULL;
if (*slot == DEBUG_TYPE_NULL)
return debug_make_indirect_type (dhandle, slot, (const char *) NULL);
return *slot;
}
/* Record that a given type number refers to a given type. */
static boolean
stab_record_type (dhandle, info, typenums, type)
PTR dhandle;
struct stab_handle *info;
const int *typenums;
debug_type type;
{
debug_type *slot;
slot = stab_find_slot (info, typenums);
if (slot == NULL)
return false;
/* gdb appears to ignore type redefinitions, so we do as well. */
*slot = type;
return true;
}
/* Return an XCOFF builtin type. */
static debug_type
stab_xcoff_builtin_type (dhandle, info, typenum)
PTR dhandle;
struct stab_handle *info;
int typenum;
{
debug_type rettype;
const char *name;
if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT)
{
fprintf (stderr, "Unrecognized XCOFF type %d\n", typenum);
return DEBUG_TYPE_NULL;
}
if (info->xcoff_types[-typenum] != NULL)
return info->xcoff_types[-typenum];
switch (-typenum)
{
case 1:
/* The size of this and all the other types are fixed, defined
by the debugging format. */
name = "int";
rettype = debug_make_int_type (dhandle, 4, false);
break;
case 2:
name = "char";
rettype = debug_make_int_type (dhandle, 1, false);
break;
case 3:
name = "short";
rettype = debug_make_int_type (dhandle, 2, false);
break;
case 4:
name = "long";
rettype = debug_make_int_type (dhandle, 4, false);
break;
case 5:
name = "unsigned char";
rettype = debug_make_int_type (dhandle, 1, true);
break;
case 6:
name = "signed char";
rettype = debug_make_int_type (dhandle, 1, false);
break;
case 7:
name = "unsigned short";
rettype = debug_make_int_type (dhandle, 2, true);
break;
case 8:
name = "unsigned int";
rettype = debug_make_int_type (dhandle, 4, true);
break;
case 9:
name = "unsigned";
rettype = debug_make_int_type (dhandle, 4, true);
case 10:
name = "unsigned long";
rettype = debug_make_int_type (dhandle, 4, true);
break;
case 11:
name = "void";
rettype = debug_make_void_type (dhandle);
break;
case 12:
/* IEEE single precision (32 bit). */
name = "float";
rettype = debug_make_float_type (dhandle, 4);
break;
case 13:
/* IEEE double precision (64 bit). */
name = "double";
rettype = debug_make_float_type (dhandle, 8);
break;
case 14:
/* This is an IEEE double on the RS/6000, and different machines
with different sizes for "long double" should use different
negative type numbers. See stabs.texinfo. */
name = "long double";
rettype = debug_make_float_type (dhandle, 8);
break;
case 15:
name = "integer";
rettype = debug_make_int_type (dhandle, 4, false);
break;
case 16:
name = "boolean";
rettype = debug_make_bool_type (dhandle, 4);
break;
case 17:
name = "short real";
rettype = debug_make_float_type (dhandle, 4);
break;
case 18:
name = "real";
rettype = debug_make_float_type (dhandle, 8);
break;
case 19:
/* FIXME */
name = "stringptr";
rettype = NULL;
break;
case 20:
/* FIXME */
name = "character";
rettype = debug_make_int_type (dhandle, 1, true);
break;
case 21:
name = "logical*1";
rettype = debug_make_bool_type (dhandle, 1);
break;
case 22:
name = "logical*2";
rettype = debug_make_bool_type (dhandle, 2);
break;
case 23:
name = "logical*4";
rettype = debug_make_bool_type (dhandle, 4);
break;
case 24:
name = "logical";
rettype = debug_make_bool_type (dhandle, 4);
break;
case 25:
/* Complex type consisting of two IEEE single precision values. */
name = "complex";
rettype = debug_make_complex_type (dhandle, 8);
break;
case 26:
/* Complex type consisting of two IEEE double precision values. */
name = "double complex";
rettype = debug_make_complex_type (dhandle, 16);
break;
case 27:
name = "integer*1";
rettype = debug_make_int_type (dhandle, 1, false);
break;
case 28:
name = "integer*2";
rettype = debug_make_int_type (dhandle, 2, false);
break;
case 29:
name = "integer*4";
rettype = debug_make_int_type (dhandle, 4, false);
break;
case 30:
/* FIXME */
name = "wchar";
rettype = debug_make_int_type (dhandle, 2, false);
break;
case 31:
name = "long long";
rettype = debug_make_int_type (dhandle, 8, false);
break;
case 32:
name = "unsigned long long";
rettype = debug_make_int_type (dhandle, 8, true);
break;
case 33:
name = "logical*8";
rettype = debug_make_bool_type (dhandle, 8);
break;
case 34:
name = "integer*8";
rettype = debug_make_int_type (dhandle, 8, false);
break;
default:
abort ();
}
rettype = debug_name_type (dhandle, name, rettype);
info->xcoff_types[-typenum] = rettype;
return rettype;
}