Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5216 → Rev 5217

/contrib/toolchain/binutils/Makefile
15,7 → 15,7
LDFLAGS = -nostdlib -shared -s --image-base 0 -T ../newlib/dll.lds -e _DllStartup
LDFLAGS+= --out-implib
 
SUBDIRS = libiberty bfd ld
SUBDIRS = libiberty bfd binutils ld
 
# targets
 
/contrib/toolchain/binutils/binutils/Makefile
0,0 → 1,43
NAME= objcopy-new
 
LIB_DIR:= $(SDK_DIR)/lib
 
CFLAGS_OPT = -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -U_MSC_VER -O2
CFLAGS_OPT+= -fomit-frame-pointer -fno-ident -mno-ms-bitfields
CFLAGS_OPT+= -W -Wall -Wmissing-prototypes -Wno-format
CFLAGS = -c $(CFLAGS_OPT)
 
INCLUDES= -I. -I../bfd -I../include -I$(SDK_DIR)/sources/newlib/libc/include
 
DEFINES= -DHAVE_CONFIG_H -DLOCALEDIR='"/home/autobuild/tools/win32/share/locale"'
DEFINES+= -Dbin_dummy_emulation=bin_vanilla_emulation
 
LIBS= -lbfd -liberty -lz -lgcc -lc.dll -lapp
 
LIBPATH:= -L$(LIB_DIR) -L/home/autobuild/tools/win32/mingw32/lib
 
LDFLAGS = -static -nostdlib --stack 12582912 -T$(SDK_DIR)/sources/newlib/app.lds --image-base 0
 
 
SRCS = \
objcopy.c not-strip.c rename.c \
rddbg.c debug.c stabs.c ieee.c \
rdcoff.c wrstabs.c bucomm.c \
version.c filemode.c
 
 
 
OBJS = $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS)))
 
# targets
 
all: $(NAME)
 
$(NAME): $(OBJS) Makefile
$(LD) $(LDFLAGS) $(LIBPATH) -o $@ $(OBJS) $(LIBS)
kos32-objcopy $@ kos32-objcopy -O binary
 
%.o : %.c Makefile
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $<
 
/contrib/toolchain/binutils/binutils/bucomm.c
0,0 → 1,629
/* bucomm.c -- Bin Utils COMmon code.
Copyright 1991, 1992, 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002,
2003, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
 
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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/* We might put this in a library someday so it could be dynamically
loaded, but for now it's not necessary. */
 
#include "sysdep.h"
#include "bfd.h"
#include "libiberty.h"
#include "filenames.h"
#include "libbfd.h"
 
#include <time.h> /* ctime, maybe time_t */
#include <assert.h>
#include "bucomm.h"
 
#ifndef HAVE_TIME_T_IN_TIME_H
#ifndef HAVE_TIME_T_IN_TYPES_H
typedef long time_t;
#endif
#endif
 
static const char * endian_string (enum bfd_endian);
static int display_target_list (void);
static int display_info_table (int, int);
static int display_target_tables (void);
/* Error reporting. */
 
char *program_name;
 
void
bfd_nonfatal (const char *string)
{
const char *errmsg;
 
errmsg = bfd_errmsg (bfd_get_error ());
fflush (stdout);
if (string)
fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
else
fprintf (stderr, "%s: %s\n", program_name, errmsg);
}
 
/* Issue a non fatal error message. FILENAME, or if NULL then BFD,
are used to indicate the problematic file. SECTION, if non NULL,
is used to provide a section name. If FORMAT is non-null, then it
is used to print additional information via vfprintf. Finally the
bfd error message is printed. In summary, error messages are of
one of the following forms:
 
PROGRAM:file: bfd-error-message
PROGRAM:file[section]: bfd-error-message
PROGRAM:file: printf-message: bfd-error-message
PROGRAM:file[section]: printf-message: bfd-error-message. */
 
void
bfd_nonfatal_message (const char *filename,
const bfd *abfd,
const asection *section,
const char *format, ...)
{
const char *errmsg;
const char *section_name;
va_list args;
 
errmsg = bfd_errmsg (bfd_get_error ());
fflush (stdout);
section_name = NULL;
va_start (args, format);
fprintf (stderr, "%s", program_name);
 
if (abfd)
{
if (!filename)
filename = bfd_get_archive_filename (abfd);
if (section)
section_name = bfd_get_section_name (abfd, section);
}
if (section_name)
fprintf (stderr, ":%s[%s]", filename, section_name);
else
fprintf (stderr, ":%s", filename);
 
if (format)
{
fprintf (stderr, ": ");
vfprintf (stderr, format, args);
}
fprintf (stderr, ": %s\n", errmsg);
va_end (args);
}
 
void
bfd_fatal (const char *string)
{
bfd_nonfatal (string);
xexit (1);
}
 
void
report (const char * format, va_list args)
{
fflush (stdout);
fprintf (stderr, "%s: ", program_name);
vfprintf (stderr, format, args);
putc ('\n', stderr);
}
 
void
fatal VPARAMS ((const char *format, ...))
{
VA_OPEN (args, format);
VA_FIXEDARG (args, const char *, format);
 
report (format, args);
VA_CLOSE (args);
xexit (1);
}
 
void
non_fatal VPARAMS ((const char *format, ...))
{
VA_OPEN (args, format);
VA_FIXEDARG (args, const char *, format);
 
report (format, args);
VA_CLOSE (args);
}
 
/* Set the default BFD target based on the configured target. Doing
this permits the binutils to be configured for a particular target,
and linked against a shared BFD library which was configured for a
different target. */
 
void
set_default_bfd_target (void)
{
/* The macro TARGET is defined by Makefile. */
const char *target = TARGET;
 
if (! bfd_set_default_target (target))
fatal (_("can't set BFD default target to `%s': %s"),
target, bfd_errmsg (bfd_get_error ()));
}
 
/* After a FALSE return from bfd_check_format_matches with
bfd_get_error () == bfd_error_file_ambiguously_recognized, print
the possible matching targets. */
 
void
list_matching_formats (char **p)
{
fflush (stdout);
fprintf (stderr, _("%s: Matching formats:"), program_name);
while (*p)
fprintf (stderr, " %s", *p++);
fputc ('\n', stderr);
}
 
/* List the supported targets. */
 
void
list_supported_targets (const char *name, FILE *f)
{
int t;
const char **targ_names;
 
if (name == NULL)
fprintf (f, _("Supported targets:"));
else
fprintf (f, _("%s: supported targets:"), name);
 
targ_names = bfd_target_list ();
for (t = 0; targ_names[t] != NULL; t++)
fprintf (f, " %s", targ_names[t]);
fprintf (f, "\n");
free (targ_names);
}
 
/* List the supported architectures. */
 
void
list_supported_architectures (const char *name, FILE *f)
{
const char ** arch;
const char ** arches;
 
if (name == NULL)
fprintf (f, _("Supported architectures:"));
else
fprintf (f, _("%s: supported architectures:"), name);
 
for (arch = arches = bfd_arch_list (); *arch; arch++)
fprintf (f, " %s", *arch);
fprintf (f, "\n");
free (arches);
}
/* The length of the longest architecture name + 1. */
#define LONGEST_ARCH sizeof ("powerpc:common")
 
static const char *
endian_string (enum bfd_endian endian)
{
switch (endian)
{
case BFD_ENDIAN_BIG: return _("big endian");
case BFD_ENDIAN_LITTLE: return _("little endian");
default: return _("endianness unknown");
}
}
 
/* List the targets that BFD is configured to support, each followed
by its endianness and the architectures it supports. */
 
static int
display_target_list (void)
{
char *dummy_name;
int t;
int ret = 1;
 
dummy_name = make_temp_file (NULL);
for (t = 0; bfd_target_vector[t]; t++)
{
const bfd_target *p = bfd_target_vector[t];
bfd *abfd = bfd_openw (dummy_name, p->name);
int a;
 
printf (_("%s\n (header %s, data %s)\n"), p->name,
endian_string (p->header_byteorder),
endian_string (p->byteorder));
 
if (abfd == NULL)
{
bfd_nonfatal (dummy_name);
ret = 0;
continue;
}
 
if (! bfd_set_format (abfd, bfd_object))
{
if (bfd_get_error () != bfd_error_invalid_operation)
{
bfd_nonfatal (p->name);
ret = 0;
}
bfd_close_all_done (abfd);
continue;
}
 
for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
if (bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0))
printf (" %s\n",
bfd_printable_arch_mach ((enum bfd_architecture) a, 0));
bfd_close_all_done (abfd);
}
unlink (dummy_name);
free (dummy_name);
 
return ret;
}
 
/* Print a table showing which architectures are supported for entries
FIRST through LAST-1 of bfd_target_vector (targets across,
architectures down). */
 
static int
display_info_table (int first, int last)
{
int t;
int ret = 1;
char *dummy_name;
int a;
 
/* Print heading of target names. */
printf ("\n%*s", (int) LONGEST_ARCH, " ");
for (t = first; t < last && bfd_target_vector[t]; t++)
printf ("%s ", bfd_target_vector[t]->name);
putchar ('\n');
 
dummy_name = make_temp_file (NULL);
for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
if (strcmp (bfd_printable_arch_mach ((enum bfd_architecture) a, 0),
"UNKNOWN!") != 0)
{
printf ("%*s ", (int) LONGEST_ARCH - 1,
bfd_printable_arch_mach ((enum bfd_architecture) a, 0));
for (t = first; t < last && bfd_target_vector[t]; t++)
{
const bfd_target *p = bfd_target_vector[t];
bfd_boolean ok = TRUE;
bfd *abfd = bfd_openw (dummy_name, p->name);
 
if (abfd == NULL)
{
bfd_nonfatal (p->name);
ret = 0;
ok = FALSE;
}
 
if (ok)
{
if (! bfd_set_format (abfd, bfd_object))
{
if (bfd_get_error () != bfd_error_invalid_operation)
{
bfd_nonfatal (p->name);
ret = 0;
}
ok = FALSE;
}
}
 
if (ok)
{
if (! bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0))
ok = FALSE;
}
 
if (ok)
printf ("%s ", p->name);
else
{
int l = strlen (p->name);
while (l--)
putchar ('-');
putchar (' ');
}
if (abfd != NULL)
bfd_close_all_done (abfd);
}
putchar ('\n');
}
unlink (dummy_name);
free (dummy_name);
 
return ret;
}
 
/* Print tables of all the target-architecture combinations that
BFD has been configured to support. */
 
static int
display_target_tables (void)
{
int t;
int columns;
int ret = 1;
char *colum;
 
columns = 0;
colum = getenv ("COLUMNS");
if (colum != NULL)
columns = atoi (colum);
if (columns == 0)
columns = 80;
 
t = 0;
while (bfd_target_vector[t] != NULL)
{
int oldt = t, wid;
 
wid = LONGEST_ARCH + strlen (bfd_target_vector[t]->name) + 1;
++t;
while (wid < columns && bfd_target_vector[t] != NULL)
{
int newwid;
 
newwid = wid + strlen (bfd_target_vector[t]->name) + 1;
if (newwid >= columns)
break;
wid = newwid;
++t;
}
if (! display_info_table (oldt, t))
ret = 0;
}
 
return ret;
}
 
int
display_info (void)
{
printf (_("BFD header file version %s\n"), BFD_VERSION_STRING);
if (! display_target_list () || ! display_target_tables ())
return 1;
else
return 0;
}
/* Display the archive header for an element as if it were an ls -l listing:
 
Mode User\tGroup\tSize\tDate Name */
 
void
print_arelt_descr (FILE *file, bfd *abfd, bfd_boolean verbose)
{
struct stat buf;
 
if (verbose)
{
if (bfd_stat_arch_elt (abfd, &buf) == 0)
{
char modebuf[11];
char timebuf[40];
time_t when = buf.st_mtime;
const char *ctime_result = (const char *) ctime (&when);
bfd_size_type size;
 
/* POSIX format: skip weekday and seconds from ctime output. */
sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
 
mode_string (buf.st_mode, modebuf);
modebuf[10] = '\0';
size = buf.st_size;
/* POSIX 1003.2/D11 says to skip first character (entry type). */
fprintf (file, "%s %ld/%ld %6" BFD_VMA_FMT "u %s ", modebuf + 1,
(long) buf.st_uid, (long) buf.st_gid,
size, timebuf);
}
}
 
fprintf (file, "%s\n", bfd_get_filename (abfd));
}
 
/* Return a path for a new temporary file in the same directory
as file PATH. */
 
static char *
template_in_dir (const char *path)
{
#define template "stXXXXXX"
const char *slash = strrchr (path, '/');
char *tmpname;
size_t len;
 
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
{
/* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
char *bslash = strrchr (path, '\\');
 
if (slash == NULL || (bslash != NULL && bslash > slash))
slash = bslash;
if (slash == NULL && path[0] != '\0' && path[1] == ':')
slash = path + 1;
}
#endif
 
if (slash != (char *) NULL)
{
len = slash - path;
tmpname = (char *) xmalloc (len + sizeof (template) + 2);
memcpy (tmpname, path, len);
 
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
/* If tmpname is "X:", appending a slash will make it a root
directory on drive X, which is NOT the same as the current
directory on drive X. */
if (len == 2 && tmpname[1] == ':')
tmpname[len++] = '.';
#endif
tmpname[len++] = '/';
}
else
{
tmpname = (char *) xmalloc (sizeof (template));
len = 0;
}
 
memcpy (tmpname + len, template, sizeof (template));
return tmpname;
#undef template
}
 
/* Return the name of a created temporary file in the same directory
as FILENAME. */
 
char *
make_tempname (char *filename)
{
char *tmpname = template_in_dir (filename);
int fd;
 
#ifdef HAVE_MKSTEMP
fd = mkstemp (tmpname);
#else
tmpname = mktemp (tmpname);
if (tmpname == NULL)
return NULL;
fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600);
#endif
if (fd == -1)
{
free (tmpname);
return NULL;
}
close (fd);
return tmpname;
}
 
/* Return the name of a created temporary directory inside the
directory containing FILENAME. */
 
char *
make_tempdir (char *filename)
{
char *tmpname = template_in_dir (filename);
 
/*
#ifdef HAVE_MKDTEMP
return mkdtemp (tmpname);
#else
tmpname = mktemp (tmpname);
if (tmpname == NULL)
return NULL;
#if defined (_WIN32) && !defined (__CYGWIN32__)
if (mkdir (tmpname) != 0)
return NULL;
#else
if (mkdir (tmpname, 0700) != 0)
return NULL;
#endif
return tmpname;
#endif
*/
return NULL;
}
 
/* Parse a string into a VMA, with a fatal error if it can't be
parsed. */
 
bfd_vma
parse_vma (const char *s, const char *arg)
{
bfd_vma ret;
const char *end;
 
ret = bfd_scan_vma (s, &end, 0);
 
if (*end != '\0')
fatal (_("%s: bad number: %s"), arg, s);
 
return ret;
}
 
/* Returns the size of the named file. If the file does not
exist, or if it is not a real file, then a suitable non-fatal
error message is printed and (off_t) -1 is returned. */
 
off_t
get_file_size (const char * file_name)
{
struct stat statbuf;
 
if (stat (file_name, &statbuf) < 0)
{
if (errno == ENOENT)
non_fatal (_("'%s': No such file"), file_name);
else
non_fatal (_("Warning: could not locate '%s'. reason: %s"),
file_name, strerror (errno));
}
else if (! S_ISREG (statbuf.st_mode))
non_fatal (_("Warning: '%s' is not an ordinary file"), file_name);
else if (statbuf.st_size < 0)
non_fatal (_("Warning: '%s' has negative size, probably it is too large"),
file_name);
else
return statbuf.st_size;
 
return (off_t) -1;
}
 
/* Return the filename in a static buffer. */
 
const char *
bfd_get_archive_filename (const bfd *abfd)
{
static size_t curr = 0;
static char *buf;
size_t needed;
 
assert (abfd != NULL);
 
if (!abfd->my_archive)
return bfd_get_filename (abfd);
 
needed = (strlen (bfd_get_filename (abfd->my_archive))
+ strlen (bfd_get_filename (abfd)) + 3);
if (needed > curr)
{
if (curr)
free (buf);
curr = needed + (needed >> 1);
buf = (char *) bfd_malloc (curr);
/* If we can't malloc, fail safe by returning just the file name.
This function is only used when building error messages. */
if (!buf)
{
curr = 0;
return bfd_get_filename (abfd);
}
}
sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive),
bfd_get_filename (abfd));
return buf;
}
/contrib/toolchain/binutils/binutils/bucomm.h
0,0 → 1,79
/* bucomm.h -- binutils common include file.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
Free Software Foundation, Inc.
 
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 3 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., 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _BUCOMM_H
#define _BUCOMM_H
 
/* Return the filename in a static buffer. */
const char *bfd_get_archive_filename (const bfd *);
 
void bfd_nonfatal (const char *);
 
void bfd_nonfatal_message (const char *, const bfd *, const asection *,
const char *, ...);
 
void bfd_fatal (const char *) ATTRIBUTE_NORETURN;
 
void report (const char *, va_list) ATTRIBUTE_PRINTF(1,0);
 
void fatal (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
 
void non_fatal (const char *, ...) ATTRIBUTE_PRINTF_1;
 
void set_default_bfd_target (void);
 
void list_matching_formats (char **);
 
void list_supported_targets (const char *, FILE *);
 
void list_supported_architectures (const char *, FILE *);
 
int display_info (void);
 
void print_arelt_descr (FILE *, bfd *, bfd_boolean);
 
char *make_tempname (char *);
char *make_tempdir (char *);
 
bfd_vma parse_vma (const char *, const char *);
 
off_t get_file_size (const char *);
 
extern char *program_name;
 
/* filemode.c */
void mode_string (unsigned long, char *);
 
/* version.c */
extern void print_version (const char *);
 
/* rename.c */
extern void set_times (const char *, const struct stat *);
 
extern int smart_rename (const char *, const char *, int);
 
/* libiberty. */
void *xmalloc (size_t);
 
void *xrealloc (void *, size_t);
 
#endif /* _BUCOMM_H */
/contrib/toolchain/binutils/binutils/budbg.h
0,0 → 1,57
/* budbg.c -- Interfaces to the generic debugging information routines.
Copyright 1995, 1996, 2002, 2003, 2005, 2007, 2008, 2012
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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
#ifndef BUDBG_H
#define BUDBG_H
 
/* Routine used to read generic debugging information. */
 
extern void *read_debugging_info (bfd *, asymbol **, long, bfd_boolean);
 
/* Routine used to print generic debugging information. */
 
extern bfd_boolean print_debugging_info
(FILE *, void *, bfd *, asymbol **, void *, bfd_boolean);
 
/* Routines used to read and write stabs information. */
 
extern void *start_stab (void *, bfd *, bfd_boolean, asymbol **, long);
 
extern bfd_boolean finish_stab (void *, void *);
 
extern bfd_boolean parse_stab
(void *, void *, int, int, bfd_vma, const char *);
 
extern bfd_boolean write_stabs_in_sections_debugging_info
(bfd *, void *, bfd_byte **, bfd_size_type *, bfd_byte **, bfd_size_type *);
 
/* Routines used to read and write IEEE debugging information. */
 
extern bfd_boolean parse_ieee (void *, bfd *, const bfd_byte *, bfd_size_type);
 
extern bfd_boolean write_ieee_debugging_info (bfd *, void *);
 
/* Routine used to read COFF debugging information. */
 
extern bfd_boolean parse_coff (bfd *, asymbol **, long, void *);
 
#endif
/contrib/toolchain/binutils/binutils/config.h
0,0 → 1,273
/* config.h. Generated from config.in by configure. */
/* config.in. Generated from configure.in by autoheader. */
 
/* Check that config.h is #included before system headers
(this works only for glibc, but that should be enough). */
#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__) && !defined(__CONFIG_H__)
# error config.h must be #included before system headers
#endif
 
#define __CONFIG_H__ 1
 
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
systems. This function is required for `alloca.c' support on those systems.
*/
/* #undef CRAY_STACKSEG_END */
 
/* Define to 1 if using `alloca.c'. */
/* #undef C_ALLOCA */
 
/* Should ar and ranlib use -D behavior by default? */
#define DEFAULT_AR_DETERMINISTIC 0
 
/* Define to 1 if translation of program messages to the user's native
language is requested. */
/* #undef ENABLE_NLS */
 
/* Suffix used for executables, if any. */
#define EXECUTABLE_SUFFIX ".exe"
 
/* Define to 1 if you have `alloca', as a function or macro. */
#define HAVE_ALLOCA 1
 
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
*/
/* #undef HAVE_ALLOCA_H */
 
/* Define to 1 if you have the declaration of `environ', and to 0 if you
don't. */
#define HAVE_DECL_ENVIRON 1
 
/* Define to 1 if you have the declaration of `fprintf', and to 0 if you
don't. */
#define HAVE_DECL_FPRINTF 1
 
/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you
don't. */
#define HAVE_DECL_GETC_UNLOCKED 0
 
/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't.
*/
#define HAVE_DECL_GETENV 1
 
/* Is the prototype for getopt in <unistd.h> in the expected format? */
#define HAVE_DECL_GETOPT 1
 
/* Define to 1 if you have the declaration of `sbrk', and to 0 if you don't.
*/
#define HAVE_DECL_SBRK 0
 
/* Define to 1 if you have the declaration of `snprintf', and to 0 if you
don't. */
#define HAVE_DECL_SNPRINTF 1
 
/* Define to 1 if you have the declaration of `stpcpy', and to 0 if you don't.
*/
#define HAVE_DECL_STPCPY 0
 
/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
don't. */
#define HAVE_DECL_STRNLEN 0
 
/* Define to 1 if you have the declaration of `strstr', and to 0 if you don't.
*/
#define HAVE_DECL_STRSTR 1
 
/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
don't. */
#define HAVE_DECL_VSNPRINTF 1
 
/* Define to 1 if you have the <dlfcn.h> header file. */
/* #undef HAVE_DLFCN_H */
 
/* Does the platform use an executable suffix? */
#define HAVE_EXECUTABLE_SUFFIX 1
 
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
 
/* Define to 1 if you have the `getc_unlocked' function. */
/* #undef HAVE_GETC_UNLOCKED */
 
/* Does <utime.h> define struct utimbuf? */
#define HAVE_GOOD_UTIME_H 1
 
/* Define if you have the iconv() function. */
#define HAVE_ICONV 1
 
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
 
/* Define if your <locale.h> file defines LC_MESSAGES. */
/* #undef HAVE_LC_MESSAGES */
 
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
 
/* Define to 1 if you have the <locale.h> header file. */
#define HAVE_LOCALE_H 1
 
/* Define if mbstate_t exists in wchar.h. */
#define HAVE_MBSTATE_T 1
 
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
 
/* Define to 1 if you have the `mkdtemp' function. */
/* #undef HAVE_MKDTEMP */
 
/* Define to 1 if you have the `mkstemp' function. */
#define HAVE_MKSTEMP 1
 
/* Define to 1 if you have the `sbrk' function. */
/* #undef HAVE_SBRK */
 
/* Define to 1 if you have the `setlocale' function. */
#define HAVE_SETLOCALE 1
 
/* Define to 1 if you have the `setmode' function. */
#define HAVE_SETMODE 1
 
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
 
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
 
/* Define to 1 if you have the `strcoll' function. */
#define HAVE_STRCOLL 1
 
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
 
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
 
/* Define to 1 if you have the <sys/file.h> header file. */
#define HAVE_SYS_FILE_H 1
 
/* Define to 1 if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
 
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
 
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
 
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
/* #undef HAVE_SYS_WAIT_H */
 
/* Is the type time_t defined in <time.h>? */
#define HAVE_TIME_T_IN_TIME_H 1
 
/* Is the type time_t defined in <sys/types.h>? */
#define HAVE_TIME_T_IN_TYPES_H 1
 
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
 
/* Define to 1 if you have the `utimes' function. */
/* #undef HAVE_UTIMES */
 
/* Define to 1 if you have the <wchar.h> header file. */
//#define HAVE_WCHAR_H 1
 
/* Define to 1 if you have the <zlib.h> header file. */
#define HAVE_ZLIB_H 1
 
/* Define as const if the declaration of iconv() needs const. */
#define ICONV_CONST
 
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
 
/* Name of package */
#define PACKAGE "binutils"
 
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
 
/* Define to the full name of this package. */
#define PACKAGE_NAME ""
 
/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""
 
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""
 
/* Define to the home page for this package. */
#define PACKAGE_URL ""
 
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
 
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
automatically deduced at runtime.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown */
/* #undef STACK_DIRECTION */
 
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
 
/* Define if you can safely include both <string.h> and <strings.h>. */
#define STRING_WITH_STRINGS 1
 
/* Configured target name. */
#define TARGET "i686-pc-mingw32"
 
/* Define to 1 if user symbol names have a leading underscore, 0 if not. */
#define TARGET_PREPENDS_UNDERSCORE 1
 
/* Use b modifier when opening binary files? */
#define USE_BINARY_FOPEN 1
 
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
 
 
/* Version number of package */
#define VERSION "2.24"
 
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
`char[]'. */
/* #undef YYTEXT_POINTER */
 
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
 
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
 
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
 
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
 
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */
/contrib/toolchain/binutils/binutils/debug.c
0,0 → 1,3371
/* debug.c -- Handle generic debugging information.
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2005, 2007,
2009 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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
 
/* This file implements a generic debugging format. We may eventually
have readers which convert different formats into this generic
format, and writers which write it out. The initial impetus for
this was writing a converter from stabs to HP IEEE-695 debugging
format. */
 
#include "sysdep.h"
#include <assert.h>
#include "bfd.h"
#include "libiberty.h"
#include "filenames.h"
#include "debug.h"
 
/* Global information we keep for debugging. A pointer to this
structure is the debugging handle passed to all the routines. */
 
struct debug_handle
{
/* A linked list of compilation units. */
struct debug_unit *units;
/* The current compilation unit. */
struct debug_unit *current_unit;
/* The current source file. */
struct debug_file *current_file;
/* The current function. */
struct debug_function *current_function;
/* The current block. */
struct debug_block *current_block;
/* The current line number information for the current unit. */
struct debug_lineno *current_lineno;
/* Mark. This is used by debug_write. */
unsigned int mark;
/* A struct/class ID used by debug_write. */
unsigned int class_id;
/* The base for class_id for this call to debug_write. */
unsigned int base_id;
/* The current line number in debug_write. */
struct debug_lineno *current_write_lineno;
unsigned int current_write_lineno_index;
/* A list of classes which have assigned ID's during debug_write.
This is linked through the next_id field of debug_class_type. */
struct debug_class_id *id_list;
/* A list used to avoid recursion during debug_type_samep. */
struct debug_type_compare_list *compare_list;
};
 
/* Information we keep for a single compilation unit. */
 
struct debug_unit
{
/* The next compilation unit. */
struct debug_unit *next;
/* A list of files included in this compilation unit. The first
file is always the main one, and that is where the main file name
is stored. */
struct debug_file *files;
/* Line number information for this compilation unit. This is not
stored by function, because assembler code may have line number
information without function information. */
struct debug_lineno *linenos;
};
 
/* Information kept for a single source file. */
 
struct debug_file
{
/* The next source file in this compilation unit. */
struct debug_file *next;
/* The name of the source file. */
const char *filename;
/* Global functions, variables, types, etc. */
struct debug_namespace *globals;
};
 
/* A type. */
 
struct debug_type_s
{
/* Kind of type. */
enum debug_type_kind kind;
/* Size of type (0 if not known). */
unsigned int size;
/* Type which is a pointer to this type. */
debug_type pointer;
/* Tagged union with additional information about the type. */
union
{
/* DEBUG_KIND_INDIRECT. */
struct debug_indirect_type *kindirect;
/* DEBUG_KIND_INT. */
/* Whether the integer is unsigned. */
bfd_boolean kint;
/* DEBUG_KIND_STRUCT, DEBUG_KIND_UNION, DEBUG_KIND_CLASS,
DEBUG_KIND_UNION_CLASS. */
struct debug_class_type *kclass;
/* DEBUG_KIND_ENUM. */
struct debug_enum_type *kenum;
/* DEBUG_KIND_POINTER. */
struct debug_type_s *kpointer;
/* DEBUG_KIND_FUNCTION. */
struct debug_function_type *kfunction;
/* DEBUG_KIND_REFERENCE. */
struct debug_type_s *kreference;
/* DEBUG_KIND_RANGE. */
struct debug_range_type *krange;
/* DEBUG_KIND_ARRAY. */
struct debug_array_type *karray;
/* DEBUG_KIND_SET. */
struct debug_set_type *kset;
/* DEBUG_KIND_OFFSET. */
struct debug_offset_type *koffset;
/* DEBUG_KIND_METHOD. */
struct debug_method_type *kmethod;
/* DEBUG_KIND_CONST. */
struct debug_type_s *kconst;
/* DEBUG_KIND_VOLATILE. */
struct debug_type_s *kvolatile;
/* DEBUG_KIND_NAMED, DEBUG_KIND_TAGGED. */
struct debug_named_type *knamed;
} u;
};
 
/* Information kept for an indirect type. */
 
struct debug_indirect_type
{
/* Slot where the final type will appear. */
debug_type *slot;
/* Tag. */
const char *tag;
};
 
/* Information kept for a struct, union, or class. */
 
struct debug_class_type
{
/* NULL terminated array of fields. */
debug_field *fields;
/* A mark field which indicates whether the struct has already been
printed. */
unsigned int mark;
/* This is used to uniquely identify unnamed structs when printing. */
unsigned int id;
/* The remaining fields are only used for DEBUG_KIND_CLASS and
DEBUG_KIND_UNION_CLASS. */
/* NULL terminated array of base classes. */
debug_baseclass *baseclasses;
/* NULL terminated array of methods. */
debug_method *methods;
/* The type of the class providing the virtual function table for
this class. This may point to the type itself. */
debug_type vptrbase;
};
 
/* Information kept for an enum. */
 
struct debug_enum_type
{
/* NULL terminated array of names. */
const char **names;
/* Array of corresponding values. */
bfd_signed_vma *values;
};
 
/* Information kept for a function. FIXME: We should be able to
record the parameter types. */
 
struct debug_function_type
{
/* Return type. */
debug_type return_type;
/* NULL terminated array of argument types. */
debug_type *arg_types;
/* Whether the function takes a variable number of arguments. */
bfd_boolean varargs;
};
 
/* Information kept for a range. */
 
struct debug_range_type
{
/* Range base type. */
debug_type type;
/* Lower bound. */
bfd_signed_vma lower;
/* Upper bound. */
bfd_signed_vma upper;
};
 
/* Information kept for an array. */
 
struct debug_array_type
{
/* Element type. */
debug_type element_type;
/* Range type. */
debug_type range_type;
/* Lower bound. */
bfd_signed_vma lower;
/* Upper bound. */
bfd_signed_vma upper;
/* Whether this array is really a string. */
bfd_boolean stringp;
};
 
/* Information kept for a set. */
 
struct debug_set_type
{
/* Base type. */
debug_type type;
/* Whether this set is really a bitstring. */
bfd_boolean bitstringp;
};
 
/* Information kept for an offset type (a based pointer). */
 
struct debug_offset_type
{
/* The type the pointer is an offset from. */
debug_type base_type;
/* The type the pointer points to. */
debug_type target_type;
};
 
/* Information kept for a method type. */
 
struct debug_method_type
{
/* The return type. */
debug_type return_type;
/* The object type which this method is for. */
debug_type domain_type;
/* A NULL terminated array of argument types. */
debug_type *arg_types;
/* Whether the method takes a variable number of arguments. */
bfd_boolean varargs;
};
 
/* Information kept for a named type. */
 
struct debug_named_type
{
/* Name. */
struct debug_name *name;
/* Real type. */
debug_type type;
};
 
/* A field in a struct or union. */
 
struct debug_field_s
{
/* Name of the field. */
const char *name;
/* Type of the field. */
struct debug_type_s *type;
/* Visibility of the field. */
enum debug_visibility visibility;
/* Whether this is a static member. */
bfd_boolean static_member;
union
{
/* If static_member is false. */
struct
{
/* Bit position of the field in the struct. */
unsigned int bitpos;
/* Size of the field in bits. */
unsigned int bitsize;
} f;
/* If static_member is true. */
struct
{
const char *physname;
} s;
} u;
};
 
/* A base class for an object. */
 
struct debug_baseclass_s
{
/* Type of the base class. */
struct debug_type_s *type;
/* Bit position of the base class in the object. */
unsigned int bitpos;
/* Whether the base class is virtual. */
bfd_boolean is_virtual;
/* Visibility of the base class. */
enum debug_visibility visibility;
};
 
/* A method of an object. */
 
struct debug_method_s
{
/* The name of the method. */
const char *name;
/* A NULL terminated array of different types of variants. */
struct debug_method_variant_s **variants;
};
 
/* The variants of a method function of an object. These indicate
which method to run. */
 
struct debug_method_variant_s
{
/* The physical name of the function. */
const char *physname;
/* The type of the function. */
struct debug_type_s *type;
/* The visibility of the function. */
enum debug_visibility visibility;
/* Whether the function is const. */
bfd_boolean constp;
/* Whether the function is volatile. */
bfd_boolean volatilep;
/* The offset to the function in the virtual function table. */
bfd_vma voffset;
/* If voffset is VOFFSET_STATIC_METHOD, this is a static method. */
#define VOFFSET_STATIC_METHOD ((bfd_vma) -1)
/* Context of a virtual method function. */
struct debug_type_s *context;
};
 
/* A variable. This is the information we keep for a variable object.
This has no name; a name is associated with a variable in a
debug_name structure. */
 
struct debug_variable
{
/* Kind of variable. */
enum debug_var_kind kind;
/* Type. */
debug_type type;
/* Value. The interpretation of the value depends upon kind. */
bfd_vma val;
};
 
/* A function. This has no name; a name is associated with a function
in a debug_name structure. */
 
struct debug_function
{
/* Return type. */
debug_type return_type;
/* Parameter information. */
struct debug_parameter *parameters;
/* Block information. The first structure on the list is the main
block of the function, and describes function local variables. */
struct debug_block *blocks;
};
 
/* A function parameter. */
 
struct debug_parameter
{
/* Next parameter. */
struct debug_parameter *next;
/* Name. */
const char *name;
/* Type. */
debug_type type;
/* Kind. */
enum debug_parm_kind kind;
/* Value (meaning depends upon kind). */
bfd_vma val;
};
 
/* A typed constant. */
 
struct debug_typed_constant
{
/* Type. */
debug_type type;
/* Value. FIXME: We may eventually need to support non-integral
values. */
bfd_vma val;
};
 
/* Information about a block within a function. */
 
struct debug_block
{
/* Next block with the same parent. */
struct debug_block *next;
/* Parent block. */
struct debug_block *parent;
/* List of child blocks. */
struct debug_block *children;
/* Start address of the block. */
bfd_vma start;
/* End address of the block. */
bfd_vma end;
/* Local variables. */
struct debug_namespace *locals;
};
 
/* Line number information we keep for a compilation unit. FIXME:
This structure is easy to create, but can be very space
inefficient. */
 
struct debug_lineno
{
/* More line number information for this block. */
struct debug_lineno *next;
/* Source file. */
struct debug_file *file;
/* Line numbers, terminated by a -1 or the end of the array. */
#define DEBUG_LINENO_COUNT 10
unsigned long linenos[DEBUG_LINENO_COUNT];
/* Addresses for the line numbers. */
bfd_vma addrs[DEBUG_LINENO_COUNT];
};
 
/* A namespace. This is a mapping from names to objects. FIXME: This
should be implemented as a hash table. */
 
struct debug_namespace
{
/* List of items in this namespace. */
struct debug_name *list;
/* Pointer to where the next item in this namespace should go. */
struct debug_name **tail;
};
 
/* Kinds of objects that appear in a namespace. */
 
enum debug_object_kind
{
/* A type. */
DEBUG_OBJECT_TYPE,
/* A tagged type (really a different sort of namespace). */
DEBUG_OBJECT_TAG,
/* A variable. */
DEBUG_OBJECT_VARIABLE,
/* A function. */
DEBUG_OBJECT_FUNCTION,
/* An integer constant. */
DEBUG_OBJECT_INT_CONSTANT,
/* A floating point constant. */
DEBUG_OBJECT_FLOAT_CONSTANT,
/* A typed constant. */
DEBUG_OBJECT_TYPED_CONSTANT
};
 
/* Linkage of an object that appears in a namespace. */
 
enum debug_object_linkage
{
/* Local variable. */
DEBUG_LINKAGE_AUTOMATIC,
/* Static--either file static or function static, depending upon the
namespace is. */
DEBUG_LINKAGE_STATIC,
/* Global. */
DEBUG_LINKAGE_GLOBAL,
/* No linkage. */
DEBUG_LINKAGE_NONE
};
 
/* A name in a namespace. */
 
struct debug_name
{
/* Next name in this namespace. */
struct debug_name *next;
/* Name. */
const char *name;
/* Mark. This is used by debug_write. */
unsigned int mark;
/* Kind of object. */
enum debug_object_kind kind;
/* Linkage of object. */
enum debug_object_linkage linkage;
/* Tagged union with additional information about the object. */
union
{
/* DEBUG_OBJECT_TYPE. */
struct debug_type_s *type;
/* DEBUG_OBJECT_TAG. */
struct debug_type_s *tag;
/* DEBUG_OBJECT_VARIABLE. */
struct debug_variable *variable;
/* DEBUG_OBJECT_FUNCTION. */
struct debug_function *function;
/* DEBUG_OBJECT_INT_CONSTANT. */
bfd_vma int_constant;
/* DEBUG_OBJECT_FLOAT_CONSTANT. */
double float_constant;
/* DEBUG_OBJECT_TYPED_CONSTANT. */
struct debug_typed_constant *typed_constant;
} u;
};
 
/* During debug_write, a linked list of these structures is used to
keep track of ID numbers that have been assigned to classes. */
 
struct debug_class_id
{
/* Next ID number. */
struct debug_class_id *next;
/* The type with the ID. */
struct debug_type_s *type;
/* The tag; NULL if no tag. */
const char *tag;
};
 
/* During debug_type_samep, a linked list of these structures is kept
on the stack to avoid infinite recursion. */
 
struct debug_type_compare_list
{
/* Next type on list. */
struct debug_type_compare_list *next;
/* The types we are comparing. */
struct debug_type_s *t1;
struct debug_type_s *t2;
};
 
/* During debug_get_real_type, a linked list of these structures is
kept on the stack to avoid infinite recursion. */
 
struct debug_type_real_list
{
/* Next type on list. */
struct debug_type_real_list *next;
/* The type we are checking. */
struct debug_type_s *t;
};
 
/* Local functions. */
 
static void debug_error (const char *);
static struct debug_name *debug_add_to_namespace
(struct debug_handle *, struct debug_namespace **, const char *,
enum debug_object_kind, enum debug_object_linkage);
static struct debug_name *debug_add_to_current_namespace
(struct debug_handle *, const char *, enum debug_object_kind,
enum debug_object_linkage);
static struct debug_type_s *debug_make_type
(struct debug_handle *, enum debug_type_kind, unsigned int);
static struct debug_type_s *debug_get_real_type
(void *, debug_type, struct debug_type_real_list *);
static bfd_boolean debug_write_name
(struct debug_handle *, const struct debug_write_fns *, void *,
struct debug_name *);
static bfd_boolean debug_write_type
(struct debug_handle *, const struct debug_write_fns *, void *,
struct debug_type_s *, struct debug_name *);
static bfd_boolean debug_write_class_type
(struct debug_handle *, const struct debug_write_fns *, void *,
struct debug_type_s *, const char *);
static bfd_boolean debug_write_function
(struct debug_handle *, const struct debug_write_fns *, void *,
const char *, enum debug_object_linkage, struct debug_function *);
static bfd_boolean debug_write_block
(struct debug_handle *, const struct debug_write_fns *, void *,
struct debug_block *);
static bfd_boolean debug_write_linenos
(struct debug_handle *, const struct debug_write_fns *, void *, bfd_vma);
static bfd_boolean debug_set_class_id
(struct debug_handle *, const char *, struct debug_type_s *);
static bfd_boolean debug_type_samep
(struct debug_handle *, struct debug_type_s *, struct debug_type_s *);
static bfd_boolean debug_class_type_samep
(struct debug_handle *, struct debug_type_s *, struct debug_type_s *);
/* Issue an error message. */
 
static void
debug_error (const char *message)
{
fprintf (stderr, "%s\n", message);
}
 
/* Add an object to a namespace. */
 
static struct debug_name *
debug_add_to_namespace (struct debug_handle *info ATTRIBUTE_UNUSED,
struct debug_namespace **nsp, const char *name,
enum debug_object_kind kind,
enum debug_object_linkage linkage)
{
struct debug_name *n;
struct debug_namespace *ns;
 
n = (struct debug_name *) xmalloc (sizeof *n);
memset (n, 0, sizeof *n);
 
n->name = name;
n->kind = kind;
n->linkage = linkage;
 
ns = *nsp;
if (ns == NULL)
{
ns = (struct debug_namespace *) xmalloc (sizeof *ns);
memset (ns, 0, sizeof *ns);
 
ns->tail = &ns->list;
 
*nsp = ns;
}
 
*ns->tail = n;
ns->tail = &n->next;
 
return n;
}
 
/* Add an object to the current namespace. */
 
static struct debug_name *
debug_add_to_current_namespace (struct debug_handle *info, const char *name,
enum debug_object_kind kind,
enum debug_object_linkage linkage)
{
struct debug_namespace **nsp;
 
if (info->current_unit == NULL
|| info->current_file == NULL)
{
debug_error (_("debug_add_to_current_namespace: no current file"));
return NULL;
}
 
if (info->current_block != NULL)
nsp = &info->current_block->locals;
else
nsp = &info->current_file->globals;
 
return debug_add_to_namespace (info, nsp, name, kind, linkage);
}
/* Return a handle for debugging information. */
 
void *
debug_init (void)
{
struct debug_handle *ret;
 
ret = (struct debug_handle *) xmalloc (sizeof *ret);
memset (ret, 0, sizeof *ret);
return (void *) ret;
}
 
/* Set the source filename. This implicitly starts a new compilation
unit. */
 
bfd_boolean
debug_set_filename (void *handle, const char *name)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_file *nfile;
struct debug_unit *nunit;
 
if (name == NULL)
name = "";
 
nfile = (struct debug_file *) xmalloc (sizeof *nfile);
memset (nfile, 0, sizeof *nfile);
 
nfile->filename = name;
 
nunit = (struct debug_unit *) xmalloc (sizeof *nunit);
memset (nunit, 0, sizeof *nunit);
 
nunit->files = nfile;
info->current_file = nfile;
 
if (info->current_unit != NULL)
info->current_unit->next = nunit;
else
{
assert (info->units == NULL);
info->units = nunit;
}
 
info->current_unit = nunit;
 
info->current_function = NULL;
info->current_block = NULL;
info->current_lineno = NULL;
 
return TRUE;
}
 
/* Change source files to the given file name. This is used for
include files in a single compilation unit. */
 
bfd_boolean
debug_start_source (void *handle, const char *name)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_file *f, **pf;
 
if (name == NULL)
name = "";
 
if (info->current_unit == NULL)
{
debug_error (_("debug_start_source: no debug_set_filename call"));
return FALSE;
}
 
for (f = info->current_unit->files; f != NULL; f = f->next)
{
if (filename_cmp (f->filename, name) == 0)
{
info->current_file = f;
return TRUE;
}
}
 
f = (struct debug_file *) xmalloc (sizeof *f);
memset (f, 0, sizeof *f);
 
f->filename = name;
 
for (pf = &info->current_file->next;
*pf != NULL;
pf = &(*pf)->next)
;
*pf = f;
 
info->current_file = f;
 
return TRUE;
}
 
/* Record a function definition. This implicitly starts a function
block. The debug_type argument is the type of the return value.
The boolean indicates whether the function is globally visible.
The bfd_vma is the address of the start of the function. Currently
the parameter types are specified by calls to
debug_record_parameter. FIXME: There is no way to specify nested
functions. */
 
bfd_boolean
debug_record_function (void *handle, const char *name,
debug_type return_type, bfd_boolean global,
bfd_vma addr)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_function *f;
struct debug_block *b;
struct debug_name *n;
 
if (name == NULL)
name = "";
if (return_type == NULL)
return FALSE;
 
if (info->current_unit == NULL)
{
debug_error (_("debug_record_function: no debug_set_filename call"));
return FALSE;
}
 
f = (struct debug_function *) xmalloc (sizeof *f);
memset (f, 0, sizeof *f);
 
f->return_type = return_type;
 
b = (struct debug_block *) xmalloc (sizeof *b);
memset (b, 0, sizeof *b);
 
b->start = addr;
b->end = (bfd_vma) -1;
 
f->blocks = b;
 
info->current_function = f;
info->current_block = b;
 
/* FIXME: If we could handle nested functions, this would be the
place: we would want to use a different namespace. */
n = debug_add_to_namespace (info,
&info->current_file->globals,
name,
DEBUG_OBJECT_FUNCTION,
(global
? DEBUG_LINKAGE_GLOBAL
: DEBUG_LINKAGE_STATIC));
if (n == NULL)
return FALSE;
 
n->u.function = f;
 
return TRUE;
}
 
/* Record a parameter for the current function. */
 
bfd_boolean
debug_record_parameter (void *handle, const char *name, debug_type type,
enum debug_parm_kind kind, bfd_vma val)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_parameter *p, **pp;
 
if (name == NULL || type == NULL)
return FALSE;
 
if (info->current_unit == NULL
|| info->current_function == NULL)
{
debug_error (_("debug_record_parameter: no current function"));
return FALSE;
}
 
p = (struct debug_parameter *) xmalloc (sizeof *p);
memset (p, 0, sizeof *p);
 
p->name = name;
p->type = type;
p->kind = kind;
p->val = val;
 
for (pp = &info->current_function->parameters;
*pp != NULL;
pp = &(*pp)->next)
;
*pp = p;
 
return TRUE;
}
 
/* End a function. FIXME: This should handle function nesting. */
 
bfd_boolean
debug_end_function (void *handle, bfd_vma addr)
{
struct debug_handle *info = (struct debug_handle *) handle;
 
if (info->current_unit == NULL
|| info->current_block == NULL
|| info->current_function == NULL)
{
debug_error (_("debug_end_function: no current function"));
return FALSE;
}
 
if (info->current_block->parent != NULL)
{
debug_error (_("debug_end_function: some blocks were not closed"));
return FALSE;
}
 
info->current_block->end = addr;
 
info->current_function = NULL;
info->current_block = NULL;
 
return TRUE;
}
 
/* Start a block in a function. All local information will be
recorded in this block, until the matching call to debug_end_block.
debug_start_block and debug_end_block may be nested. The bfd_vma
argument is the address at which this block starts. */
 
bfd_boolean
debug_start_block (void *handle, bfd_vma addr)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_block *b, **pb;
 
/* We must always have a current block: debug_record_function sets
one up. */
if (info->current_unit == NULL
|| info->current_block == NULL)
{
debug_error (_("debug_start_block: no current block"));
return FALSE;
}
 
b = (struct debug_block *) xmalloc (sizeof *b);
memset (b, 0, sizeof *b);
 
b->parent = info->current_block;
b->start = addr;
b->end = (bfd_vma) -1;
 
/* This new block is a child of the current block. */
for (pb = &info->current_block->children;
*pb != NULL;
pb = &(*pb)->next)
;
*pb = b;
 
info->current_block = b;
 
return TRUE;
}
 
/* Finish a block in a function. This matches the call to
debug_start_block. The argument is the address at which this block
ends. */
 
bfd_boolean
debug_end_block (void *handle, bfd_vma addr)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_block *parent;
 
if (info->current_unit == NULL
|| info->current_block == NULL)
{
debug_error (_("debug_end_block: no current block"));
return FALSE;
}
 
parent = info->current_block->parent;
if (parent == NULL)
{
debug_error (_("debug_end_block: attempt to close top level block"));
return FALSE;
}
 
info->current_block->end = addr;
 
info->current_block = parent;
 
return TRUE;
}
 
/* Associate a line number in the current source file and function
with a given address. */
 
bfd_boolean
debug_record_line (void *handle, unsigned long lineno, bfd_vma addr)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_lineno *l;
unsigned int i;
 
if (info->current_unit == NULL)
{
debug_error (_("debug_record_line: no current unit"));
return FALSE;
}
 
l = info->current_lineno;
if (l != NULL && l->file == info->current_file)
{
for (i = 0; i < DEBUG_LINENO_COUNT; i++)
{
if (l->linenos[i] == (unsigned long) -1)
{
l->linenos[i] = lineno;
l->addrs[i] = addr;
return TRUE;
}
}
}
 
/* If we get here, then either 1) there is no current_lineno
structure, which means this is the first line number in this
compilation unit, 2) the current_lineno structure is for a
different file, or 3) the current_lineno structure is full.
Regardless, we want to allocate a new debug_lineno structure, put
it in the right place, and make it the new current_lineno
structure. */
 
l = (struct debug_lineno *) xmalloc (sizeof *l);
memset (l, 0, sizeof *l);
 
l->file = info->current_file;
l->linenos[0] = lineno;
l->addrs[0] = addr;
for (i = 1; i < DEBUG_LINENO_COUNT; i++)
l->linenos[i] = (unsigned long) -1;
 
if (info->current_lineno != NULL)
info->current_lineno->next = l;
else
info->current_unit->linenos = l;
 
info->current_lineno = l;
 
return TRUE;
}
 
/* Start a named common block. This is a block of variables that may
move in memory. */
 
bfd_boolean
debug_start_common_block (void *handle ATTRIBUTE_UNUSED,
const char *name ATTRIBUTE_UNUSED)
{
/* FIXME */
debug_error (_("debug_start_common_block: not implemented"));
return FALSE;
}
 
/* End a named common block. */
 
bfd_boolean
debug_end_common_block (void *handle ATTRIBUTE_UNUSED,
const char *name ATTRIBUTE_UNUSED)
{
/* FIXME */
debug_error (_("debug_end_common_block: not implemented"));
return FALSE;
}
 
/* Record a named integer constant. */
 
bfd_boolean
debug_record_int_const (void *handle, const char *name, bfd_vma val)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_name *n;
 
if (name == NULL)
return FALSE;
 
n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_INT_CONSTANT,
DEBUG_LINKAGE_NONE);
if (n == NULL)
return FALSE;
 
n->u.int_constant = val;
 
return TRUE;
}
 
/* Record a named floating point constant. */
 
bfd_boolean
debug_record_float_const (void *handle, const char *name, double val)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_name *n;
 
if (name == NULL)
return FALSE;
 
n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_FLOAT_CONSTANT,
DEBUG_LINKAGE_NONE);
if (n == NULL)
return FALSE;
 
n->u.float_constant = val;
 
return TRUE;
}
 
/* Record a typed constant with an integral value. */
 
bfd_boolean
debug_record_typed_const (void *handle, const char *name, debug_type type,
bfd_vma val)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_name *n;
struct debug_typed_constant *tc;
 
if (name == NULL || type == NULL)
return FALSE;
 
n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_TYPED_CONSTANT,
DEBUG_LINKAGE_NONE);
if (n == NULL)
return FALSE;
 
tc = (struct debug_typed_constant *) xmalloc (sizeof *tc);
memset (tc, 0, sizeof *tc);
 
tc->type = type;
tc->val = val;
 
n->u.typed_constant = tc;
 
return TRUE;
}
 
/* Record a label. */
 
bfd_boolean
debug_record_label (void *handle ATTRIBUTE_UNUSED,
const char *name ATTRIBUTE_UNUSED,
debug_type type ATTRIBUTE_UNUSED,
bfd_vma addr ATTRIBUTE_UNUSED)
{
/* FIXME. */
debug_error (_("debug_record_label: not implemented"));
return FALSE;
}
 
/* Record a variable. */
 
bfd_boolean
debug_record_variable (void *handle, const char *name, debug_type type,
enum debug_var_kind kind, bfd_vma val)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_namespace **nsp;
enum debug_object_linkage linkage;
struct debug_name *n;
struct debug_variable *v;
 
if (name == NULL || type == NULL)
return FALSE;
 
if (info->current_unit == NULL
|| info->current_file == NULL)
{
debug_error (_("debug_record_variable: no current file"));
return FALSE;
}
 
if (kind == DEBUG_GLOBAL || kind == DEBUG_STATIC)
{
nsp = &info->current_file->globals;
if (kind == DEBUG_GLOBAL)
linkage = DEBUG_LINKAGE_GLOBAL;
else
linkage = DEBUG_LINKAGE_STATIC;
}
else
{
if (info->current_block == NULL)
nsp = &info->current_file->globals;
else
nsp = &info->current_block->locals;
linkage = DEBUG_LINKAGE_AUTOMATIC;
}
 
n = debug_add_to_namespace (info, nsp, name, DEBUG_OBJECT_VARIABLE, linkage);
if (n == NULL)
return FALSE;
 
v = (struct debug_variable *) xmalloc (sizeof *v);
memset (v, 0, sizeof *v);
 
v->kind = kind;
v->type = type;
v->val = val;
 
n->u.variable = v;
 
return TRUE;
}
 
/* Make a type with a given kind and size. */
 
static struct debug_type_s *
debug_make_type (struct debug_handle *info ATTRIBUTE_UNUSED,
enum debug_type_kind kind, unsigned int size)
{
struct debug_type_s *t;
 
t = (struct debug_type_s *) xmalloc (sizeof *t);
memset (t, 0, sizeof *t);
 
t->kind = kind;
t->size = size;
 
return t;
}
 
/* Make an indirect type which may be used as a placeholder for a type
which is referenced before it is defined. */
 
debug_type
debug_make_indirect_type (void *handle, debug_type *slot, const char *tag)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_indirect_type *i;
 
t = debug_make_type (info, DEBUG_KIND_INDIRECT, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
i = (struct debug_indirect_type *) xmalloc (sizeof *i);
memset (i, 0, sizeof *i);
 
i->slot = slot;
i->tag = tag;
 
t->u.kindirect = i;
 
return t;
}
 
/* Make a void type. There is only one of these. */
 
debug_type
debug_make_void_type (void *handle)
{
struct debug_handle *info = (struct debug_handle *) handle;
 
return debug_make_type (info, DEBUG_KIND_VOID, 0);
}
 
/* Make an integer type of a given size. The boolean argument is true
if the integer is unsigned. */
 
debug_type
debug_make_int_type (void *handle, unsigned int size, bfd_boolean unsignedp)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
 
t = debug_make_type (info, DEBUG_KIND_INT, size);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
t->u.kint = unsignedp;
 
return t;
}
 
/* Make a floating point type of a given size. FIXME: On some
platforms, like an Alpha, you probably need to be able to specify
the format. */
 
debug_type
debug_make_float_type (void *handle, unsigned int size)
{
struct debug_handle *info = (struct debug_handle *) handle;
 
return debug_make_type (info, DEBUG_KIND_FLOAT, size);
}
 
/* Make a boolean type of a given size. */
 
debug_type
debug_make_bool_type (void *handle, unsigned int size)
{
struct debug_handle *info = (struct debug_handle *) handle;
 
return debug_make_type (info, DEBUG_KIND_BOOL, size);
}
 
/* Make a complex type of a given size. */
 
debug_type
debug_make_complex_type (void *handle, unsigned int size)
{
struct debug_handle *info = (struct debug_handle *) handle;
 
return debug_make_type (info, DEBUG_KIND_COMPLEX, size);
}
 
/* Make a structure type. The second argument is true for a struct,
false for a union. The third argument is the size of the struct.
The fourth argument is a NULL terminated array of fields. */
 
debug_type
debug_make_struct_type (void *handle, bfd_boolean structp, bfd_vma size,
debug_field *fields)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_class_type *c;
 
t = debug_make_type (info,
structp ? DEBUG_KIND_STRUCT : DEBUG_KIND_UNION,
size);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
c = (struct debug_class_type *) xmalloc (sizeof *c);
memset (c, 0, sizeof *c);
 
c->fields = fields;
 
t->u.kclass = c;
 
return t;
}
 
/* Make an object type. The first three arguments after the handle
are the same as for debug_make_struct_type. The next arguments are
a NULL terminated array of base classes, a NULL terminated array of
methods, the type of the object holding the virtual function table
if it is not this object, and a boolean which is true if this
object has its own virtual function table. */
 
debug_type
debug_make_object_type (void *handle, bfd_boolean structp, bfd_vma size,
debug_field *fields, debug_baseclass *baseclasses,
debug_method *methods, debug_type vptrbase,
bfd_boolean ownvptr)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_class_type *c;
 
t = debug_make_type (info,
structp ? DEBUG_KIND_CLASS : DEBUG_KIND_UNION_CLASS,
size);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
c = (struct debug_class_type *) xmalloc (sizeof *c);
memset (c, 0, sizeof *c);
 
c->fields = fields;
c->baseclasses = baseclasses;
c->methods = methods;
if (ownvptr)
c->vptrbase = t;
else
c->vptrbase = vptrbase;
 
t->u.kclass = c;
 
return t;
}
 
/* Make an enumeration type. The arguments are a null terminated
array of strings, and an array of corresponding values. */
 
debug_type
debug_make_enum_type (void *handle, const char **names,
bfd_signed_vma *values)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_enum_type *e;
 
t = debug_make_type (info, DEBUG_KIND_ENUM, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
e = (struct debug_enum_type *) xmalloc (sizeof *e);
memset (e, 0, sizeof *e);
 
e->names = names;
e->values = values;
 
t->u.kenum = e;
 
return t;
}
 
/* Make a pointer to a given type. */
 
debug_type
debug_make_pointer_type (void *handle, debug_type type)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
 
if (type == NULL)
return DEBUG_TYPE_NULL;
 
if (type->pointer != DEBUG_TYPE_NULL)
return type->pointer;
 
t = debug_make_type (info, DEBUG_KIND_POINTER, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
t->u.kpointer = type;
 
type->pointer = t;
 
return t;
}
 
/* Make a function returning a given type. FIXME: We should be able
to record the parameter types. */
 
debug_type
debug_make_function_type (void *handle, debug_type type,
debug_type *arg_types, bfd_boolean varargs)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_function_type *f;
 
if (type == NULL)
return DEBUG_TYPE_NULL;
 
t = debug_make_type (info, DEBUG_KIND_FUNCTION, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
f = (struct debug_function_type *) xmalloc (sizeof *f);
memset (f, 0, sizeof *f);
 
f->return_type = type;
f->arg_types = arg_types;
f->varargs = varargs;
 
t->u.kfunction = f;
 
return t;
}
 
/* Make a reference to a given type. */
 
debug_type
debug_make_reference_type (void *handle, debug_type type)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
 
if (type == NULL)
return DEBUG_TYPE_NULL;
 
t = debug_make_type (info, DEBUG_KIND_REFERENCE, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
t->u.kreference = type;
 
return t;
}
 
/* Make a range of a given type from a lower to an upper bound. */
 
debug_type
debug_make_range_type (void *handle, debug_type type, bfd_signed_vma lower,
bfd_signed_vma upper)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_range_type *r;
 
if (type == NULL)
return DEBUG_TYPE_NULL;
 
t = debug_make_type (info, DEBUG_KIND_RANGE, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
r = (struct debug_range_type *) xmalloc (sizeof *r);
memset (r, 0, sizeof *r);
 
r->type = type;
r->lower = lower;
r->upper = upper;
 
t->u.krange = r;
 
return t;
}
 
/* Make an array type. The second argument is the type of an element
of the array. The third argument is the type of a range of the
array. The fourth and fifth argument are the lower and upper
bounds, respectively. The sixth argument is true if this array is
actually a string, as in C. */
 
debug_type
debug_make_array_type (void *handle, debug_type element_type,
debug_type range_type, bfd_signed_vma lower,
bfd_signed_vma upper, bfd_boolean stringp)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_array_type *a;
 
if (element_type == NULL || range_type == NULL)
return DEBUG_TYPE_NULL;
 
t = debug_make_type (info, DEBUG_KIND_ARRAY, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
a = (struct debug_array_type *) xmalloc (sizeof *a);
memset (a, 0, sizeof *a);
 
a->element_type = element_type;
a->range_type = range_type;
a->lower = lower;
a->upper = upper;
a->stringp = stringp;
 
t->u.karray = a;
 
return t;
}
 
/* Make a set of a given type. For example, a Pascal set type. The
boolean argument is true if this set is actually a bitstring, as in
CHILL. */
 
debug_type
debug_make_set_type (void *handle, debug_type type, bfd_boolean bitstringp)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_set_type *s;
 
if (type == NULL)
return DEBUG_TYPE_NULL;
 
t = debug_make_type (info, DEBUG_KIND_SET, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
s = (struct debug_set_type *) xmalloc (sizeof *s);
memset (s, 0, sizeof *s);
 
s->type = type;
s->bitstringp = bitstringp;
 
t->u.kset = s;
 
return t;
}
 
/* Make a type for a pointer which is relative to an object. The
second argument is the type of the object to which the pointer is
relative. The third argument is the type that the pointer points
to. */
 
debug_type
debug_make_offset_type (void *handle, debug_type base_type,
debug_type target_type)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_offset_type *o;
 
if (base_type == NULL || target_type == NULL)
return DEBUG_TYPE_NULL;
 
t = debug_make_type (info, DEBUG_KIND_OFFSET, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
o = (struct debug_offset_type *) xmalloc (sizeof *o);
memset (o, 0, sizeof *o);
 
o->base_type = base_type;
o->target_type = target_type;
 
t->u.koffset = o;
 
return t;
}
 
/* Make a type for a method function. The second argument is the
return type, the third argument is the domain, and the fourth
argument is a NULL terminated array of argument types. */
 
debug_type
debug_make_method_type (void *handle, debug_type return_type,
debug_type domain_type, debug_type *arg_types,
bfd_boolean varargs)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_method_type *m;
 
if (return_type == NULL)
return DEBUG_TYPE_NULL;
 
t = debug_make_type (info, DEBUG_KIND_METHOD, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
m = (struct debug_method_type *) xmalloc (sizeof *m);
memset (m, 0, sizeof *m);
 
m->return_type = return_type;
m->domain_type = domain_type;
m->arg_types = arg_types;
m->varargs = varargs;
 
t->u.kmethod = m;
 
return t;
}
 
/* Make a const qualified version of a given type. */
 
debug_type
debug_make_const_type (void *handle, debug_type type)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
 
if (type == NULL)
return DEBUG_TYPE_NULL;
 
t = debug_make_type (info, DEBUG_KIND_CONST, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
t->u.kconst = type;
 
return t;
}
 
/* Make a volatile qualified version of a given type. */
 
debug_type
debug_make_volatile_type (void *handle, debug_type type)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
 
if (type == NULL)
return DEBUG_TYPE_NULL;
 
t = debug_make_type (info, DEBUG_KIND_VOLATILE, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
t->u.kvolatile = type;
 
return t;
}
 
/* Make an undefined tagged type. For example, a struct which has
been mentioned, but not defined. */
 
debug_type
debug_make_undefined_tagged_type (void *handle, const char *name,
enum debug_type_kind kind)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
 
if (name == NULL)
return DEBUG_TYPE_NULL;
 
switch (kind)
{
case DEBUG_KIND_STRUCT:
case DEBUG_KIND_UNION:
case DEBUG_KIND_CLASS:
case DEBUG_KIND_UNION_CLASS:
case DEBUG_KIND_ENUM:
break;
 
default:
debug_error (_("debug_make_undefined_type: unsupported kind"));
return DEBUG_TYPE_NULL;
}
 
t = debug_make_type (info, kind, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
return debug_tag_type (handle, name, t);
}
 
/* Make a base class for an object. The second argument is the base
class type. The third argument is the bit position of this base
class in the object (always 0 unless doing multiple inheritance).
The fourth argument is whether this is a virtual class. The fifth
argument is the visibility of the base class. */
 
debug_baseclass
debug_make_baseclass (void *handle ATTRIBUTE_UNUSED, debug_type type,
bfd_vma bitpos, bfd_boolean is_virtual,
enum debug_visibility visibility)
{
struct debug_baseclass_s *b;
 
b = (struct debug_baseclass_s *) xmalloc (sizeof *b);
memset (b, 0, sizeof *b);
 
b->type = type;
b->bitpos = bitpos;
b->is_virtual = is_virtual;
b->visibility = visibility;
 
return b;
}
 
/* Make a field for a struct. The second argument is the name. The
third argument is the type of the field. The fourth argument is
the bit position of the field. The fifth argument is the size of
the field (it may be zero). The sixth argument is the visibility
of the field. */
 
debug_field
debug_make_field (void *handle ATTRIBUTE_UNUSED, const char *name,
debug_type type, bfd_vma bitpos, bfd_vma bitsize,
enum debug_visibility visibility)
{
struct debug_field_s *f;
 
f = (struct debug_field_s *) xmalloc (sizeof *f);
memset (f, 0, sizeof *f);
 
f->name = name;
f->type = type;
f->static_member = FALSE;
f->u.f.bitpos = bitpos;
f->u.f.bitsize = bitsize;
f->visibility = visibility;
 
return f;
}
 
/* Make a static member of an object. The second argument is the
name. The third argument is the type of the member. The fourth
argument is the physical name of the member (i.e., the name as a
global variable). The fifth argument is the visibility of the
member. */
 
debug_field
debug_make_static_member (void *handle ATTRIBUTE_UNUSED, const char *name,
debug_type type, const char *physname,
enum debug_visibility visibility)
{
struct debug_field_s *f;
 
f = (struct debug_field_s *) xmalloc (sizeof *f);
memset (f, 0, sizeof *f);
 
f->name = name;
f->type = type;
f->static_member = TRUE;
f->u.s.physname = physname;
f->visibility = visibility;
 
return f;
}
 
/* Make a method. The second argument is the name, and the third
argument is a NULL terminated array of method variants. */
 
debug_method
debug_make_method (void *handle ATTRIBUTE_UNUSED, const char *name,
debug_method_variant *variants)
{
struct debug_method_s *m;
 
m = (struct debug_method_s *) xmalloc (sizeof *m);
memset (m, 0, sizeof *m);
 
m->name = name;
m->variants = variants;
 
return m;
}
 
/* Make a method argument. The second argument is the real name of
the function. The third argument is the type of the function. The
fourth argument is the visibility. The fifth argument is whether
this is a const function. The sixth argument is whether this is a
volatile function. The seventh argument is the offset in the
virtual function table, if any. The eighth argument is the virtual
function context. FIXME: Are the const and volatile arguments
necessary? Could we just use debug_make_const_type? */
 
debug_method_variant
debug_make_method_variant (void *handle ATTRIBUTE_UNUSED,
const char *physname, debug_type type,
enum debug_visibility visibility,
bfd_boolean constp, bfd_boolean volatilep,
bfd_vma voffset, debug_type context)
{
struct debug_method_variant_s *m;
 
m = (struct debug_method_variant_s *) xmalloc (sizeof *m);
memset (m, 0, sizeof *m);
 
m->physname = physname;
m->type = type;
m->visibility = visibility;
m->constp = constp;
m->volatilep = volatilep;
m->voffset = voffset;
m->context = context;
 
return m;
}
 
/* Make a static method argument. The arguments are the same as for
debug_make_method_variant, except that the last two are omitted
since a static method can not also be virtual. */
 
debug_method_variant
debug_make_static_method_variant (void *handle ATTRIBUTE_UNUSED,
const char *physname, debug_type type,
enum debug_visibility visibility,
bfd_boolean constp, bfd_boolean volatilep)
{
struct debug_method_variant_s *m;
 
m = (struct debug_method_variant_s *) xmalloc (sizeof *m);
memset (m, 0, sizeof *m);
 
m->physname = physname;
m->type = type;
m->visibility = visibility;
m->constp = constp;
m->volatilep = volatilep;
m->voffset = VOFFSET_STATIC_METHOD;
 
return m;
}
 
/* Name a type. */
 
debug_type
debug_name_type (void *handle, const char *name, debug_type type)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_named_type *n;
struct debug_name *nm;
 
if (name == NULL || type == NULL)
return DEBUG_TYPE_NULL;
 
if (info->current_unit == NULL
|| info->current_file == NULL)
{
debug_error (_("debug_name_type: no current file"));
return DEBUG_TYPE_NULL;
}
 
t = debug_make_type (info, DEBUG_KIND_NAMED, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
n = (struct debug_named_type *) xmalloc (sizeof *n);
memset (n, 0, sizeof *n);
 
n->type = type;
 
t->u.knamed = n;
 
/* We always add the name to the global namespace. This is probably
wrong in some cases, but it seems to be right for stabs. FIXME. */
 
nm = debug_add_to_namespace (info, &info->current_file->globals, name,
DEBUG_OBJECT_TYPE, DEBUG_LINKAGE_NONE);
if (nm == NULL)
return DEBUG_TYPE_NULL;
 
nm->u.type = t;
 
n->name = nm;
 
return t;
}
 
/* Tag a type. */
 
debug_type
debug_tag_type (void *handle, const char *name, debug_type type)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_type_s *t;
struct debug_named_type *n;
struct debug_name *nm;
 
if (name == NULL || type == NULL)
return DEBUG_TYPE_NULL;
 
if (info->current_file == NULL)
{
debug_error (_("debug_tag_type: no current file"));
return DEBUG_TYPE_NULL;
}
 
if (type->kind == DEBUG_KIND_TAGGED)
{
if (strcmp (type->u.knamed->name->name, name) == 0)
return type;
debug_error (_("debug_tag_type: extra tag attempted"));
return DEBUG_TYPE_NULL;
}
 
t = debug_make_type (info, DEBUG_KIND_TAGGED, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
 
n = (struct debug_named_type *) xmalloc (sizeof *n);
memset (n, 0, sizeof *n);
 
n->type = type;
 
t->u.knamed = n;
 
/* We keep a global namespace of tags for each compilation unit. I
don't know if that is the right thing to do. */
 
nm = debug_add_to_namespace (info, &info->current_file->globals, name,
DEBUG_OBJECT_TAG, DEBUG_LINKAGE_NONE);
if (nm == NULL)
return DEBUG_TYPE_NULL;
 
nm->u.tag = t;
 
n->name = nm;
 
return t;
}
 
/* Record the size of a given type. */
 
bfd_boolean
debug_record_type_size (void *handle ATTRIBUTE_UNUSED, debug_type type,
unsigned int size)
{
if (type->size != 0 && type->size != size)
fprintf (stderr, _("Warning: changing type size from %d to %d\n"),
type->size, size);
 
type->size = size;
 
return TRUE;
}
 
/* Find a named type. */
 
debug_type
debug_find_named_type (void *handle, const char *name)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_block *b;
struct debug_file *f;
 
/* We only search the current compilation unit. I don't know if
this is right or not. */
 
if (info->current_unit == NULL)
{
debug_error (_("debug_find_named_type: no current compilation unit"));
return DEBUG_TYPE_NULL;
}
 
for (b = info->current_block; b != NULL; b = b->parent)
{
if (b->locals != NULL)
{
struct debug_name *n;
 
for (n = b->locals->list; n != NULL; n = n->next)
{
if (n->kind == DEBUG_OBJECT_TYPE
&& n->name[0] == name[0]
&& strcmp (n->name, name) == 0)
return n->u.type;
}
}
}
 
for (f = info->current_unit->files; f != NULL; f = f->next)
{
if (f->globals != NULL)
{
struct debug_name *n;
 
for (n = f->globals->list; n != NULL; n = n->next)
{
if (n->kind == DEBUG_OBJECT_TYPE
&& n->name[0] == name[0]
&& strcmp (n->name, name) == 0)
return n->u.type;
}
}
}
 
return DEBUG_TYPE_NULL;
}
 
/* Find a tagged type. */
 
debug_type
debug_find_tagged_type (void *handle, const char *name,
enum debug_type_kind kind)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_unit *u;
 
/* We search the globals of all the compilation units. I don't know
if this is correct or not. It would be easy to change. */
 
for (u = info->units; u != NULL; u = u->next)
{
struct debug_file *f;
 
for (f = u->files; f != NULL; f = f->next)
{
struct debug_name *n;
 
if (f->globals != NULL)
{
for (n = f->globals->list; n != NULL; n = n->next)
{
if (n->kind == DEBUG_OBJECT_TAG
&& (kind == DEBUG_KIND_ILLEGAL
|| n->u.tag->kind == kind)
&& n->name[0] == name[0]
&& strcmp (n->name, name) == 0)
return n->u.tag;
}
}
}
}
 
return DEBUG_TYPE_NULL;
}
 
/* Get a base type. We build a linked list on the stack to avoid
crashing if the type is defined circularly. */
 
static struct debug_type_s *
debug_get_real_type (void *handle, debug_type type,
struct debug_type_real_list *list)
{
struct debug_type_real_list *l;
struct debug_type_real_list rl;
 
switch (type->kind)
{
default:
return type;
 
case DEBUG_KIND_INDIRECT:
case DEBUG_KIND_NAMED:
case DEBUG_KIND_TAGGED:
break;
}
 
for (l = list; l != NULL; l = l->next)
{
if (l->t == type || l == l->next)
{
fprintf (stderr,
_("debug_get_real_type: circular debug information for %s\n"),
debug_get_type_name (handle, type));
return NULL;
}
}
 
rl.next = list;
rl.t = type;
 
switch (type->kind)
{
/* The default case is just here to avoid warnings. */
default:
case DEBUG_KIND_INDIRECT:
if (*type->u.kindirect->slot != NULL)
return debug_get_real_type (handle, *type->u.kindirect->slot, &rl);
return type;
case DEBUG_KIND_NAMED:
case DEBUG_KIND_TAGGED:
return debug_get_real_type (handle, type->u.knamed->type, &rl);
}
/*NOTREACHED*/
}
 
/* Get the kind of a type. */
 
enum debug_type_kind
debug_get_type_kind (void *handle, debug_type type)
{
if (type == NULL)
return DEBUG_KIND_ILLEGAL;
type = debug_get_real_type (handle, type, NULL);
if (type == NULL)
return DEBUG_KIND_ILLEGAL;
return type->kind;
}
 
/* Get the name of a type. */
 
const char *
debug_get_type_name (void *handle, debug_type type)
{
if (type->kind == DEBUG_KIND_INDIRECT)
{
if (*type->u.kindirect->slot != NULL)
return debug_get_type_name (handle, *type->u.kindirect->slot);
return type->u.kindirect->tag;
}
if (type->kind == DEBUG_KIND_NAMED
|| type->kind == DEBUG_KIND_TAGGED)
return type->u.knamed->name->name;
return NULL;
}
 
/* Get the size of a type. */
 
bfd_vma
debug_get_type_size (void *handle, debug_type type)
{
if (type == NULL)
return 0;
 
/* We don't call debug_get_real_type, because somebody might have
called debug_record_type_size on a named or indirect type. */
 
if (type->size != 0)
return type->size;
 
switch (type->kind)
{
default:
return 0;
case DEBUG_KIND_INDIRECT:
if (*type->u.kindirect->slot != NULL)
return debug_get_type_size (handle, *type->u.kindirect->slot);
return 0;
case DEBUG_KIND_NAMED:
case DEBUG_KIND_TAGGED:
return debug_get_type_size (handle, type->u.knamed->type);
}
/*NOTREACHED*/
}
 
/* Get the return type of a function or method type. */
 
debug_type
debug_get_return_type (void *handle, debug_type type)
{
if (type == NULL)
return DEBUG_TYPE_NULL;
 
type = debug_get_real_type (handle, type, NULL);
if (type == NULL)
return DEBUG_TYPE_NULL;
 
switch (type->kind)
{
default:
return DEBUG_TYPE_NULL;
case DEBUG_KIND_FUNCTION:
return type->u.kfunction->return_type;
case DEBUG_KIND_METHOD:
return type->u.kmethod->return_type;
}
/*NOTREACHED*/
}
 
/* Get the parameter types of a function or method type (except that
we don't currently store the parameter types of a function). */
 
const debug_type *
debug_get_parameter_types (void *handle, debug_type type,
bfd_boolean *pvarargs)
{
if (type == NULL)
return NULL;
 
type = debug_get_real_type (handle, type, NULL);
if (type == NULL)
return NULL;
 
switch (type->kind)
{
default:
return NULL;
case DEBUG_KIND_FUNCTION:
*pvarargs = type->u.kfunction->varargs;
return type->u.kfunction->arg_types;
case DEBUG_KIND_METHOD:
*pvarargs = type->u.kmethod->varargs;
return type->u.kmethod->arg_types;
}
/*NOTREACHED*/
}
 
/* Get the target type of a type. */
 
debug_type
debug_get_target_type (void *handle, debug_type type)
{
if (type == NULL)
return NULL;
 
type = debug_get_real_type (handle, type, NULL);
if (type == NULL)
return NULL;
 
switch (type->kind)
{
default:
return NULL;
case DEBUG_KIND_POINTER:
return type->u.kpointer;
case DEBUG_KIND_REFERENCE:
return type->u.kreference;
case DEBUG_KIND_CONST:
return type->u.kconst;
case DEBUG_KIND_VOLATILE:
return type->u.kvolatile;
}
/*NOTREACHED*/
}
 
/* Get the NULL terminated array of fields for a struct, union, or
class. */
 
const debug_field *
debug_get_fields (void *handle, debug_type type)
{
if (type == NULL)
return NULL;
 
type = debug_get_real_type (handle, type, NULL);
if (type == NULL)
return NULL;
 
switch (type->kind)
{
default:
return NULL;
case DEBUG_KIND_STRUCT:
case DEBUG_KIND_UNION:
case DEBUG_KIND_CLASS:
case DEBUG_KIND_UNION_CLASS:
return type->u.kclass->fields;
}
/*NOTREACHED*/
}
 
/* Get the type of a field. */
 
debug_type
debug_get_field_type (void *handle ATTRIBUTE_UNUSED, debug_field field)
{
if (field == NULL)
return NULL;
return field->type;
}
 
/* Get the name of a field. */
 
const char *
debug_get_field_name (void *handle ATTRIBUTE_UNUSED, debug_field field)
{
if (field == NULL)
return NULL;
return field->name;
}
 
/* Get the bit position of a field. */
 
bfd_vma
debug_get_field_bitpos (void *handle ATTRIBUTE_UNUSED, debug_field field)
{
if (field == NULL || field->static_member)
return (bfd_vma) -1;
return field->u.f.bitpos;
}
 
/* Get the bit size of a field. */
 
bfd_vma
debug_get_field_bitsize (void *handle ATTRIBUTE_UNUSED, debug_field field)
{
if (field == NULL || field->static_member)
return (bfd_vma) -1;
return field->u.f.bitsize;
}
 
/* Get the visibility of a field. */
 
enum debug_visibility
debug_get_field_visibility (void *handle ATTRIBUTE_UNUSED, debug_field field)
{
if (field == NULL)
return DEBUG_VISIBILITY_IGNORE;
return field->visibility;
}
 
/* Get the physical name of a field. */
 
const char *
debug_get_field_physname (void *handle ATTRIBUTE_UNUSED, debug_field field)
{
if (field == NULL || ! field->static_member)
return NULL;
return field->u.s.physname;
}
/* Write out the debugging information. This is given a handle to
debugging information, and a set of function pointers to call. */
 
bfd_boolean
debug_write (void *handle, const struct debug_write_fns *fns, void *fhandle)
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_unit *u;
 
/* We use a mark to tell whether we have already written out a
particular name. We use an integer, so that we don't have to
clear the mark fields if we happen to write out the same
information more than once. */
++info->mark;
 
/* The base_id field holds an ID value which will never be used, so
that we can tell whether we have assigned an ID during this call
to debug_write. */
info->base_id = info->class_id;
 
/* We keep a linked list of classes for which was have assigned ID's
during this call to debug_write. */
info->id_list = NULL;
 
for (u = info->units; u != NULL; u = u->next)
{
struct debug_file *f;
bfd_boolean first_file;
 
info->current_write_lineno = u->linenos;
info->current_write_lineno_index = 0;
 
if (! (*fns->start_compilation_unit) (fhandle, u->files->filename))
return FALSE;
 
first_file = TRUE;
for (f = u->files; f != NULL; f = f->next)
{
struct debug_name *n;
 
if (first_file)
first_file = FALSE;
else if (! (*fns->start_source) (fhandle, f->filename))
return FALSE;
 
if (f->globals != NULL)
for (n = f->globals->list; n != NULL; n = n->next)
if (! debug_write_name (info, fns, fhandle, n))
return FALSE;
}
 
/* Output any line number information which hasn't already been
handled. */
if (! debug_write_linenos (info, fns, fhandle, (bfd_vma) -1))
return FALSE;
}
 
return TRUE;
}
 
/* Write out an element in a namespace. */
 
static bfd_boolean
debug_write_name (struct debug_handle *info,
const struct debug_write_fns *fns, void *fhandle,
struct debug_name *n)
{
switch (n->kind)
{
case DEBUG_OBJECT_TYPE:
if (! debug_write_type (info, fns, fhandle, n->u.type, n)
|| ! (*fns->typdef) (fhandle, n->name))
return FALSE;
return TRUE;
case DEBUG_OBJECT_TAG:
if (! debug_write_type (info, fns, fhandle, n->u.tag, n))
return FALSE;
return (*fns->tag) (fhandle, n->name);
case DEBUG_OBJECT_VARIABLE:
if (! debug_write_type (info, fns, fhandle, n->u.variable->type,
(struct debug_name *) NULL))
return FALSE;
return (*fns->variable) (fhandle, n->name, n->u.variable->kind,
n->u.variable->val);
case DEBUG_OBJECT_FUNCTION:
return debug_write_function (info, fns, fhandle, n->name,
n->linkage, n->u.function);
case DEBUG_OBJECT_INT_CONSTANT:
return (*fns->int_constant) (fhandle, n->name, n->u.int_constant);
case DEBUG_OBJECT_FLOAT_CONSTANT:
return (*fns->float_constant) (fhandle, n->name, n->u.float_constant);
case DEBUG_OBJECT_TYPED_CONSTANT:
if (! debug_write_type (info, fns, fhandle, n->u.typed_constant->type,
(struct debug_name *) NULL))
return FALSE;
return (*fns->typed_constant) (fhandle, n->name,
n->u.typed_constant->val);
default:
abort ();
return FALSE;
}
/*NOTREACHED*/
}
 
/* Write out a type. If the type is DEBUG_KIND_NAMED or
DEBUG_KIND_TAGGED, then the name argument is the name for which we
are about to call typedef or tag. If the type is anything else,
then the name argument is a tag from a DEBUG_KIND_TAGGED type which
points to this one. */
 
static bfd_boolean
debug_write_type (struct debug_handle *info,
const struct debug_write_fns *fns, void *fhandle,
struct debug_type_s *type, struct debug_name *name)
{
unsigned int i;
int is;
const char *tag = NULL;
 
/* If we have a name for this type, just output it. We only output
typedef names after they have been defined. We output type tags
whenever we are not actually defining them. */
if ((type->kind == DEBUG_KIND_NAMED
|| type->kind == DEBUG_KIND_TAGGED)
&& (type->u.knamed->name->mark == info->mark
|| (type->kind == DEBUG_KIND_TAGGED
&& type->u.knamed->name != name)))
{
if (type->kind == DEBUG_KIND_NAMED)
return (*fns->typedef_type) (fhandle, type->u.knamed->name->name);
else
{
struct debug_type_s *real;
unsigned int id;
 
real = debug_get_real_type ((void *) info, type, NULL);
if (real == NULL)
return (*fns->empty_type) (fhandle);
id = 0;
if ((real->kind == DEBUG_KIND_STRUCT
|| real->kind == DEBUG_KIND_UNION
|| real->kind == DEBUG_KIND_CLASS
|| real->kind == DEBUG_KIND_UNION_CLASS)
&& real->u.kclass != NULL)
{
if (real->u.kclass->id <= info->base_id)
{
if (! debug_set_class_id (info,
type->u.knamed->name->name,
real))
return FALSE;
}
id = real->u.kclass->id;
}
 
return (*fns->tag_type) (fhandle, type->u.knamed->name->name, id,
real->kind);
}
}
 
/* Mark the name after we have already looked for a known name, so
that we don't just define a type in terms of itself. We need to
mark the name here so that a struct containing a pointer to
itself will work. */
if (name != NULL)
name->mark = info->mark;
 
if (name != NULL
&& type->kind != DEBUG_KIND_NAMED
&& type->kind != DEBUG_KIND_TAGGED)
{
assert (name->kind == DEBUG_OBJECT_TAG);
tag = name->name;
}
 
switch (type->kind)
{
case DEBUG_KIND_ILLEGAL:
debug_error (_("debug_write_type: illegal type encountered"));
return FALSE;
case DEBUG_KIND_INDIRECT:
if (*type->u.kindirect->slot == DEBUG_TYPE_NULL)
return (*fns->empty_type) (fhandle);
return debug_write_type (info, fns, fhandle, *type->u.kindirect->slot,
name);
case DEBUG_KIND_VOID:
return (*fns->void_type) (fhandle);
case DEBUG_KIND_INT:
return (*fns->int_type) (fhandle, type->size, type->u.kint);
case DEBUG_KIND_FLOAT:
return (*fns->float_type) (fhandle, type->size);
case DEBUG_KIND_COMPLEX:
return (*fns->complex_type) (fhandle, type->size);
case DEBUG_KIND_BOOL:
return (*fns->bool_type) (fhandle, type->size);
case DEBUG_KIND_STRUCT:
case DEBUG_KIND_UNION:
if (type->u.kclass != NULL)
{
if (type->u.kclass->id <= info->base_id)
{
if (! debug_set_class_id (info, tag, type))
return FALSE;
}
 
if (info->mark == type->u.kclass->mark)
{
/* We are currently outputting this struct, or we have
already output it. I don't know if this can happen,
but it can happen for a class. */
assert (type->u.kclass->id > info->base_id);
return (*fns->tag_type) (fhandle, tag, type->u.kclass->id,
type->kind);
}
type->u.kclass->mark = info->mark;
}
 
if (! (*fns->start_struct_type) (fhandle, tag,
(type->u.kclass != NULL
? type->u.kclass->id
: 0),
type->kind == DEBUG_KIND_STRUCT,
type->size))
return FALSE;
if (type->u.kclass != NULL
&& type->u.kclass->fields != NULL)
{
for (i = 0; type->u.kclass->fields[i] != NULL; i++)
{
struct debug_field_s *f;
 
f = type->u.kclass->fields[i];
if (! debug_write_type (info, fns, fhandle, f->type,
(struct debug_name *) NULL)
|| ! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos,
f->u.f.bitsize, f->visibility))
return FALSE;
}
}
return (*fns->end_struct_type) (fhandle);
case DEBUG_KIND_CLASS:
case DEBUG_KIND_UNION_CLASS:
return debug_write_class_type (info, fns, fhandle, type, tag);
case DEBUG_KIND_ENUM:
if (type->u.kenum == NULL)
return (*fns->enum_type) (fhandle, tag, (const char **) NULL,
(bfd_signed_vma *) NULL);
return (*fns->enum_type) (fhandle, tag, type->u.kenum->names,
type->u.kenum->values);
case DEBUG_KIND_POINTER:
if (! debug_write_type (info, fns, fhandle, type->u.kpointer,
(struct debug_name *) NULL))
return FALSE;
return (*fns->pointer_type) (fhandle);
case DEBUG_KIND_FUNCTION:
if (! debug_write_type (info, fns, fhandle,
type->u.kfunction->return_type,
(struct debug_name *) NULL))
return FALSE;
if (type->u.kfunction->arg_types == NULL)
is = -1;
else
{
for (is = 0; type->u.kfunction->arg_types[is] != NULL; is++)
if (! debug_write_type (info, fns, fhandle,
type->u.kfunction->arg_types[is],
(struct debug_name *) NULL))
return FALSE;
}
return (*fns->function_type) (fhandle, is,
type->u.kfunction->varargs);
case DEBUG_KIND_REFERENCE:
if (! debug_write_type (info, fns, fhandle, type->u.kreference,
(struct debug_name *) NULL))
return FALSE;
return (*fns->reference_type) (fhandle);
case DEBUG_KIND_RANGE:
if (! debug_write_type (info, fns, fhandle, type->u.krange->type,
(struct debug_name *) NULL))
return FALSE;
return (*fns->range_type) (fhandle, type->u.krange->lower,
type->u.krange->upper);
case DEBUG_KIND_ARRAY:
if (! debug_write_type (info, fns, fhandle, type->u.karray->element_type,
(struct debug_name *) NULL)
|| ! debug_write_type (info, fns, fhandle,
type->u.karray->range_type,
(struct debug_name *) NULL))
return FALSE;
return (*fns->array_type) (fhandle, type->u.karray->lower,
type->u.karray->upper,
type->u.karray->stringp);
case DEBUG_KIND_SET:
if (! debug_write_type (info, fns, fhandle, type->u.kset->type,
(struct debug_name *) NULL))
return FALSE;
return (*fns->set_type) (fhandle, type->u.kset->bitstringp);
case DEBUG_KIND_OFFSET:
if (! debug_write_type (info, fns, fhandle, type->u.koffset->base_type,
(struct debug_name *) NULL)
|| ! debug_write_type (info, fns, fhandle,
type->u.koffset->target_type,
(struct debug_name *) NULL))
return FALSE;
return (*fns->offset_type) (fhandle);
case DEBUG_KIND_METHOD:
if (! debug_write_type (info, fns, fhandle,
type->u.kmethod->return_type,
(struct debug_name *) NULL))
return FALSE;
if (type->u.kmethod->arg_types == NULL)
is = -1;
else
{
for (is = 0; type->u.kmethod->arg_types[is] != NULL; is++)
if (! debug_write_type (info, fns, fhandle,
type->u.kmethod->arg_types[is],
(struct debug_name *) NULL))
return FALSE;
}
if (type->u.kmethod->domain_type != NULL)
{
if (! debug_write_type (info, fns, fhandle,
type->u.kmethod->domain_type,
(struct debug_name *) NULL))
return FALSE;
}
return (*fns->method_type) (fhandle,
type->u.kmethod->domain_type != NULL,
is,
type->u.kmethod->varargs);
case DEBUG_KIND_CONST:
if (! debug_write_type (info, fns, fhandle, type->u.kconst,
(struct debug_name *) NULL))
return FALSE;
return (*fns->const_type) (fhandle);
case DEBUG_KIND_VOLATILE:
if (! debug_write_type (info, fns, fhandle, type->u.kvolatile,
(struct debug_name *) NULL))
return FALSE;
return (*fns->volatile_type) (fhandle);
case DEBUG_KIND_NAMED:
return debug_write_type (info, fns, fhandle, type->u.knamed->type,
(struct debug_name *) NULL);
case DEBUG_KIND_TAGGED:
return debug_write_type (info, fns, fhandle, type->u.knamed->type,
type->u.knamed->name);
default:
abort ();
return FALSE;
}
}
 
/* Write out a class type. */
 
static bfd_boolean
debug_write_class_type (struct debug_handle *info,
const struct debug_write_fns *fns, void *fhandle,
struct debug_type_s *type, const char *tag)
{
unsigned int i;
unsigned int id;
struct debug_type_s *vptrbase;
 
if (type->u.kclass == NULL)
{
id = 0;
vptrbase = NULL;
}
else
{
if (type->u.kclass->id <= info->base_id)
{
if (! debug_set_class_id (info, tag, type))
return FALSE;
}
 
if (info->mark == type->u.kclass->mark)
{
/* We are currently outputting this class, or we have
already output it. This can happen when there are
methods for an anonymous class. */
assert (type->u.kclass->id > info->base_id);
return (*fns->tag_type) (fhandle, tag, type->u.kclass->id,
type->kind);
}
type->u.kclass->mark = info->mark;
id = type->u.kclass->id;
 
vptrbase = type->u.kclass->vptrbase;
if (vptrbase != NULL && vptrbase != type)
{
if (! debug_write_type (info, fns, fhandle, vptrbase,
(struct debug_name *) NULL))
return FALSE;
}
}
 
if (! (*fns->start_class_type) (fhandle, tag, id,
type->kind == DEBUG_KIND_CLASS,
type->size,
vptrbase != NULL,
vptrbase == type))
return FALSE;
 
if (type->u.kclass != NULL)
{
if (type->u.kclass->fields != NULL)
{
for (i = 0; type->u.kclass->fields[i] != NULL; i++)
{
struct debug_field_s *f;
 
f = type->u.kclass->fields[i];
if (! debug_write_type (info, fns, fhandle, f->type,
(struct debug_name *) NULL))
return FALSE;
if (f->static_member)
{
if (! (*fns->class_static_member) (fhandle, f->name,
f->u.s.physname,
f->visibility))
return FALSE;
}
else
{
if (! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos,
f->u.f.bitsize, f->visibility))
return FALSE;
}
}
}
 
if (type->u.kclass->baseclasses != NULL)
{
for (i = 0; type->u.kclass->baseclasses[i] != NULL; i++)
{
struct debug_baseclass_s *b;
 
b = type->u.kclass->baseclasses[i];
if (! debug_write_type (info, fns, fhandle, b->type,
(struct debug_name *) NULL))
return FALSE;
if (! (*fns->class_baseclass) (fhandle, b->bitpos, b->is_virtual,
b->visibility))
return FALSE;
}
}
 
if (type->u.kclass->methods != NULL)
{
for (i = 0; type->u.kclass->methods[i] != NULL; i++)
{
struct debug_method_s *m;
unsigned int j;
 
m = type->u.kclass->methods[i];
if (! (*fns->class_start_method) (fhandle, m->name))
return FALSE;
for (j = 0; m->variants[j] != NULL; j++)
{
struct debug_method_variant_s *v;
 
v = m->variants[j];
if (v->context != NULL)
{
if (! debug_write_type (info, fns, fhandle, v->context,
(struct debug_name *) NULL))
return FALSE;
}
if (! debug_write_type (info, fns, fhandle, v->type,
(struct debug_name *) NULL))
return FALSE;
if (v->voffset != VOFFSET_STATIC_METHOD)
{
if (! (*fns->class_method_variant) (fhandle, v->physname,
v->visibility,
v->constp,
v->volatilep,
v->voffset,
v->context != NULL))
return FALSE;
}
else
{
if (! (*fns->class_static_method_variant) (fhandle,
v->physname,
v->visibility,
v->constp,
v->volatilep))
return FALSE;
}
}
if (! (*fns->class_end_method) (fhandle))
return FALSE;
}
}
}
 
return (*fns->end_class_type) (fhandle);
}
 
/* Write out information for a function. */
 
static bfd_boolean
debug_write_function (struct debug_handle *info,
const struct debug_write_fns *fns, void *fhandle,
const char *name, enum debug_object_linkage linkage,
struct debug_function *function)
{
struct debug_parameter *p;
struct debug_block *b;
 
if (! debug_write_linenos (info, fns, fhandle, function->blocks->start))
return FALSE;
 
if (! debug_write_type (info, fns, fhandle, function->return_type,
(struct debug_name *) NULL))
return FALSE;
 
if (! (*fns->start_function) (fhandle, name,
linkage == DEBUG_LINKAGE_GLOBAL))
return FALSE;
 
for (p = function->parameters; p != NULL; p = p->next)
{
if (! debug_write_type (info, fns, fhandle, p->type,
(struct debug_name *) NULL)
|| ! (*fns->function_parameter) (fhandle, p->name, p->kind, p->val))
return FALSE;
}
 
for (b = function->blocks; b != NULL; b = b->next)
{
if (! debug_write_block (info, fns, fhandle, b))
return FALSE;
}
 
return (*fns->end_function) (fhandle);
}
 
/* Write out information for a block. */
 
static bfd_boolean
debug_write_block (struct debug_handle *info,
const struct debug_write_fns *fns, void *fhandle,
struct debug_block *block)
{
struct debug_name *n;
struct debug_block *b;
 
if (! debug_write_linenos (info, fns, fhandle, block->start))
return FALSE;
 
/* I can't see any point to writing out a block with no local
variables, so we don't bother, except for the top level block. */
if (block->locals != NULL || block->parent == NULL)
{
if (! (*fns->start_block) (fhandle, block->start))
return FALSE;
}
 
if (block->locals != NULL)
{
for (n = block->locals->list; n != NULL; n = n->next)
{
if (! debug_write_name (info, fns, fhandle, n))
return FALSE;
}
}
 
for (b = block->children; b != NULL; b = b->next)
{
if (! debug_write_block (info, fns, fhandle, b))
return FALSE;
}
 
if (! debug_write_linenos (info, fns, fhandle, block->end))
return FALSE;
 
if (block->locals != NULL || block->parent == NULL)
{
if (! (*fns->end_block) (fhandle, block->end))
return FALSE;
}
 
return TRUE;
}
 
/* Write out line number information up to ADDRESS. */
 
static bfd_boolean
debug_write_linenos (struct debug_handle *info,
const struct debug_write_fns *fns, void *fhandle,
bfd_vma address)
{
while (info->current_write_lineno != NULL)
{
struct debug_lineno *l;
 
l = info->current_write_lineno;
 
while (info->current_write_lineno_index < DEBUG_LINENO_COUNT)
{
if (l->linenos[info->current_write_lineno_index]
== (unsigned long) -1)
break;
 
if (l->addrs[info->current_write_lineno_index] >= address)
return TRUE;
 
if (! (*fns->lineno) (fhandle, l->file->filename,
l->linenos[info->current_write_lineno_index],
l->addrs[info->current_write_lineno_index]))
return FALSE;
 
++info->current_write_lineno_index;
}
 
info->current_write_lineno = l->next;
info->current_write_lineno_index = 0;
}
 
return TRUE;
}
 
/* Get the ID number for a class. If during the same call to
debug_write we find a struct with the same definition with the same
name, we use the same ID. This type of things happens because the
same struct will be defined by multiple compilation units. */
 
static bfd_boolean
debug_set_class_id (struct debug_handle *info, const char *tag,
struct debug_type_s *type)
{
struct debug_class_type *c;
struct debug_class_id *l;
 
assert (type->kind == DEBUG_KIND_STRUCT
|| type->kind == DEBUG_KIND_UNION
|| type->kind == DEBUG_KIND_CLASS
|| type->kind == DEBUG_KIND_UNION_CLASS);
 
c = type->u.kclass;
 
if (c->id > info->base_id)
return TRUE;
 
for (l = info->id_list; l != NULL; l = l->next)
{
if (l->type->kind != type->kind)
continue;
 
if (tag == NULL)
{
if (l->tag != NULL)
continue;
}
else
{
if (l->tag == NULL
|| l->tag[0] != tag[0]
|| strcmp (l->tag, tag) != 0)
continue;
}
 
if (debug_type_samep (info, l->type, type))
{
c->id = l->type->u.kclass->id;
return TRUE;
}
}
 
/* There are no identical types. Use a new ID, and add it to the
list. */
++info->class_id;
c->id = info->class_id;
 
l = (struct debug_class_id *) xmalloc (sizeof *l);
memset (l, 0, sizeof *l);
 
l->type = type;
l->tag = tag;
 
l->next = info->id_list;
info->id_list = l;
 
return TRUE;
}
 
/* See if two types are the same. At this point, we don't care about
tags and the like. */
 
static bfd_boolean
debug_type_samep (struct debug_handle *info, struct debug_type_s *t1,
struct debug_type_s *t2)
{
struct debug_type_compare_list *l;
struct debug_type_compare_list top;
bfd_boolean ret;
 
if (t1 == NULL)
return t2 == NULL;
if (t2 == NULL)
return FALSE;
 
while (t1->kind == DEBUG_KIND_INDIRECT)
{
t1 = *t1->u.kindirect->slot;
if (t1 == NULL)
return FALSE;
}
while (t2->kind == DEBUG_KIND_INDIRECT)
{
t2 = *t2->u.kindirect->slot;
if (t2 == NULL)
return FALSE;
}
 
if (t1 == t2)
return TRUE;
 
/* As a special case, permit a typedef to match a tag, since C++
debugging output will sometimes add a typedef where C debugging
output will not. */
if (t1->kind == DEBUG_KIND_NAMED
&& t2->kind == DEBUG_KIND_TAGGED)
return debug_type_samep (info, t1->u.knamed->type, t2);
else if (t1->kind == DEBUG_KIND_TAGGED
&& t2->kind == DEBUG_KIND_NAMED)
return debug_type_samep (info, t1, t2->u.knamed->type);
 
if (t1->kind != t2->kind
|| t1->size != t2->size)
return FALSE;
 
/* Get rid of the trivial cases first. */
switch (t1->kind)
{
default:
break;
case DEBUG_KIND_VOID:
case DEBUG_KIND_FLOAT:
case DEBUG_KIND_COMPLEX:
case DEBUG_KIND_BOOL:
return TRUE;
case DEBUG_KIND_INT:
return t1->u.kint == t2->u.kint;
}
 
/* We have to avoid an infinite recursion. We do this by keeping a
list of types which we are comparing. We just keep the list on
the stack. If we encounter a pair of types we are currently
comparing, we just assume that they are equal. */
for (l = info->compare_list; l != NULL; l = l->next)
{
if (l->t1 == t1 && l->t2 == t2)
return TRUE;
}
 
top.t1 = t1;
top.t2 = t2;
top.next = info->compare_list;
info->compare_list = &top;
 
switch (t1->kind)
{
default:
abort ();
ret = FALSE;
break;
 
case DEBUG_KIND_STRUCT:
case DEBUG_KIND_UNION:
case DEBUG_KIND_CLASS:
case DEBUG_KIND_UNION_CLASS:
if (t1->u.kclass == NULL)
ret = t2->u.kclass == NULL;
else if (t2->u.kclass == NULL)
ret = FALSE;
else if (t1->u.kclass->id > info->base_id
&& t1->u.kclass->id == t2->u.kclass->id)
ret = TRUE;
else
ret = debug_class_type_samep (info, t1, t2);
break;
 
case DEBUG_KIND_ENUM:
if (t1->u.kenum == NULL)
ret = t2->u.kenum == NULL;
else if (t2->u.kenum == NULL)
ret = FALSE;
else
{
const char **pn1, **pn2;
bfd_signed_vma *pv1, *pv2;
 
pn1 = t1->u.kenum->names;
pn2 = t2->u.kenum->names;
pv1 = t1->u.kenum->values;
pv2 = t2->u.kenum->values;
while (*pn1 != NULL && *pn2 != NULL)
{
if (**pn1 != **pn2
|| *pv1 != *pv2
|| strcmp (*pn1, *pn2) != 0)
break;
++pn1;
++pn2;
++pv1;
++pv2;
}
ret = *pn1 == NULL && *pn2 == NULL;
}
break;
 
case DEBUG_KIND_POINTER:
ret = debug_type_samep (info, t1->u.kpointer, t2->u.kpointer);
break;
 
case DEBUG_KIND_FUNCTION:
if (t1->u.kfunction->varargs != t2->u.kfunction->varargs
|| ! debug_type_samep (info, t1->u.kfunction->return_type,
t2->u.kfunction->return_type)
|| ((t1->u.kfunction->arg_types == NULL)
!= (t2->u.kfunction->arg_types == NULL)))
ret = FALSE;
else if (t1->u.kfunction->arg_types == NULL)
ret = TRUE;
else
{
struct debug_type_s **a1, **a2;
 
a1 = t1->u.kfunction->arg_types;
a2 = t2->u.kfunction->arg_types;
while (*a1 != NULL && *a2 != NULL)
{
if (! debug_type_samep (info, *a1, *a2))
break;
++a1;
++a2;
}
ret = *a1 == NULL && *a2 == NULL;
}
break;
 
case DEBUG_KIND_REFERENCE:
ret = debug_type_samep (info, t1->u.kreference, t2->u.kreference);
break;
 
case DEBUG_KIND_RANGE:
ret = (t1->u.krange->lower == t2->u.krange->lower
&& t1->u.krange->upper == t2->u.krange->upper
&& debug_type_samep (info, t1->u.krange->type,
t2->u.krange->type));
 
case DEBUG_KIND_ARRAY:
ret = (t1->u.karray->lower == t2->u.karray->lower
&& t1->u.karray->upper == t2->u.karray->upper
&& t1->u.karray->stringp == t2->u.karray->stringp
&& debug_type_samep (info, t1->u.karray->element_type,
t2->u.karray->element_type));
break;
 
case DEBUG_KIND_SET:
ret = (t1->u.kset->bitstringp == t2->u.kset->bitstringp
&& debug_type_samep (info, t1->u.kset->type, t2->u.kset->type));
break;
 
case DEBUG_KIND_OFFSET:
ret = (debug_type_samep (info, t1->u.koffset->base_type,
t2->u.koffset->base_type)
&& debug_type_samep (info, t1->u.koffset->target_type,
t2->u.koffset->target_type));
break;
 
case DEBUG_KIND_METHOD:
if (t1->u.kmethod->varargs != t2->u.kmethod->varargs
|| ! debug_type_samep (info, t1->u.kmethod->return_type,
t2->u.kmethod->return_type)
|| ! debug_type_samep (info, t1->u.kmethod->domain_type,
t2->u.kmethod->domain_type)
|| ((t1->u.kmethod->arg_types == NULL)
!= (t2->u.kmethod->arg_types == NULL)))
ret = FALSE;
else if (t1->u.kmethod->arg_types == NULL)
ret = TRUE;
else
{
struct debug_type_s **a1, **a2;
 
a1 = t1->u.kmethod->arg_types;
a2 = t2->u.kmethod->arg_types;
while (*a1 != NULL && *a2 != NULL)
{
if (! debug_type_samep (info, *a1, *a2))
break;
++a1;
++a2;
}
ret = *a1 == NULL && *a2 == NULL;
}
break;
 
case DEBUG_KIND_CONST:
ret = debug_type_samep (info, t1->u.kconst, t2->u.kconst);
break;
 
case DEBUG_KIND_VOLATILE:
ret = debug_type_samep (info, t1->u.kvolatile, t2->u.kvolatile);
break;
 
case DEBUG_KIND_NAMED:
case DEBUG_KIND_TAGGED:
ret = (strcmp (t1->u.knamed->name->name, t2->u.knamed->name->name) == 0
&& debug_type_samep (info, t1->u.knamed->type,
t2->u.knamed->type));
break;
}
 
info->compare_list = top.next;
 
return ret;
}
 
/* See if two classes are the same. This is a subroutine of
debug_type_samep. */
 
static bfd_boolean
debug_class_type_samep (struct debug_handle *info, struct debug_type_s *t1,
struct debug_type_s *t2)
{
struct debug_class_type *c1, *c2;
 
c1 = t1->u.kclass;
c2 = t2->u.kclass;
 
if ((c1->fields == NULL) != (c2->fields == NULL)
|| (c1->baseclasses == NULL) != (c2->baseclasses == NULL)
|| (c1->methods == NULL) != (c2->methods == NULL)
|| (c1->vptrbase == NULL) != (c2->vptrbase == NULL))
return FALSE;
 
if (c1->fields != NULL)
{
struct debug_field_s **pf1, **pf2;
 
for (pf1 = c1->fields, pf2 = c2->fields;
*pf1 != NULL && *pf2 != NULL;
pf1++, pf2++)
{
struct debug_field_s *f1, *f2;
 
f1 = *pf1;
f2 = *pf2;
if (f1->name[0] != f2->name[0]
|| f1->visibility != f2->visibility
|| f1->static_member != f2->static_member)
return FALSE;
if (f1->static_member)
{
if (strcmp (f1->u.s.physname, f2->u.s.physname) != 0)
return FALSE;
}
else
{
if (f1->u.f.bitpos != f2->u.f.bitpos
|| f1->u.f.bitsize != f2->u.f.bitsize)
return FALSE;
}
/* We do the checks which require function calls last. We
don't require that the types of fields have the same
names, since that sometimes fails in the presence of
typedefs and we really don't care. */
if (strcmp (f1->name, f2->name) != 0
|| ! debug_type_samep (info,
debug_get_real_type ((void *) info,
f1->type, NULL),
debug_get_real_type ((void *) info,
f2->type, NULL)))
return FALSE;
}
if (*pf1 != NULL || *pf2 != NULL)
return FALSE;
}
 
if (c1->vptrbase != NULL)
{
if (! debug_type_samep (info, c1->vptrbase, c2->vptrbase))
return FALSE;
}
 
if (c1->baseclasses != NULL)
{
struct debug_baseclass_s **pb1, **pb2;
 
for (pb1 = c1->baseclasses, pb2 = c2->baseclasses;
*pb1 != NULL && *pb2 != NULL;
++pb1, ++pb2)
{
struct debug_baseclass_s *b1, *b2;
 
b1 = *pb1;
b2 = *pb2;
if (b1->bitpos != b2->bitpos
|| b1->is_virtual != b2->is_virtual
|| b1->visibility != b2->visibility
|| ! debug_type_samep (info, b1->type, b2->type))
return FALSE;
}
if (*pb1 != NULL || *pb2 != NULL)
return FALSE;
}
 
if (c1->methods != NULL)
{
struct debug_method_s **pm1, **pm2;
 
for (pm1 = c1->methods, pm2 = c2->methods;
*pm1 != NULL && *pm2 != NULL;
++pm1, ++pm2)
{
struct debug_method_s *m1, *m2;
 
m1 = *pm1;
m2 = *pm2;
if (m1->name[0] != m2->name[0]
|| strcmp (m1->name, m2->name) != 0
|| (m1->variants == NULL) != (m2->variants == NULL))
return FALSE;
if (m1->variants == NULL)
{
struct debug_method_variant_s **pv1, **pv2;
 
for (pv1 = m1->variants, pv2 = m2->variants;
*pv1 != NULL && *pv2 != NULL;
++pv1, ++pv2)
{
struct debug_method_variant_s *v1, *v2;
 
v1 = *pv1;
v2 = *pv2;
if (v1->physname[0] != v2->physname[0]
|| v1->visibility != v2->visibility
|| v1->constp != v2->constp
|| v1->volatilep != v2->volatilep
|| v1->voffset != v2->voffset
|| (v1->context == NULL) != (v2->context == NULL)
|| strcmp (v1->physname, v2->physname) != 0
|| ! debug_type_samep (info, v1->type, v2->type))
return FALSE;
if (v1->context != NULL)
{
if (! debug_type_samep (info, v1->context,
v2->context))
return FALSE;
}
}
if (*pv1 != NULL || *pv2 != NULL)
return FALSE;
}
}
if (*pm1 != NULL || *pm2 != NULL)
return FALSE;
}
 
return TRUE;
}
/contrib/toolchain/binutils/binutils/debug.h
0,0 → 1,793
/* debug.h -- Describe generic debugging information.
Copyright 1995, 1996, 2002, 2003, 2005, 2007, 2009
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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
#ifndef DEBUG_H
#define DEBUG_H
 
/* This header file describes a generic debugging information format.
We may eventually have readers which convert different formats into
this generic format, and writers which write it out. The initial
impetus for this was writing a converter from stabs to HP IEEE-695
debugging format. */
 
/* Different kinds of types. */
 
enum debug_type_kind
{
/* Not used. */
DEBUG_KIND_ILLEGAL,
/* Indirect via a pointer. */
DEBUG_KIND_INDIRECT,
/* Void. */
DEBUG_KIND_VOID,
/* Integer. */
DEBUG_KIND_INT,
/* Floating point. */
DEBUG_KIND_FLOAT,
/* Complex. */
DEBUG_KIND_COMPLEX,
/* Boolean. */
DEBUG_KIND_BOOL,
/* Struct. */
DEBUG_KIND_STRUCT,
/* Union. */
DEBUG_KIND_UNION,
/* Class. */
DEBUG_KIND_CLASS,
/* Union class (can this really happen?). */
DEBUG_KIND_UNION_CLASS,
/* Enumeration type. */
DEBUG_KIND_ENUM,
/* Pointer. */
DEBUG_KIND_POINTER,
/* Function. */
DEBUG_KIND_FUNCTION,
/* Reference. */
DEBUG_KIND_REFERENCE,
/* Range. */
DEBUG_KIND_RANGE,
/* Array. */
DEBUG_KIND_ARRAY,
/* Set. */
DEBUG_KIND_SET,
/* Based pointer. */
DEBUG_KIND_OFFSET,
/* Method. */
DEBUG_KIND_METHOD,
/* Const qualified type. */
DEBUG_KIND_CONST,
/* Volatile qualified type. */
DEBUG_KIND_VOLATILE,
/* Named type. */
DEBUG_KIND_NAMED,
/* Tagged type. */
DEBUG_KIND_TAGGED
};
 
/* Different kinds of variables. */
 
enum debug_var_kind
{
/* Not used. */
DEBUG_VAR_ILLEGAL,
/* A global variable. */
DEBUG_GLOBAL,
/* A static variable. */
DEBUG_STATIC,
/* A local static variable. */
DEBUG_LOCAL_STATIC,
/* A local variable. */
DEBUG_LOCAL,
/* A register variable. */
DEBUG_REGISTER
};
 
/* Different kinds of function parameters. */
 
enum debug_parm_kind
{
/* Not used. */
DEBUG_PARM_ILLEGAL,
/* A stack based parameter. */
DEBUG_PARM_STACK,
/* A register parameter. */
DEBUG_PARM_REG,
/* A stack based reference parameter. */
DEBUG_PARM_REFERENCE,
/* A register reference parameter. */
DEBUG_PARM_REF_REG
};
 
/* Different kinds of visibility. */
 
enum debug_visibility
{
/* A public field (e.g., a field in a C struct). */
DEBUG_VISIBILITY_PUBLIC,
/* A protected field. */
DEBUG_VISIBILITY_PROTECTED,
/* A private field. */
DEBUG_VISIBILITY_PRIVATE,
/* A field which should be ignored. */
DEBUG_VISIBILITY_IGNORE
};
 
/* A type. */
 
typedef struct debug_type_s *debug_type;
 
#define DEBUG_TYPE_NULL ((debug_type) NULL)
 
/* A field in a struct or union. */
 
typedef struct debug_field_s *debug_field;
 
#define DEBUG_FIELD_NULL ((debug_field) NULL)
 
/* A base class for an object. */
 
typedef struct debug_baseclass_s *debug_baseclass;
 
#define DEBUG_BASECLASS_NULL ((debug_baseclass) NULL)
 
/* A method of an object. */
 
typedef struct debug_method_s *debug_method;
 
#define DEBUG_METHOD_NULL ((debug_method) NULL)
 
/* The arguments to a method function of an object. These indicate
which method to run. */
 
typedef struct debug_method_variant_s *debug_method_variant;
 
#define DEBUG_METHOD_VARIANT_NULL ((debug_method_variant) NULL)
 
/* This structure is passed to debug_write. It holds function
pointers that debug_write will call based on the accumulated
debugging information. */
 
struct debug_write_fns
{
/* This is called at the start of each new compilation unit with the
name of the main file in the new unit. */
bfd_boolean (*start_compilation_unit) (void *, const char *);
 
/* This is called at the start of each source file within a
compilation unit, before outputting any global information for
that file. The argument is the name of the file. */
bfd_boolean (*start_source) (void *, const char *);
 
/* Each writer must keep a stack of types. */
 
/* Push an empty type onto the type stack. This type can appear if
there is a reference to a type which is never defined. */
bfd_boolean (*empty_type) (void *);
 
/* Push a void type onto the type stack. */
bfd_boolean (*void_type) (void *);
 
/* Push an integer type onto the type stack, given the size and
whether it is unsigned. */
bfd_boolean (*int_type) (void *, unsigned int, bfd_boolean);
 
/* Push a floating type onto the type stack, given the size. */
bfd_boolean (*float_type) (void *, unsigned int);
 
/* Push a complex type onto the type stack, given the size. */
bfd_boolean (*complex_type) (void *, unsigned int);
 
/* Push a bfd_boolean type onto the type stack, given the size. */
bfd_boolean (*bool_type) (void *, unsigned int);
 
/* Push an enum type onto the type stack, given the tag, a NULL
terminated array of names and the associated values. If there is
no tag, the tag argument will be NULL. If this is an undefined
enum, the names and values arguments will be NULL. */
bfd_boolean (*enum_type)
(void *, const char *, const char **, bfd_signed_vma *);
 
/* Pop the top type on the type stack, and push a pointer to that
type onto the type stack. */
bfd_boolean (*pointer_type) (void *);
 
/* Push a function type onto the type stack. The second argument
indicates the number of argument types that have been pushed onto
the stack. If the number of argument types is passed as -1, then
the argument types of the function are unknown, and no types have
been pushed onto the stack. The third argument is TRUE if the
function takes a variable number of arguments. The return type
of the function is pushed onto the type stack below the argument
types, if any. */
bfd_boolean (*function_type) (void *, int, bfd_boolean);
 
/* Pop the top type on the type stack, and push a reference to that
type onto the type stack. */
bfd_boolean (*reference_type) (void *);
 
/* Pop the top type on the type stack, and push a range of that type
with the given lower and upper bounds onto the type stack. */
bfd_boolean (*range_type) (void *, bfd_signed_vma, bfd_signed_vma);
 
/* Push an array type onto the type stack. The top type on the type
stack is the range, and the next type on the type stack is the
element type. These should be popped before the array type is
pushed. The arguments are the lower bound, the upper bound, and
whether the array is a string. */
bfd_boolean (*array_type)
(void *, bfd_signed_vma, bfd_signed_vma, bfd_boolean);
 
/* Pop the top type on the type stack, and push a set of that type
onto the type stack. The argument indicates whether this set is
a bitstring. */
bfd_boolean (*set_type) (void *, bfd_boolean);
 
/* Push an offset type onto the type stack. The top type on the
type stack is the target type, and the next type on the type
stack is the base type. These should be popped before the offset
type is pushed. */
bfd_boolean (*offset_type) (void *);
 
/* Push a method type onto the type stack. If the second argument
is TRUE, the top type on the stack is the class to which the
method belongs; otherwise, the class must be determined by the
class to which the method is attached. The third argument is the
number of argument types; these are pushed onto the type stack in
reverse order (the first type popped is the last argument to the
method). A value of -1 for the third argument means that no
argument information is available. The fourth argument is TRUE
if the function takes a variable number of arguments. The next
type on the type stack below the domain and the argument types is
the return type of the method. All these types must be popped,
and then the method type must be pushed. */
bfd_boolean (*method_type) (void *, bfd_boolean, int, bfd_boolean);
 
/* Pop the top type off the type stack, and push a const qualified
version of that type onto the type stack. */
bfd_boolean (*const_type) (void *);
 
/* Pop the top type off the type stack, and push a volatile
qualified version of that type onto the type stack. */
bfd_boolean (*volatile_type) (void *);
 
/* Start building a struct. This is followed by calls to the
struct_field function, and finished by a call to the
end_struct_type function. The second argument is the tag; this
will be NULL if there isn't one. If the second argument is NULL,
the third argument is a constant identifying this struct for use
with tag_type. The fourth argument is TRUE for a struct, FALSE
for a union. The fifth argument is the size. If this is an
undefined struct or union, the size will be 0 and struct_field
will not be called before end_struct_type is called. */
bfd_boolean (*start_struct_type)
(void *, const char *, unsigned int, bfd_boolean, unsigned int);
 
/* Add a field to the struct type currently being built. The type
of the field should be popped off the type stack. The arguments
are the name, the bit position, the bit size (may be zero if the
field is not packed), and the visibility. */
bfd_boolean (*struct_field)
(void *, const char *, bfd_vma, bfd_vma, enum debug_visibility);
 
/* Finish building a struct, and push it onto the type stack. */
bfd_boolean (*end_struct_type) (void *);
 
/* Start building a class. This is followed by calls to several
functions: struct_field, class_static_member, class_baseclass,
class_start_method, class_method_variant,
class_static_method_variant, and class_end_method. The class is
finished by a call to end_class_type. The first five arguments
are the same as for start_struct_type. The sixth argument is
TRUE if there is a virtual function table; if there is, the
seventh argument is TRUE if the virtual function table can be
found in the type itself, and is FALSE if the type of the object
holding the virtual function table should be popped from the type
stack. */
bfd_boolean (*start_class_type)
(void *, const char *, unsigned int, bfd_boolean, unsigned int,
bfd_boolean, bfd_boolean);
 
/* Add a static member to the class currently being built. The
arguments are the field name, the physical name, and the
visibility. The type must be popped off the type stack. */
bfd_boolean (*class_static_member)
(void *, const char *, const char *, enum debug_visibility);
 
/* Add a baseclass to the class currently being built. The type of
the baseclass must be popped off the type stack. The arguments
are the bit position, whether the class is virtual, and the
visibility. */
bfd_boolean (*class_baseclass)
(void *, bfd_vma, bfd_boolean, enum debug_visibility);
 
/* Start adding a method to the class currently being built. This
is followed by calls to class_method_variant and
class_static_method_variant to describe different variants of the
method which take different arguments. The method is finished
with a call to class_end_method. The argument is the method
name. */
bfd_boolean (*class_start_method) (void *, const char *);
 
/* Describe a variant to the class method currently being built.
The type of the variant must be popped off the type stack. The
second argument is the physical name of the function. The
following arguments are the visibility, whether the variant is
const, whether the variant is volatile, the offset in the virtual
function table, and whether the context is on the type stack
(below the variant type). */
bfd_boolean (*class_method_variant)
(void *, const char *, enum debug_visibility, bfd_boolean,
bfd_boolean, bfd_vma, bfd_boolean);
 
/* Describe a static variant to the class method currently being
built. The arguments are the same as for class_method_variant,
except that the last two arguments are omitted. The type of the
variant must be popped off the type stack. */
bfd_boolean (*class_static_method_variant)
(void *, const char *, enum debug_visibility, bfd_boolean,
bfd_boolean);
 
/* Finish describing a class method. */
bfd_boolean (*class_end_method) (void *);
 
/* Finish describing a class, and push it onto the type stack. */
bfd_boolean (*end_class_type) (void *);
 
/* Push a type on the stack which was given a name by an earlier
call to typdef. */
bfd_boolean (*typedef_type) (void *, const char *);
 
/* Push a tagged type on the stack which was defined earlier. If
the second argument is not NULL, the type was defined by a call
to tag. If the second argument is NULL, the type was defined by
a call to start_struct_type or start_class_type with a tag of
NULL and the number of the third argument. Either way, the
fourth argument is the tag kind. Note that this may be called
for a struct (class) being defined, in between the call to
start_struct_type (start_class_type) and the call to
end_struct_type (end_class_type). */
bfd_boolean (*tag_type)
(void *, const char *, unsigned int, enum debug_type_kind);
 
/* Pop the type stack, and typedef it to the given name. */
bfd_boolean (*typdef) (void *, const char *);
 
/* Pop the type stack, and declare it as a tagged struct or union or
enum or whatever. The tag passed down here is redundant, since
was also passed when enum_type, start_struct_type, or
start_class_type was called. */
bfd_boolean (*tag) (void *, const char *);
 
/* This is called to record a named integer constant. */
bfd_boolean (*int_constant) (void *, const char *, bfd_vma);
 
/* This is called to record a named floating point constant. */
bfd_boolean (*float_constant) (void *, const char *, double);
 
/* This is called to record a typed integer constant. The type is
popped off the type stack. */
bfd_boolean (*typed_constant) (void *, const char *, bfd_vma);
 
/* This is called to record a variable. The type is popped off the
type stack. */
bfd_boolean (*variable)
(void *, const char *, enum debug_var_kind, bfd_vma);
 
/* Start writing out a function. The return type must be popped off
the stack. The bfd_boolean is TRUE if the function is global. This
is followed by calls to function_parameter, followed by block
information. */
bfd_boolean (*start_function) (void *, const char *, bfd_boolean);
 
/* Record a function parameter for the current function. The type
must be popped off the stack. */
bfd_boolean (*function_parameter)
(void *, const char *, enum debug_parm_kind, bfd_vma);
 
/* Start writing out a block. There is at least one top level block
per function. Blocks may be nested. The argument is the
starting address of the block. */
bfd_boolean (*start_block) (void *, bfd_vma);
 
/* Finish writing out a block. The argument is the ending address
of the block. */
bfd_boolean (*end_block) (void *, bfd_vma);
 
/* Finish writing out a function. */
bfd_boolean (*end_function) (void *);
 
/* Record line number information for the current compilation unit. */
bfd_boolean (*lineno) (void *, const char *, unsigned long, bfd_vma);
};
 
/* Exported functions. */
 
/* The first argument to most of these functions is a handle. This
handle is returned by the debug_init function. The purpose of the
handle is to permit the debugging routines to not use static
variables, and hence to be reentrant. This would be useful for a
program which wanted to handle two executables simultaneously. */
 
/* Return a debugging handle. */
 
extern void *debug_init (void);
 
/* Set the source filename. This implicitly starts a new compilation
unit. */
 
extern bfd_boolean debug_set_filename (void *, const char *);
 
/* Change source files to the given file name. This is used for
include files in a single compilation unit. */
 
extern bfd_boolean debug_start_source (void *, const char *);
 
/* Record a function definition. This implicitly starts a function
block. The debug_type argument is the type of the return value.
The bfd_boolean indicates whether the function is globally visible.
The bfd_vma is the address of the start of the function. Currently
the parameter types are specified by calls to
debug_record_parameter. */
 
extern bfd_boolean debug_record_function
(void *, const char *, debug_type, bfd_boolean, bfd_vma);
 
/* Record a parameter for the current function. */
 
extern bfd_boolean debug_record_parameter
(void *, const char *, debug_type, enum debug_parm_kind, bfd_vma);
 
/* End a function definition. The argument is the address where the
function ends. */
 
extern bfd_boolean debug_end_function (void *, bfd_vma);
 
/* Start a block in a function. All local information will be
recorded in this block, until the matching call to debug_end_block.
debug_start_block and debug_end_block may be nested. The argument
is the address at which this block starts. */
 
extern bfd_boolean debug_start_block (void *, bfd_vma);
 
/* Finish a block in a function. This matches the call to
debug_start_block. The argument is the address at which this block
ends. */
 
extern bfd_boolean debug_end_block (void *, bfd_vma);
 
/* Associate a line number in the current source file with a given
address. */
 
extern bfd_boolean debug_record_line (void *, unsigned long, bfd_vma);
 
/* Start a named common block. This is a block of variables that may
move in memory. */
 
extern bfd_boolean debug_start_common_block (void *, const char *);
 
/* End a named common block. */
 
extern bfd_boolean debug_end_common_block (void *, const char *);
 
/* Record a named integer constant. */
 
extern bfd_boolean debug_record_int_const (void *, const char *, bfd_vma);
 
/* Record a named floating point constant. */
 
extern bfd_boolean debug_record_float_const (void *, const char *, double);
 
/* Record a typed constant with an integral value. */
 
extern bfd_boolean debug_record_typed_const
(void *, const char *, debug_type, bfd_vma);
 
/* Record a label. */
 
extern bfd_boolean debug_record_label
(void *, const char *, debug_type, bfd_vma);
 
/* Record a variable. */
 
extern bfd_boolean debug_record_variable
(void *, const char *, debug_type, enum debug_var_kind, bfd_vma);
 
/* Make an indirect type. The first argument is a pointer to the
location where the real type will be placed. The second argument
is the type tag, if there is one; this may be NULL; the only
purpose of this argument is so that debug_get_type_name can return
something useful. This function may be used when a type is
referenced before it is defined. */
 
extern debug_type debug_make_indirect_type
(void *, debug_type *, const char *);
 
/* Make a void type. */
 
extern debug_type debug_make_void_type (void *);
 
/* Make an integer type of a given size. The bfd_boolean argument is TRUE
if the integer is unsigned. */
 
extern debug_type debug_make_int_type (void *, unsigned int, bfd_boolean);
 
/* Make a floating point type of a given size. FIXME: On some
platforms, like an Alpha, you probably need to be able to specify
the format. */
 
extern debug_type debug_make_float_type (void *, unsigned int);
 
/* Make a boolean type of a given size. */
 
extern debug_type debug_make_bool_type (void *, unsigned int);
 
/* Make a complex type of a given size. */
 
extern debug_type debug_make_complex_type (void *, unsigned int);
 
/* Make a structure type. The second argument is TRUE for a struct,
FALSE for a union. The third argument is the size of the struct.
The fourth argument is a NULL terminated array of fields. */
 
extern debug_type debug_make_struct_type
(void *, bfd_boolean, bfd_vma, debug_field *);
 
/* Make an object type. The first three arguments after the handle
are the same as for debug_make_struct_type. The next arguments are
a NULL terminated array of base classes, a NULL terminated array of
methods, the type of the object holding the virtual function table
if it is not this object, and a bfd_boolean which is TRUE if this
object has its own virtual function table. */
 
extern debug_type debug_make_object_type
(void *, bfd_boolean, bfd_vma, debug_field *, debug_baseclass *,
debug_method *, debug_type, bfd_boolean);
 
/* Make an enumeration type. The arguments are a null terminated
array of strings, and an array of corresponding values. */
 
extern debug_type debug_make_enum_type
(void *, const char **, bfd_signed_vma *);
 
/* Make a pointer to a given type. */
 
extern debug_type debug_make_pointer_type (void *, debug_type);
 
/* Make a function type. The second argument is the return type. The
third argument is a NULL terminated array of argument types. The
fourth argument is TRUE if the function takes a variable number of
arguments. If the third argument is NULL, then the argument types
are unknown. */
 
extern debug_type debug_make_function_type
(void *, debug_type, debug_type *, bfd_boolean);
 
/* Make a reference to a given type. */
 
extern debug_type debug_make_reference_type (void *, debug_type);
 
/* Make a range of a given type from a lower to an upper bound. */
 
extern debug_type debug_make_range_type
(void *, debug_type, bfd_signed_vma, bfd_signed_vma);
 
/* Make an array type. The second argument is the type of an element
of the array. The third argument is the type of a range of the
array. The fourth and fifth argument are the lower and upper
bounds, respectively (if the bounds are not known, lower should be
0 and upper should be -1). The sixth argument is TRUE if this
array is actually a string, as in C. */
 
extern debug_type debug_make_array_type
(void *, debug_type, debug_type, bfd_signed_vma, bfd_signed_vma,
bfd_boolean);
 
/* Make a set of a given type. For example, a Pascal set type. The
bfd_boolean argument is TRUE if this set is actually a bitstring, as in
CHILL. */
 
extern debug_type debug_make_set_type (void *, debug_type, bfd_boolean);
 
/* Make a type for a pointer which is relative to an object. The
second argument is the type of the object to which the pointer is
relative. The third argument is the type that the pointer points
to. */
 
extern debug_type debug_make_offset_type (void *, debug_type, debug_type);
 
/* Make a type for a method function. The second argument is the
return type. The third argument is the domain. The fourth
argument is a NULL terminated array of argument types. The fifth
argument is TRUE if the function takes a variable number of
arguments, in which case the array of argument types indicates the
types of the first arguments. The domain and the argument array
may be NULL, in which case this is a stub method and that
information is not available. Stabs debugging uses this, and gets
the argument types from the mangled name. */
 
extern debug_type debug_make_method_type
(void *, debug_type, debug_type, debug_type *, bfd_boolean);
 
/* Make a const qualified version of a given type. */
 
extern debug_type debug_make_const_type (void *, debug_type);
 
/* Make a volatile qualified version of a given type. */
 
extern debug_type debug_make_volatile_type (void *, debug_type);
 
/* Make an undefined tagged type. For example, a struct which has
been mentioned, but not defined. */
 
extern debug_type debug_make_undefined_tagged_type
(void *, const char *, enum debug_type_kind);
 
/* Make a base class for an object. The second argument is the base
class type. The third argument is the bit position of this base
class in the object. The fourth argument is whether this is a
virtual class. The fifth argument is the visibility of the base
class. */
 
extern debug_baseclass debug_make_baseclass
(void *, debug_type, bfd_vma, bfd_boolean, enum debug_visibility);
 
/* Make a field for a struct. The second argument is the name. The
third argument is the type of the field. The fourth argument is
the bit position of the field. The fifth argument is the size of
the field (it may be zero). The sixth argument is the visibility
of the field. */
 
extern debug_field debug_make_field
(void *, const char *, debug_type, bfd_vma, bfd_vma, enum debug_visibility);
 
/* Make a static member of an object. The second argument is the
name. The third argument is the type of the member. The fourth
argument is the physical name of the member (i.e., the name as a
global variable). The fifth argument is the visibility of the
member. */
 
extern debug_field debug_make_static_member
(void *, const char *, debug_type, const char *, enum debug_visibility);
 
/* Make a method. The second argument is the name, and the third
argument is a NULL terminated array of method variants. Each
method variant is a method with this name but with different
argument types. */
 
extern debug_method debug_make_method
(void *, const char *, debug_method_variant *);
 
/* Make a method variant. The second argument is the physical name of
the function. The third argument is the type of the function,
probably constructed by debug_make_method_type. The fourth
argument is the visibility. The fifth argument is whether this is
a const function. The sixth argument is whether this is a volatile
function. The seventh argument is the index in the virtual
function table, if any. The eighth argument is the virtual
function context. */
 
extern debug_method_variant debug_make_method_variant
(void *, const char *, debug_type, enum debug_visibility, bfd_boolean,
bfd_boolean, bfd_vma, debug_type);
 
/* Make a static method argument. The arguments are the same as for
debug_make_method_variant, except that the last two are omitted
since a static method can not also be virtual. */
 
extern debug_method_variant debug_make_static_method_variant
(void *, const char *, debug_type, enum debug_visibility, bfd_boolean,
bfd_boolean);
 
/* Name a type. This returns a new type with an attached name. */
 
extern debug_type debug_name_type (void *, const char *, debug_type);
 
/* Give a tag to a type, such as a struct or union. This returns a
new type with an attached tag. */
 
extern debug_type debug_tag_type (void *, const char *, debug_type);
 
/* Record the size of a given type. */
 
extern bfd_boolean debug_record_type_size (void *, debug_type, unsigned int);
 
/* Find a named type. */
 
extern debug_type debug_find_named_type (void *, const char *);
 
/* Find a tagged type. */
 
extern debug_type debug_find_tagged_type
(void *, const char *, enum debug_type_kind);
 
/* Get the kind of a type. */
 
extern enum debug_type_kind debug_get_type_kind (void *, debug_type);
 
/* Get the name of a type. */
 
extern const char *debug_get_type_name (void *, debug_type);
 
/* Get the size of a type. */
 
extern bfd_vma debug_get_type_size (void *, debug_type);
 
/* Get the return type of a function or method type. */
 
extern debug_type debug_get_return_type (void *, debug_type);
 
/* Get the NULL terminated array of parameter types for a function or
method type (actually, parameter types are not currently stored for
function types). This may be used to determine whether a method
type is a stub method or not. The last argument points to a
bfd_boolean which is set to TRUE if the function takes a variable
number of arguments. */
 
extern const debug_type *debug_get_parameter_types
(void *, debug_type, bfd_boolean *);
 
/* Get the target type of a pointer or reference or const or volatile
type. */
 
extern debug_type debug_get_target_type (void *, debug_type);
 
/* Get the NULL terminated array of fields for a struct, union, or
class. */
 
extern const debug_field *debug_get_fields (void *, debug_type);
 
/* Get the type of a field. */
 
extern debug_type debug_get_field_type (void *, debug_field);
 
/* Get the name of a field. */
 
extern const char *debug_get_field_name (void *, debug_field);
 
/* Get the bit position of a field within the containing structure.
If the field is a static member, this will return (bfd_vma) -1. */
 
extern bfd_vma debug_get_field_bitpos (void *, debug_field);
 
/* Get the bit size of a field. If the field is a static member, this
will return (bfd_vma) -1. */
 
extern bfd_vma debug_get_field_bitsize (void *, debug_field);
 
/* Get the visibility of a field. */
 
extern enum debug_visibility debug_get_field_visibility (void *, debug_field);
 
/* Get the physical name of a field, if it is a static member. If the
field is not a static member, this will return NULL. */
 
extern const char *debug_get_field_physname (void *, debug_field);
 
/* Write out the recorded debugging information. This takes a set of
function pointers which are called to do the actual writing. The
first void * is the debugging handle. The second void * is a handle
which is passed to the functions. */
 
extern bfd_boolean debug_write
(void *, const struct debug_write_fns *, void *);
 
#endif /* DEBUG_H */
/contrib/toolchain/binutils/binutils/filemode.c
0,0 → 1,249
/* filemode.c -- make a string describing file modes
Copyright 1985, 1990, 1991, 1994, 1995, 1997, 1999, 2002, 2003, 2005,
2007 Free Software Foundation, Inc.
 
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 3, 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "sysdep.h"
#include "bfd.h"
#include "bucomm.h"
 
static char ftypelet (unsigned long);
static void setst (unsigned long, char *);
 
/* filemodestring - fill in string STR with an ls-style ASCII
representation of the st_mode field of file stats block STATP.
10 characters are stored in STR; no terminating null is added.
The characters stored in STR are:
 
0 File type. 'd' for directory, 'c' for character
special, 'b' for block special, 'm' for multiplex,
'l' for symbolic link, 's' for socket, 'p' for fifo,
'-' for any other file type
 
1 'r' if the owner may read, '-' otherwise.
 
2 'w' if the owner may write, '-' otherwise.
 
3 'x' if the owner may execute, 's' if the file is
set-user-id, '-' otherwise.
'S' if the file is set-user-id, but the execute
bit isn't set.
 
4 'r' if group members may read, '-' otherwise.
 
5 'w' if group members may write, '-' otherwise.
 
6 'x' if group members may execute, 's' if the file is
set-group-id, '-' otherwise.
'S' if it is set-group-id but not executable.
 
7 'r' if any user may read, '-' otherwise.
 
8 'w' if any user may write, '-' otherwise.
 
9 'x' if any user may execute, 't' if the file is "sticky"
(will be retained in swap space after execution), '-'
otherwise.
'T' if the file is sticky but not executable. */
 
/* Get definitions for the file permission bits. */
 
#ifndef S_IRWXU
#define S_IRWXU 0700
#endif
#ifndef S_IRUSR
#define S_IRUSR 0400
#endif
#ifndef S_IWUSR
#define S_IWUSR 0200
#endif
#ifndef S_IXUSR
#define S_IXUSR 0100
#endif
 
#ifndef S_IRWXG
#define S_IRWXG 0070
#endif
#ifndef S_IRGRP
#define S_IRGRP 0040
#endif
#ifndef S_IWGRP
#define S_IWGRP 0020
#endif
#ifndef S_IXGRP
#define S_IXGRP 0010
#endif
 
#ifndef S_IRWXO
#define S_IRWXO 0007
#endif
#ifndef S_IROTH
#define S_IROTH 0004
#endif
#ifndef S_IWOTH
#define S_IWOTH 0002
#endif
#ifndef S_IXOTH
#define S_IXOTH 0001
#endif
 
/* Like filemodestring, but only the relevant part of the `struct stat'
is given as an argument. */
 
void
mode_string (unsigned long mode, char *str)
{
str[0] = ftypelet ((unsigned long) mode);
str[1] = (mode & S_IRUSR) != 0 ? 'r' : '-';
str[2] = (mode & S_IWUSR) != 0 ? 'w' : '-';
str[3] = (mode & S_IXUSR) != 0 ? 'x' : '-';
str[4] = (mode & S_IRGRP) != 0 ? 'r' : '-';
str[5] = (mode & S_IWGRP) != 0 ? 'w' : '-';
str[6] = (mode & S_IXGRP) != 0 ? 'x' : '-';
str[7] = (mode & S_IROTH) != 0 ? 'r' : '-';
str[8] = (mode & S_IWOTH) != 0 ? 'w' : '-';
str[9] = (mode & S_IXOTH) != 0 ? 'x' : '-';
setst ((unsigned long) mode, str);
}
 
/* Return a character indicating the type of file described by
file mode BITS:
'd' for directories
'b' for block special files
'c' for character special files
'm' for multiplexer files
'l' for symbolic links
's' for sockets
'p' for fifos
'-' for any other file type. */
 
#ifndef S_ISDIR
#ifdef S_IFDIR
#define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR)
#else /* ! defined (S_IFDIR) */
#define S_ISDIR(i) (((i) & 0170000) == 040000)
#endif /* ! defined (S_IFDIR) */
#endif /* ! defined (S_ISDIR) */
 
#ifndef S_ISBLK
#ifdef S_IFBLK
#define S_ISBLK(i) (((i) & S_IFMT) == S_IFBLK)
#else /* ! defined (S_IFBLK) */
#define S_ISBLK(i) 0
#endif /* ! defined (S_IFBLK) */
#endif /* ! defined (S_ISBLK) */
 
#ifndef S_ISCHR
#ifdef S_IFCHR
#define S_ISCHR(i) (((i) & S_IFMT) == S_IFCHR)
#else /* ! defined (S_IFCHR) */
#define S_ISCHR(i) 0
#endif /* ! defined (S_IFCHR) */
#endif /* ! defined (S_ISCHR) */
 
#ifndef S_ISFIFO
#ifdef S_IFIFO
#define S_ISFIFO(i) (((i) & S_IFMT) == S_IFIFO)
#else /* ! defined (S_IFIFO) */
#define S_ISFIFO(i) 0
#endif /* ! defined (S_IFIFO) */
#endif /* ! defined (S_ISFIFO) */
 
#ifndef S_ISSOCK
#ifdef S_IFSOCK
#define S_ISSOCK(i) (((i) & S_IFMT) == S_IFSOCK)
#else /* ! defined (S_IFSOCK) */
#define S_ISSOCK(i) 0
#endif /* ! defined (S_IFSOCK) */
#endif /* ! defined (S_ISSOCK) */
 
#ifndef S_ISLNK
#ifdef S_IFLNK
#define S_ISLNK(i) (((i) & S_IFMT) == S_IFLNK)
#else /* ! defined (S_IFLNK) */
#define S_ISLNK(i) 0
#endif /* ! defined (S_IFLNK) */
#endif /* ! defined (S_ISLNK) */
 
static char
ftypelet (unsigned long bits)
{
if (S_ISDIR (bits))
return 'd';
if (S_ISLNK (bits))
return 'l';
if (S_ISBLK (bits))
return 'b';
if (S_ISCHR (bits))
return 'c';
if (S_ISSOCK (bits))
return 's';
if (S_ISFIFO (bits))
return 'p';
 
#ifdef S_IFMT
#ifdef S_IFMPC
if ((bits & S_IFMT) == S_IFMPC
|| (bits & S_IFMT) == S_IFMPB)
return 'm';
#endif
#ifdef S_IFNWK
if ((bits & S_IFMT) == S_IFNWK)
return 'n';
#endif
#endif
 
return '-';
}
 
/* Set the 's' and 't' flags in file attributes string CHARS,
according to the file mode BITS. */
 
static void
setst (unsigned long bits ATTRIBUTE_UNUSED, char *chars ATTRIBUTE_UNUSED)
{
#ifdef S_ISUID
if (bits & S_ISUID)
{
if (chars[3] != 'x')
/* Set-uid, but not executable by owner. */
chars[3] = 'S';
else
chars[3] = 's';
}
#endif
#ifdef S_ISGID
if (bits & S_ISGID)
{
if (chars[6] != 'x')
/* Set-gid, but not executable by group. */
chars[6] = 'S';
else
chars[6] = 's';
}
#endif
#ifdef S_ISVTX
if (bits & S_ISVTX)
{
if (chars[9] != 'x')
/* Sticky, but not executable by others. */
chars[9] = 'T';
else
chars[9] = 't';
}
#endif
}
/contrib/toolchain/binutils/binutils/ieee.c
0,0 → 1,7411
/* ieee.c -- Read and write IEEE-695 debugging information.
Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007,
2008, 2009, 2010, 2011 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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
/* This file reads and writes IEEE-695 debugging information. */
 
#include "sysdep.h"
#include <assert.h>
#include "bfd.h"
#include "ieee.h"
#include "libiberty.h"
#include "debug.h"
#include "budbg.h"
#include "filenames.h"
 
/* This structure holds an entry on the block stack. */
 
struct ieee_block
{
/* The kind of block. */
int kind;
/* The source file name, for a BB5 block. */
const char *filename;
/* The index of the function type, for a BB4 or BB6 block. */
unsigned int fnindx;
/* TRUE if this function is being skipped. */
bfd_boolean skip;
};
 
/* This structure is the block stack. */
 
#define BLOCKSTACK_SIZE (16)
 
struct ieee_blockstack
{
/* The stack pointer. */
struct ieee_block *bsp;
/* The stack. */
struct ieee_block stack[BLOCKSTACK_SIZE];
};
 
/* This structure holds information for a variable. */
 
enum ieee_var_kind
{
IEEE_UNKNOWN,
IEEE_EXTERNAL,
IEEE_GLOBAL,
IEEE_STATIC,
IEEE_LOCAL,
IEEE_FUNCTION
};
 
struct ieee_var
{
/* Start of name. */
const char *name;
/* Length of name. */
unsigned long namlen;
/* Type. */
debug_type type;
/* Slot if we make an indirect type. */
debug_type *pslot;
/* Kind of variable or function. */
enum ieee_var_kind kind;
};
 
/* This structure holds all the variables. */
 
struct ieee_vars
{
/* Number of slots allocated. */
unsigned int alloc;
/* Variables. */
struct ieee_var *vars;
};
 
/* This structure holds information for a type. We need this because
we don't want to represent bitfields as real types. */
 
struct ieee_type
{
/* Type. */
debug_type type;
/* Slot if this is type is referenced before it is defined. */
debug_type *pslot;
/* Slots for arguments if we make indirect types for them. */
debug_type *arg_slots;
/* If this is a bitfield, this is the size in bits. If this is not
a bitfield, this is zero. */
unsigned long bitsize;
};
 
/* This structure holds all the type information. */
 
struct ieee_types
{
/* Number of slots allocated. */
unsigned int alloc;
/* Types. */
struct ieee_type *types;
/* Builtin types. */
#define BUILTIN_TYPE_COUNT (60)
debug_type builtins[BUILTIN_TYPE_COUNT];
};
 
/* This structure holds a linked last of structs with their tag names,
so that we can convert them to C++ classes if necessary. */
 
struct ieee_tag
{
/* Next tag. */
struct ieee_tag *next;
/* This tag name. */
const char *name;
/* The type of the tag. */
debug_type type;
/* The tagged type is an indirect type pointing at this slot. */
debug_type slot;
/* This is an array of slots used when a field type is converted
into a indirect type, in case it needs to be later converted into
a reference type. */
debug_type *fslots;
};
 
/* This structure holds the information we pass around to the parsing
functions. */
 
struct ieee_info
{
/* The debugging handle. */
void *dhandle;
/* The BFD. */
bfd *abfd;
/* The start of the bytes to be parsed. */
const bfd_byte *bytes;
/* The end of the bytes to be parsed. */
const bfd_byte *pend;
/* The block stack. */
struct ieee_blockstack blockstack;
/* Whether we have seen a BB1 or BB2. */
bfd_boolean saw_filename;
/* The variables. */
struct ieee_vars vars;
/* The global variables, after a global typedef block. */
struct ieee_vars *global_vars;
/* The types. */
struct ieee_types types;
/* The global types, after a global typedef block. */
struct ieee_types *global_types;
/* The list of tagged structs. */
struct ieee_tag *tags;
};
 
/* Basic builtin types, not including the pointers. */
 
enum builtin_types
{
builtin_unknown = 0,
builtin_void = 1,
builtin_signed_char = 2,
builtin_unsigned_char = 3,
builtin_signed_short_int = 4,
builtin_unsigned_short_int = 5,
builtin_signed_long = 6,
builtin_unsigned_long = 7,
builtin_signed_long_long = 8,
builtin_unsigned_long_long = 9,
builtin_float = 10,
builtin_double = 11,
builtin_long_double = 12,
builtin_long_long_double = 13,
builtin_quoted_string = 14,
builtin_instruction_address = 15,
builtin_int = 16,
builtin_unsigned = 17,
builtin_unsigned_int = 18,
builtin_char = 19,
builtin_long = 20,
builtin_short = 21,
builtin_unsigned_short = 22,
builtin_short_int = 23,
builtin_signed_short = 24,
builtin_bcd_float = 25
};
 
/* These are the values found in the derivation flags of a 'b'
component record of a 'T' type extension record in a C++ pmisc
record. These are bitmasks. */
 
/* Set for a private base class, clear for a public base class.
Protected base classes are not supported. */
#define BASEFLAGS_PRIVATE (0x1)
/* Set for a virtual base class. */
#define BASEFLAGS_VIRTUAL (0x2)
/* Set for a friend class, clear for a base class. */
#define BASEFLAGS_FRIEND (0x10)
 
/* These are the values found in the specs flags of a 'd', 'm', or 'v'
component record of a 'T' type extension record in a C++ pmisc
record. The same flags are used for a 'M' record in a C++ pmisc
record. */
 
/* The lower two bits hold visibility information. */
#define CXXFLAGS_VISIBILITY (0x3)
/* This value in the lower two bits indicates a public member. */
#define CXXFLAGS_VISIBILITY_PUBLIC (0x0)
/* This value in the lower two bits indicates a private member. */
#define CXXFLAGS_VISIBILITY_PRIVATE (0x1)
/* This value in the lower two bits indicates a protected member. */
#define CXXFLAGS_VISIBILITY_PROTECTED (0x2)
/* Set for a static member. */
#define CXXFLAGS_STATIC (0x4)
/* Set for a virtual override. */
#define CXXFLAGS_OVERRIDE (0x8)
/* Set for a friend function. */
#define CXXFLAGS_FRIEND (0x10)
/* Set for a const function. */
#define CXXFLAGS_CONST (0x20)
/* Set for a volatile function. */
#define CXXFLAGS_VOLATILE (0x40)
/* Set for an overloaded function. */
#define CXXFLAGS_OVERLOADED (0x80)
/* Set for an operator function. */
#define CXXFLAGS_OPERATOR (0x100)
/* Set for a constructor or destructor. */
#define CXXFLAGS_CTORDTOR (0x400)
/* Set for a constructor. */
#define CXXFLAGS_CTOR (0x200)
/* Set for an inline function. */
#define CXXFLAGS_INLINE (0x800)
 
/* Local functions. */
 
static void ieee_error (struct ieee_info *, const bfd_byte *, const char *);
static void ieee_eof (struct ieee_info *);
static char *savestring (const char *, unsigned long);
static bfd_boolean ieee_read_number
(struct ieee_info *, const bfd_byte **, bfd_vma *);
static bfd_boolean ieee_read_optional_number
(struct ieee_info *, const bfd_byte **, bfd_vma *, bfd_boolean *);
static bfd_boolean ieee_read_id
(struct ieee_info *, const bfd_byte **, const char **, unsigned long *);
static bfd_boolean ieee_read_optional_id
(struct ieee_info *, const bfd_byte **, const char **, unsigned long *,
bfd_boolean *);
static bfd_boolean ieee_read_expression
(struct ieee_info *, const bfd_byte **, bfd_vma *);
static debug_type ieee_builtin_type
(struct ieee_info *, const bfd_byte *, unsigned int);
static bfd_boolean ieee_alloc_type
(struct ieee_info *, unsigned int, bfd_boolean);
static bfd_boolean ieee_read_type_index
(struct ieee_info *, const bfd_byte **, debug_type *);
static int ieee_regno_to_genreg (bfd *, int);
static int ieee_genreg_to_regno (bfd *, int);
static bfd_boolean parse_ieee_bb (struct ieee_info *, const bfd_byte **);
static bfd_boolean parse_ieee_be (struct ieee_info *, const bfd_byte **);
static bfd_boolean parse_ieee_nn (struct ieee_info *, const bfd_byte **);
static bfd_boolean parse_ieee_ty (struct ieee_info *, const bfd_byte **);
static bfd_boolean parse_ieee_atn (struct ieee_info *, const bfd_byte **);
static bfd_boolean ieee_read_cxx_misc
(struct ieee_info *, const bfd_byte **, unsigned long);
static bfd_boolean ieee_read_cxx_class
(struct ieee_info *, const bfd_byte **, unsigned long);
static bfd_boolean ieee_read_cxx_defaults
(struct ieee_info *, const bfd_byte **, unsigned long);
static bfd_boolean ieee_read_reference
(struct ieee_info *, const bfd_byte **);
static bfd_boolean ieee_require_asn
(struct ieee_info *, const bfd_byte **, bfd_vma *);
static bfd_boolean ieee_require_atn65
(struct ieee_info *, const bfd_byte **, const char **, unsigned long *);
 
/* Report an error in the IEEE debugging information. */
 
static void
ieee_error (struct ieee_info *info, const bfd_byte *p, const char *s)
{
if (p != NULL)
fprintf (stderr, "%s: 0x%lx: %s (0x%x)\n", bfd_get_filename (info->abfd),
(unsigned long) (p - info->bytes), s, *p);
else
fprintf (stderr, "%s: %s\n", bfd_get_filename (info->abfd), s);
}
 
/* Report an unexpected EOF in the IEEE debugging information. */
 
static void
ieee_eof (struct ieee_info *info)
{
ieee_error (info, (const bfd_byte *) NULL,
_("unexpected end of debugging information"));
}
 
/* Save a string in memory. */
 
static char *
savestring (const char *start, unsigned long len)
{
char *ret;
 
ret = (char *) xmalloc (len + 1);
memcpy (ret, start, len);
ret[len] = '\0';
return ret;
}
 
/* Read a number which must be present in an IEEE file. */
 
static bfd_boolean
ieee_read_number (struct ieee_info *info, const bfd_byte **pp, bfd_vma *pv)
{
return ieee_read_optional_number (info, pp, pv, (bfd_boolean *) NULL);
}
 
/* Read a number in an IEEE file. If ppresent is not NULL, the number
need not be there. */
 
static bfd_boolean
ieee_read_optional_number (struct ieee_info *info, const bfd_byte **pp,
bfd_vma *pv, bfd_boolean *ppresent)
{
ieee_record_enum_type b;
 
if (*pp >= info->pend)
{
if (ppresent != NULL)
{
*ppresent = FALSE;
return TRUE;
}
ieee_eof (info);
return FALSE;
}
 
b = (ieee_record_enum_type) **pp;
++*pp;
 
if (b <= ieee_number_end_enum)
{
*pv = (bfd_vma) b;
if (ppresent != NULL)
*ppresent = TRUE;
return TRUE;
}
 
if (b >= ieee_number_repeat_start_enum && b <= ieee_number_repeat_end_enum)
{
unsigned int i;
 
i = (int) b - (int) ieee_number_repeat_start_enum;
if (*pp + i - 1 >= info->pend)
{
ieee_eof (info);
return FALSE;
}
 
*pv = 0;
for (; i > 0; i--)
{
*pv <<= 8;
*pv += **pp;
++*pp;
}
 
if (ppresent != NULL)
*ppresent = TRUE;
 
return TRUE;
}
 
if (ppresent != NULL)
{
--*pp;
*ppresent = FALSE;
return TRUE;
}
 
ieee_error (info, *pp - 1, _("invalid number"));
return FALSE;
}
 
/* Read a required string from an IEEE file. */
 
static bfd_boolean
ieee_read_id (struct ieee_info *info, const bfd_byte **pp,
const char **pname, unsigned long *pnamlen)
{
return ieee_read_optional_id (info, pp, pname, pnamlen, (bfd_boolean *) NULL);
}
 
/* Read a string from an IEEE file. If ppresent is not NULL, the
string is optional. */
 
static bfd_boolean
ieee_read_optional_id (struct ieee_info *info, const bfd_byte **pp,
const char **pname, unsigned long *pnamlen,
bfd_boolean *ppresent)
{
bfd_byte b;
unsigned long len;
 
if (*pp >= info->pend)
{
ieee_eof (info);
return FALSE;
}
 
b = **pp;
++*pp;
 
if (b <= 0x7f)
len = b;
else if ((ieee_record_enum_type) b == ieee_extension_length_1_enum)
{
len = **pp;
++*pp;
}
else if ((ieee_record_enum_type) b == ieee_extension_length_2_enum)
{
len = (**pp << 8) + (*pp)[1];
*pp += 2;
}
else
{
if (ppresent != NULL)
{
--*pp;
*ppresent = FALSE;
return TRUE;
}
ieee_error (info, *pp - 1, _("invalid string length"));
return FALSE;
}
 
if ((unsigned long) (info->pend - *pp) < len)
{
ieee_eof (info);
return FALSE;
}
 
*pname = (const char *) *pp;
*pnamlen = len;
*pp += len;
 
if (ppresent != NULL)
*ppresent = TRUE;
 
return TRUE;
}
 
/* Read an expression from an IEEE file. Since this code is only used
to parse debugging information, I haven't bothered to write a full
blown IEEE expression parser. I've only thrown in the things I've
seen in debugging information. This can be easily extended if
necessary. */
 
static bfd_boolean
ieee_read_expression (struct ieee_info *info, const bfd_byte **pp,
bfd_vma *pv)
{
const bfd_byte *expr_start;
#define EXPR_STACK_SIZE (10)
bfd_vma expr_stack[EXPR_STACK_SIZE];
bfd_vma *esp;
 
expr_start = *pp;
 
esp = expr_stack;
 
while (1)
{
const bfd_byte *start;
bfd_vma val;
bfd_boolean present;
ieee_record_enum_type c;
 
start = *pp;
 
if (! ieee_read_optional_number (info, pp, &val, &present))
return FALSE;
 
if (present)
{
if (esp - expr_stack >= EXPR_STACK_SIZE)
{
ieee_error (info, start, _("expression stack overflow"));
return FALSE;
}
*esp++ = val;
continue;
}
 
c = (ieee_record_enum_type) **pp;
 
if (c >= ieee_module_beginning_enum)
break;
 
++*pp;
 
if (c == ieee_comma)
break;
 
switch (c)
{
default:
ieee_error (info, start, _("unsupported IEEE expression operator"));
break;
 
case ieee_variable_R_enum:
{
bfd_vma indx;
asection *s;
 
if (! ieee_read_number (info, pp, &indx))
return FALSE;
for (s = info->abfd->sections; s != NULL; s = s->next)
if ((bfd_vma) s->target_index == indx)
break;
if (s == NULL)
{
ieee_error (info, start, _("unknown section"));
return FALSE;
}
 
if (esp - expr_stack >= EXPR_STACK_SIZE)
{
ieee_error (info, start, _("expression stack overflow"));
return FALSE;
}
 
*esp++ = bfd_get_section_vma (info->abfd, s);
}
break;
 
case ieee_function_plus_enum:
case ieee_function_minus_enum:
{
bfd_vma v1, v2;
 
if (esp - expr_stack < 2)
{
ieee_error (info, start, _("expression stack underflow"));
return FALSE;
}
 
v1 = *--esp;
v2 = *--esp;
*esp++ = v1 + v2;
}
break;
}
}
 
if (esp - 1 != expr_stack)
{
ieee_error (info, expr_start, _("expression stack mismatch"));
return FALSE;
}
 
*pv = *--esp;
 
return TRUE;
}
 
/* Return an IEEE builtin type. */
 
static debug_type
ieee_builtin_type (struct ieee_info *info, const bfd_byte *p,
unsigned int indx)
{
void *dhandle;
debug_type type;
const char *name;
 
if (indx < BUILTIN_TYPE_COUNT
&& info->types.builtins[indx] != DEBUG_TYPE_NULL)
return info->types.builtins[indx];
 
dhandle = info->dhandle;
 
if (indx >= 32 && indx < 64)
{
type = debug_make_pointer_type (dhandle,
ieee_builtin_type (info, p, indx - 32));
assert (indx < BUILTIN_TYPE_COUNT);
info->types.builtins[indx] = type;
return type;
}
 
switch ((enum builtin_types) indx)
{
default:
ieee_error (info, p, _("unknown builtin type"));
return NULL;
 
case builtin_unknown:
type = debug_make_void_type (dhandle);
name = NULL;
break;
 
case builtin_void:
type = debug_make_void_type (dhandle);
name = "void";
break;
 
case builtin_signed_char:
type = debug_make_int_type (dhandle, 1, FALSE);
name = "signed char";
break;
 
case builtin_unsigned_char:
type = debug_make_int_type (dhandle, 1, TRUE);
name = "unsigned char";
break;
 
case builtin_signed_short_int:
type = debug_make_int_type (dhandle, 2, FALSE);
name = "signed short int";
break;
 
case builtin_unsigned_short_int:
type = debug_make_int_type (dhandle, 2, TRUE);
name = "unsigned short int";
break;
 
case builtin_signed_long:
type = debug_make_int_type (dhandle, 4, FALSE);
name = "signed long";
break;
 
case builtin_unsigned_long:
type = debug_make_int_type (dhandle, 4, TRUE);
name = "unsigned long";
break;
 
case builtin_signed_long_long:
type = debug_make_int_type (dhandle, 8, FALSE);
name = "signed long long";
break;
 
case builtin_unsigned_long_long:
type = debug_make_int_type (dhandle, 8, TRUE);
name = "unsigned long long";
break;
 
case builtin_float:
type = debug_make_float_type (dhandle, 4);
name = "float";
break;
 
case builtin_double:
type = debug_make_float_type (dhandle, 8);
name = "double";
break;
 
case builtin_long_double:
/* FIXME: The size for this type should depend upon the
processor. */
type = debug_make_float_type (dhandle, 12);
name = "long double";
break;
 
case builtin_long_long_double:
type = debug_make_float_type (dhandle, 16);
name = "long long double";
break;
 
case builtin_quoted_string:
type = debug_make_array_type (dhandle,
ieee_builtin_type (info, p,
((unsigned int)
builtin_char)),
ieee_builtin_type (info, p,
((unsigned int)
builtin_int)),
0, -1, TRUE);
name = "QUOTED STRING";
break;
 
case builtin_instruction_address:
/* FIXME: This should be a code address. */
type = debug_make_int_type (dhandle, 4, TRUE);
name = "instruction address";
break;
 
case builtin_int:
/* FIXME: The size for this type should depend upon the
processor. */
type = debug_make_int_type (dhandle, 4, FALSE);
name = "int";
break;
 
case builtin_unsigned:
/* FIXME: The size for this type should depend upon the
processor. */
type = debug_make_int_type (dhandle, 4, TRUE);
name = "unsigned";
break;
 
case builtin_unsigned_int:
/* FIXME: The size for this type should depend upon the
processor. */
type = debug_make_int_type (dhandle, 4, TRUE);
name = "unsigned int";
break;
 
case builtin_char:
type = debug_make_int_type (dhandle, 1, FALSE);
name = "char";
break;
 
case builtin_long:
type = debug_make_int_type (dhandle, 4, FALSE);
name = "long";
break;
 
case builtin_short:
type = debug_make_int_type (dhandle, 2, FALSE);
name = "short";
break;
 
case builtin_unsigned_short:
type = debug_make_int_type (dhandle, 2, TRUE);
name = "unsigned short";
break;
 
case builtin_short_int:
type = debug_make_int_type (dhandle, 2, FALSE);
name = "short int";
break;
 
case builtin_signed_short:
type = debug_make_int_type (dhandle, 2, FALSE);
name = "signed short";
break;
 
case builtin_bcd_float:
ieee_error (info, p, _("BCD float type not supported"));
return DEBUG_TYPE_NULL;
}
 
if (name != NULL)
type = debug_name_type (dhandle, name, type);
 
assert (indx < BUILTIN_TYPE_COUNT);
 
info->types.builtins[indx] = type;
 
return type;
}
 
/* Allocate more space in the type table. If ref is TRUE, this is a
reference to the type; if it is not already defined, we should set
up an indirect type. */
 
static bfd_boolean
ieee_alloc_type (struct ieee_info *info, unsigned int indx, bfd_boolean ref)
{
unsigned int nalloc;
register struct ieee_type *t;
struct ieee_type *tend;
 
if (indx >= info->types.alloc)
{
nalloc = info->types.alloc;
if (nalloc == 0)
nalloc = 4;
while (indx >= nalloc)
nalloc *= 2;
 
info->types.types = ((struct ieee_type *)
xrealloc (info->types.types,
nalloc * sizeof *info->types.types));
 
memset (info->types.types + info->types.alloc, 0,
(nalloc - info->types.alloc) * sizeof *info->types.types);
 
tend = info->types.types + nalloc;
for (t = info->types.types + info->types.alloc; t < tend; t++)
t->type = DEBUG_TYPE_NULL;
 
info->types.alloc = nalloc;
}
 
if (ref)
{
t = info->types.types + indx;
if (t->type == NULL)
{
t->pslot = (debug_type *) xmalloc (sizeof *t->pslot);
*t->pslot = DEBUG_TYPE_NULL;
t->type = debug_make_indirect_type (info->dhandle, t->pslot,
(const char *) NULL);
if (t->type == NULL)
return FALSE;
}
}
 
return TRUE;
}
 
/* Read a type index and return the corresponding type. */
 
static bfd_boolean
ieee_read_type_index (struct ieee_info *info, const bfd_byte **pp,
debug_type *ptype)
{
const bfd_byte *start;
bfd_vma indx;
 
start = *pp;
 
if (! ieee_read_number (info, pp, &indx))
return FALSE;
 
if (indx < 256)
{
*ptype = ieee_builtin_type (info, start, indx);
if (*ptype == NULL)
return FALSE;
return TRUE;
}
 
indx -= 256;
if (! ieee_alloc_type (info, indx, TRUE))
return FALSE;
 
*ptype = info->types.types[indx].type;
 
return TRUE;
}
 
/* Parse IEEE debugging information for a file. This is passed the
bytes which compose the Debug Information Part of an IEEE file. */
 
bfd_boolean
parse_ieee (void *dhandle, bfd *abfd, const bfd_byte *bytes, bfd_size_type len)
{
struct ieee_info info;
unsigned int i;
const bfd_byte *p, *pend;
 
info.dhandle = dhandle;
info.abfd = abfd;
info.bytes = bytes;
info.pend = bytes + len;
info.blockstack.bsp = info.blockstack.stack;
info.saw_filename = FALSE;
info.vars.alloc = 0;
info.vars.vars = NULL;
info.global_vars = NULL;
info.types.alloc = 0;
info.types.types = NULL;
info.global_types = NULL;
info.tags = NULL;
for (i = 0; i < BUILTIN_TYPE_COUNT; i++)
info.types.builtins[i] = DEBUG_TYPE_NULL;
 
p = bytes;
pend = info.pend;
while (p < pend)
{
const bfd_byte *record_start;
ieee_record_enum_type c;
 
record_start = p;
 
c = (ieee_record_enum_type) *p++;
 
if (c == ieee_at_record_enum)
c = (ieee_record_enum_type) (((unsigned int) c << 8) | *p++);
 
if (c <= ieee_number_repeat_end_enum)
{
ieee_error (&info, record_start, _("unexpected number"));
return FALSE;
}
 
switch (c)
{
default:
ieee_error (&info, record_start, _("unexpected record type"));
return FALSE;
 
case ieee_bb_record_enum:
if (! parse_ieee_bb (&info, &p))
return FALSE;
break;
 
case ieee_be_record_enum:
if (! parse_ieee_be (&info, &p))
return FALSE;
break;
 
case ieee_nn_record:
if (! parse_ieee_nn (&info, &p))
return FALSE;
break;
 
case ieee_ty_record_enum:
if (! parse_ieee_ty (&info, &p))
return FALSE;
break;
 
case ieee_atn_record_enum:
if (! parse_ieee_atn (&info, &p))
return FALSE;
break;
}
}
 
if (info.blockstack.bsp != info.blockstack.stack)
{
ieee_error (&info, (const bfd_byte *) NULL,
_("blocks left on stack at end"));
return FALSE;
}
 
return TRUE;
}
 
/* Handle an IEEE BB record. */
 
static bfd_boolean
parse_ieee_bb (struct ieee_info *info, const bfd_byte **pp)
{
const bfd_byte *block_start;
bfd_byte b;
bfd_vma size;
const char *name;
unsigned long namlen;
char *namcopy = NULL;
unsigned int fnindx;
bfd_boolean skip;
 
block_start = *pp;
 
b = **pp;
++*pp;
 
if (! ieee_read_number (info, pp, &size)
|| ! ieee_read_id (info, pp, &name, &namlen))
return FALSE;
 
fnindx = (unsigned int) -1;
skip = FALSE;
 
switch (b)
{
case 1:
/* BB1: Type definitions local to a module. */
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_set_filename (info->dhandle, namcopy))
return FALSE;
info->saw_filename = TRUE;
 
/* Discard any variables or types we may have seen before. */
if (info->vars.vars != NULL)
free (info->vars.vars);
info->vars.vars = NULL;
info->vars.alloc = 0;
if (info->types.types != NULL)
free (info->types.types);
info->types.types = NULL;
info->types.alloc = 0;
 
/* Initialize the types to the global types. */
if (info->global_types != NULL)
{
info->types.alloc = info->global_types->alloc;
info->types.types = ((struct ieee_type *)
xmalloc (info->types.alloc
* sizeof (*info->types.types)));
memcpy (info->types.types, info->global_types->types,
info->types.alloc * sizeof (*info->types.types));
}
 
break;
 
case 2:
/* BB2: Global type definitions. The name is supposed to be
empty, but we don't check. */
if (! debug_set_filename (info->dhandle, "*global*"))
return FALSE;
info->saw_filename = TRUE;
break;
 
case 3:
/* BB3: High level module block begin. We don't have to do
anything here. The name is supposed to be the same as for
the BB1, but we don't check. */
break;
 
case 4:
/* BB4: Global function. */
{
bfd_vma stackspace, typindx, offset;
debug_type return_type;
 
if (! ieee_read_number (info, pp, &stackspace)
|| ! ieee_read_number (info, pp, &typindx)
|| ! ieee_read_expression (info, pp, &offset))
return FALSE;
 
/* We have no way to record the stack space. FIXME. */
 
if (typindx < 256)
{
return_type = ieee_builtin_type (info, block_start, typindx);
if (return_type == DEBUG_TYPE_NULL)
return FALSE;
}
else
{
typindx -= 256;
if (! ieee_alloc_type (info, typindx, TRUE))
return FALSE;
fnindx = typindx;
return_type = info->types.types[typindx].type;
if (debug_get_type_kind (info->dhandle, return_type)
== DEBUG_KIND_FUNCTION)
return_type = debug_get_return_type (info->dhandle,
return_type);
}
 
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_record_function (info->dhandle, namcopy, return_type,
TRUE, offset))
return FALSE;
}
break;
 
case 5:
/* BB5: File name for source line numbers. */
{
unsigned int i;
 
/* We ignore the date and time. FIXME. */
for (i = 0; i < 6; i++)
{
bfd_vma ignore;
bfd_boolean present;
 
if (! ieee_read_optional_number (info, pp, &ignore, &present))
return FALSE;
if (! present)
break;
}
 
if (! info->saw_filename)
{
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_set_filename (info->dhandle, namcopy))
return FALSE;
info->saw_filename = TRUE;
}
 
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_start_source (info->dhandle, namcopy))
return FALSE;
}
break;
 
case 6:
/* BB6: Local function or block. */
{
bfd_vma stackspace, typindx, offset;
 
if (! ieee_read_number (info, pp, &stackspace)
|| ! ieee_read_number (info, pp, &typindx)
|| ! ieee_read_expression (info, pp, &offset))
return FALSE;
 
/* We have no way to record the stack space. FIXME. */
 
if (namlen == 0)
{
if (! debug_start_block (info->dhandle, offset))
return FALSE;
/* Change b to indicate that this is a block
rather than a function. */
b = 0x86;
}
else
{
/* The MRI C++ compiler will output a fake function named
__XRYCPP to hold C++ debugging information. We skip
that function. This is not crucial, but it makes
converting from IEEE to other debug formats work
better. */
if (strncmp (name, "__XRYCPP", namlen) == 0)
skip = TRUE;
else
{
debug_type return_type;
 
if (typindx < 256)
{
return_type = ieee_builtin_type (info, block_start,
typindx);
if (return_type == NULL)
return FALSE;
}
else
{
typindx -= 256;
if (! ieee_alloc_type (info, typindx, TRUE))
return FALSE;
fnindx = typindx;
return_type = info->types.types[typindx].type;
if (debug_get_type_kind (info->dhandle, return_type)
== DEBUG_KIND_FUNCTION)
return_type = debug_get_return_type (info->dhandle,
return_type);
}
 
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_record_function (info->dhandle, namcopy,
return_type, FALSE, offset))
return FALSE;
}
}
}
break;
 
case 10:
/* BB10: Assembler module scope. In the normal case, we
completely ignore all this information. FIXME. */
{
const char *inam, *vstr;
unsigned long inamlen, vstrlen;
bfd_vma tool_type;
bfd_boolean present;
unsigned int i;
 
if (! info->saw_filename)
{
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_set_filename (info->dhandle, namcopy))
return FALSE;
info->saw_filename = TRUE;
}
 
if (! ieee_read_id (info, pp, &inam, &inamlen)
|| ! ieee_read_number (info, pp, &tool_type)
|| ! ieee_read_optional_id (info, pp, &vstr, &vstrlen, &present))
return FALSE;
for (i = 0; i < 6; i++)
{
bfd_vma ignore;
 
if (! ieee_read_optional_number (info, pp, &ignore, &present))
return FALSE;
if (! present)
break;
}
}
break;
 
case 11:
/* BB11: Module section. We completely ignore all this
information. FIXME. */
{
bfd_vma sectype, secindx, offset, map;
bfd_boolean present;
 
if (! ieee_read_number (info, pp, &sectype)
|| ! ieee_read_number (info, pp, &secindx)
|| ! ieee_read_expression (info, pp, &offset)
|| ! ieee_read_optional_number (info, pp, &map, &present))
return FALSE;
}
break;
 
default:
ieee_error (info, block_start, _("unknown BB type"));
return FALSE;
}
 
 
/* Push this block on the block stack. */
 
if (info->blockstack.bsp >= info->blockstack.stack + BLOCKSTACK_SIZE)
{
ieee_error (info, (const bfd_byte *) NULL, _("stack overflow"));
return FALSE;
}
 
info->blockstack.bsp->kind = b;
if (b == 5)
info->blockstack.bsp->filename = namcopy;
info->blockstack.bsp->fnindx = fnindx;
info->blockstack.bsp->skip = skip;
++info->blockstack.bsp;
 
return TRUE;
}
 
/* Handle an IEEE BE record. */
 
static bfd_boolean
parse_ieee_be (struct ieee_info *info, const bfd_byte **pp)
{
bfd_vma offset;
 
if (info->blockstack.bsp <= info->blockstack.stack)
{
ieee_error (info, *pp, _("stack underflow"));
return FALSE;
}
--info->blockstack.bsp;
 
switch (info->blockstack.bsp->kind)
{
case 2:
/* When we end the global typedefs block, we copy out the
contents of info->vars. This is because the variable indices
may be reused in the local blocks. However, we need to
preserve them so that we can locate a function returning a
reference variable whose type is named in the global typedef
block. */
info->global_vars = ((struct ieee_vars *)
xmalloc (sizeof *info->global_vars));
info->global_vars->alloc = info->vars.alloc;
info->global_vars->vars = ((struct ieee_var *)
xmalloc (info->vars.alloc
* sizeof (*info->vars.vars)));
memcpy (info->global_vars->vars, info->vars.vars,
info->vars.alloc * sizeof (*info->vars.vars));
 
/* We also copy out the non builtin parts of info->types, since
the types are discarded when we start a new block. */
info->global_types = ((struct ieee_types *)
xmalloc (sizeof *info->global_types));
info->global_types->alloc = info->types.alloc;
info->global_types->types = ((struct ieee_type *)
xmalloc (info->types.alloc
* sizeof (*info->types.types)));
memcpy (info->global_types->types, info->types.types,
info->types.alloc * sizeof (*info->types.types));
memset (info->global_types->builtins, 0,
sizeof (info->global_types->builtins));
 
break;
 
case 4:
case 6:
if (! ieee_read_expression (info, pp, &offset))
return FALSE;
if (! info->blockstack.bsp->skip)
{
if (! debug_end_function (info->dhandle, offset + 1))
return FALSE;
}
break;
 
case 0x86:
/* This is BE6 when BB6 started a block rather than a local
function. */
if (! ieee_read_expression (info, pp, &offset))
return FALSE;
if (! debug_end_block (info->dhandle, offset + 1))
return FALSE;
break;
 
case 5:
/* When we end a BB5, we look up the stack for the last BB5, if
there is one, so that we can call debug_start_source. */
if (info->blockstack.bsp > info->blockstack.stack)
{
struct ieee_block *bl;
 
bl = info->blockstack.bsp;
do
{
--bl;
if (bl->kind == 5)
{
if (! debug_start_source (info->dhandle, bl->filename))
return FALSE;
break;
}
}
while (bl != info->blockstack.stack);
}
break;
 
case 11:
if (! ieee_read_expression (info, pp, &offset))
return FALSE;
/* We just ignore the module size. FIXME. */
break;
 
default:
/* Other block types do not have any trailing information. */
break;
}
 
return TRUE;
}
 
/* Parse an NN record. */
 
static bfd_boolean
parse_ieee_nn (struct ieee_info *info, const bfd_byte **pp)
{
const bfd_byte *nn_start;
bfd_vma varindx;
const char *name;
unsigned long namlen;
 
nn_start = *pp;
 
if (! ieee_read_number (info, pp, &varindx)
|| ! ieee_read_id (info, pp, &name, &namlen))
return FALSE;
 
if (varindx < 32)
{
ieee_error (info, nn_start, _("illegal variable index"));
return FALSE;
}
varindx -= 32;
 
if (varindx >= info->vars.alloc)
{
unsigned int alloc;
 
alloc = info->vars.alloc;
if (alloc == 0)
alloc = 4;
while (varindx >= alloc)
alloc *= 2;
info->vars.vars = ((struct ieee_var *)
xrealloc (info->vars.vars,
alloc * sizeof *info->vars.vars));
memset (info->vars.vars + info->vars.alloc, 0,
(alloc - info->vars.alloc) * sizeof *info->vars.vars);
info->vars.alloc = alloc;
}
 
info->vars.vars[varindx].name = name;
info->vars.vars[varindx].namlen = namlen;
 
return TRUE;
}
 
/* Parse a TY record. */
 
static bfd_boolean
parse_ieee_ty (struct ieee_info *info, const bfd_byte **pp)
{
const bfd_byte *ty_start, *ty_var_start, *ty_code_start;
bfd_vma typeindx, varindx, tc;
void *dhandle;
bfd_boolean tag, typdef;
debug_type *arg_slots;
unsigned long type_bitsize;
debug_type type;
 
ty_start = *pp;
 
if (! ieee_read_number (info, pp, &typeindx))
return FALSE;
 
if (typeindx < 256)
{
ieee_error (info, ty_start, _("illegal type index"));
return FALSE;
}
 
typeindx -= 256;
if (! ieee_alloc_type (info, typeindx, FALSE))
return FALSE;
 
if (**pp != 0xce)
{
ieee_error (info, *pp, _("unknown TY code"));
return FALSE;
}
++*pp;
 
ty_var_start = *pp;
 
if (! ieee_read_number (info, pp, &varindx))
return FALSE;
 
if (varindx < 32)
{
ieee_error (info, ty_var_start, _("illegal variable index"));
return FALSE;
}
varindx -= 32;
 
if (varindx >= info->vars.alloc || info->vars.vars[varindx].name == NULL)
{
ieee_error (info, ty_var_start, _("undefined variable in TY"));
return FALSE;
}
 
ty_code_start = *pp;
 
if (! ieee_read_number (info, pp, &tc))
return FALSE;
 
dhandle = info->dhandle;
 
tag = FALSE;
typdef = FALSE;
arg_slots = NULL;
type_bitsize = 0;
switch (tc)
{
default:
ieee_error (info, ty_code_start, _("unknown TY code"));
return FALSE;
 
case '!':
/* Unknown type, with size. We treat it as int. FIXME. */
{
bfd_vma size;
 
if (! ieee_read_number (info, pp, &size))
return FALSE;
type = debug_make_int_type (dhandle, size, FALSE);
}
break;
 
case 'A': /* Array. */
case 'a': /* FORTRAN array in column/row order. FIXME: Not
distinguished from normal array. */
{
debug_type ele_type;
bfd_vma lower, upper;
 
if (! ieee_read_type_index (info, pp, &ele_type)
|| ! ieee_read_number (info, pp, &lower)
|| ! ieee_read_number (info, pp, &upper))
return FALSE;
type = debug_make_array_type (dhandle, ele_type,
ieee_builtin_type (info, ty_code_start,
((unsigned int)
builtin_int)),
(bfd_signed_vma) lower,
(bfd_signed_vma) upper,
FALSE);
}
break;
 
case 'E':
/* Simple enumeration. */
{
bfd_vma size;
unsigned int alloc;
const char **names;
unsigned int c;
bfd_signed_vma *vals;
unsigned int i;
 
if (! ieee_read_number (info, pp, &size))
return FALSE;
/* FIXME: we ignore the enumeration size. */
 
alloc = 10;
names = (const char **) xmalloc (alloc * sizeof *names);
memset (names, 0, alloc * sizeof *names);
c = 0;
while (1)
{
const char *name;
unsigned long namlen;
bfd_boolean present;
 
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
if (! present)
break;
 
if (c + 1 >= alloc)
{
alloc += 10;
names = ((const char **)
xrealloc (names, alloc * sizeof *names));
}
 
names[c] = savestring (name, namlen);
if (names[c] == NULL)
return FALSE;
++c;
}
 
names[c] = NULL;
 
vals = (bfd_signed_vma *) xmalloc (c * sizeof *vals);
for (i = 0; i < c; i++)
vals[i] = i;
 
type = debug_make_enum_type (dhandle, names, vals);
tag = TRUE;
}
break;
 
case 'G':
/* Struct with bit fields. */
{
bfd_vma size;
unsigned int alloc;
debug_field *fields;
unsigned int c;
 
if (! ieee_read_number (info, pp, &size))
return FALSE;
 
alloc = 10;
fields = (debug_field *) xmalloc (alloc * sizeof *fields);
c = 0;
while (1)
{
const char *name;
unsigned long namlen;
bfd_boolean present;
debug_type ftype;
bfd_vma bitpos, bitsize;
 
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
if (! present)
break;
if (! ieee_read_type_index (info, pp, &ftype)
|| ! ieee_read_number (info, pp, &bitpos)
|| ! ieee_read_number (info, pp, &bitsize))
return FALSE;
 
if (c + 1 >= alloc)
{
alloc += 10;
fields = ((debug_field *)
xrealloc (fields, alloc * sizeof *fields));
}
 
fields[c] = debug_make_field (dhandle, savestring (name, namlen),
ftype, bitpos, bitsize,
DEBUG_VISIBILITY_PUBLIC);
if (fields[c] == NULL)
return FALSE;
++c;
}
 
fields[c] = NULL;
 
type = debug_make_struct_type (dhandle, TRUE, size, fields);
tag = TRUE;
}
break;
 
case 'N':
/* Enumeration. */
{
unsigned int alloc;
const char **names;
bfd_signed_vma *vals;
unsigned int c;
 
alloc = 10;
names = (const char **) xmalloc (alloc * sizeof *names);
vals = (bfd_signed_vma *) xmalloc (alloc * sizeof *names);
c = 0;
while (1)
{
const char *name;
unsigned long namlen;
bfd_boolean present;
bfd_vma val;
 
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
if (! present)
break;
if (! ieee_read_number (info, pp, &val))
return FALSE;
 
/* If the length of the name is zero, then the value is
actually the size of the enum. We ignore this
information. FIXME. */
if (namlen == 0)
continue;
 
if (c + 1 >= alloc)
{
alloc += 10;
names = ((const char **)
xrealloc (names, alloc * sizeof *names));
vals = ((bfd_signed_vma *)
xrealloc (vals, alloc * sizeof *vals));
}
 
names[c] = savestring (name, namlen);
if (names[c] == NULL)
return FALSE;
vals[c] = (bfd_signed_vma) val;
++c;
}
 
names[c] = NULL;
 
type = debug_make_enum_type (dhandle, names, vals);
tag = TRUE;
}
break;
 
case 'O': /* Small pointer. We don't distinguish small and large
pointers. FIXME. */
case 'P': /* Large pointer. */
{
debug_type t;
 
if (! ieee_read_type_index (info, pp, &t))
return FALSE;
type = debug_make_pointer_type (dhandle, t);
}
break;
 
case 'R':
/* Range. */
{
bfd_vma low, high, signedp, size;
 
if (! ieee_read_number (info, pp, &low)
|| ! ieee_read_number (info, pp, &high)
|| ! ieee_read_number (info, pp, &signedp)
|| ! ieee_read_number (info, pp, &size))
return FALSE;
 
type = debug_make_range_type (dhandle,
debug_make_int_type (dhandle, size,
! signedp),
(bfd_signed_vma) low,
(bfd_signed_vma) high);
}
break;
 
case 'S': /* Struct. */
case 'U': /* Union. */
{
bfd_vma size;
unsigned int alloc;
debug_field *fields;
unsigned int c;
 
if (! ieee_read_number (info, pp, &size))
return FALSE;
 
alloc = 10;
fields = (debug_field *) xmalloc (alloc * sizeof *fields);
c = 0;
while (1)
{
const char *name;
unsigned long namlen;
bfd_boolean present;
bfd_vma tindx;
bfd_vma offset;
debug_type ftype;
bfd_vma bitsize;
 
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
if (! present)
break;
if (! ieee_read_number (info, pp, &tindx)
|| ! ieee_read_number (info, pp, &offset))
return FALSE;
 
if (tindx < 256)
{
ftype = ieee_builtin_type (info, ty_code_start, tindx);
bitsize = 0;
offset *= 8;
}
else
{
struct ieee_type *t;
 
tindx -= 256;
if (! ieee_alloc_type (info, tindx, TRUE))
return FALSE;
t = info->types.types + tindx;
ftype = t->type;
bitsize = t->bitsize;
if (bitsize == 0)
offset *= 8;
}
 
if (c + 1 >= alloc)
{
alloc += 10;
fields = ((debug_field *)
xrealloc (fields, alloc * sizeof *fields));
}
 
fields[c] = debug_make_field (dhandle, savestring (name, namlen),
ftype, offset, bitsize,
DEBUG_VISIBILITY_PUBLIC);
if (fields[c] == NULL)
return FALSE;
++c;
}
 
fields[c] = NULL;
 
type = debug_make_struct_type (dhandle, tc == 'S', size, fields);
tag = TRUE;
}
break;
 
case 'T':
/* Typedef. */
if (! ieee_read_type_index (info, pp, &type))
return FALSE;
typdef = TRUE;
break;
 
case 'X':
/* Procedure. FIXME: This is an extern declaration, which we
have no way of representing. */
{
bfd_vma attr;
debug_type rtype;
bfd_vma nargs;
bfd_boolean present;
struct ieee_var *pv;
 
/* FIXME: We ignore the attribute and the argument names. */
 
if (! ieee_read_number (info, pp, &attr)
|| ! ieee_read_type_index (info, pp, &rtype)
|| ! ieee_read_number (info, pp, &nargs))
return FALSE;
do
{
const char *name;
unsigned long namlen;
 
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
}
while (present);
 
pv = info->vars.vars + varindx;
pv->kind = IEEE_EXTERNAL;
if (pv->namlen > 0
&& debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER)
{
/* Set up the return type as an indirect type pointing to
the variable slot, so that we can change it to a
reference later if appropriate. */
pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot);
*pv->pslot = rtype;
rtype = debug_make_indirect_type (dhandle, pv->pslot,
(const char *) NULL);
}
 
type = debug_make_function_type (dhandle, rtype, (debug_type *) NULL,
FALSE);
}
break;
 
case 'V':
case 'v':
/* Void. This is not documented, but the MRI compiler emits it. */
type = debug_make_void_type (dhandle);
break;
 
case 'Z':
/* Array with 0 lower bound. */
{
debug_type etype;
bfd_vma high;
 
if (! ieee_read_type_index (info, pp, &etype)
|| ! ieee_read_number (info, pp, &high))
return FALSE;
 
type = debug_make_array_type (dhandle, etype,
ieee_builtin_type (info, ty_code_start,
((unsigned int)
builtin_int)),
0, (bfd_signed_vma) high, FALSE);
}
break;
 
case 'c': /* Complex. */
case 'd': /* Double complex. */
{
const char *name;
unsigned long namlen;
 
/* FIXME: I don't know what the name means. */
 
if (! ieee_read_id (info, pp, &name, &namlen))
return FALSE;
 
type = debug_make_complex_type (dhandle, tc == 'c' ? 4 : 8);
}
break;
 
case 'f':
/* Pascal file name. FIXME. */
ieee_error (info, ty_code_start, _("Pascal file name not supported"));
return FALSE;
 
case 'g':
/* Bitfield type. */
{
bfd_vma signedp, bitsize, dummy;
const bfd_byte *hold;
bfd_boolean present;
 
if (! ieee_read_number (info, pp, &signedp)
|| ! ieee_read_number (info, pp, &bitsize))
return FALSE;
 
/* I think the documentation says that there is a type index,
but some actual files do not have one. */
hold = *pp;
if (! ieee_read_optional_number (info, pp, &dummy, &present))
return FALSE;
if (! present)
{
/* FIXME: This is just a guess. */
type = debug_make_int_type (dhandle, 4,
signedp ? FALSE : TRUE);
}
else
{
*pp = hold;
if (! ieee_read_type_index (info, pp, &type))
return FALSE;
}
type_bitsize = bitsize;
}
break;
 
case 'n':
/* Qualifier. */
{
bfd_vma kind;
debug_type t;
 
if (! ieee_read_number (info, pp, &kind)
|| ! ieee_read_type_index (info, pp, &t))
return FALSE;
 
switch (kind)
{
default:
ieee_error (info, ty_start, _("unsupported qualifier"));
return FALSE;
 
case 1:
type = debug_make_const_type (dhandle, t);
break;
 
case 2:
type = debug_make_volatile_type (dhandle, t);
break;
}
}
break;
 
case 's':
/* Set. */
{
bfd_vma size;
debug_type etype;
 
if (! ieee_read_number (info, pp, &size)
|| ! ieee_read_type_index (info, pp, &etype))
return FALSE;
 
/* FIXME: We ignore the size. */
 
type = debug_make_set_type (dhandle, etype, FALSE);
}
break;
 
case 'x':
/* Procedure with compiler dependencies. */
{
struct ieee_var *pv;
bfd_vma attr, frame_type, push_mask, nargs, level, father;
debug_type rtype;
debug_type *arg_types;
bfd_boolean varargs;
bfd_boolean present;
 
/* FIXME: We ignore some of this information. */
 
pv = info->vars.vars + varindx;
 
if (! ieee_read_number (info, pp, &attr)
|| ! ieee_read_number (info, pp, &frame_type)
|| ! ieee_read_number (info, pp, &push_mask)
|| ! ieee_read_type_index (info, pp, &rtype)
|| ! ieee_read_number (info, pp, &nargs))
return FALSE;
if (nargs == (bfd_vma) -1)
{
arg_types = NULL;
varargs = FALSE;
}
else
{
unsigned int i;
 
arg_types = ((debug_type *)
xmalloc ((nargs + 1) * sizeof *arg_types));
for (i = 0; i < nargs; i++)
if (! ieee_read_type_index (info, pp, arg_types + i))
return FALSE;
 
/* If the last type is pointer to void, this is really a
varargs function. */
varargs = FALSE;
if (nargs > 0)
{
debug_type last;
 
last = arg_types[nargs - 1];
if (debug_get_type_kind (dhandle, last) == DEBUG_KIND_POINTER
&& (debug_get_type_kind (dhandle,
debug_get_target_type (dhandle,
last))
== DEBUG_KIND_VOID))
{
--nargs;
varargs = TRUE;
}
}
 
/* If there are any pointer arguments, turn them into
indirect types in case we later need to convert them to
reference types. */
for (i = 0; i < nargs; i++)
{
if (debug_get_type_kind (dhandle, arg_types[i])
== DEBUG_KIND_POINTER)
{
if (arg_slots == NULL)
{
arg_slots = ((debug_type *)
xmalloc (nargs * sizeof *arg_slots));
memset (arg_slots, 0, nargs * sizeof *arg_slots);
}
arg_slots[i] = arg_types[i];
arg_types[i] =
debug_make_indirect_type (dhandle,
arg_slots + i,
(const char *) NULL);
}
}
 
arg_types[nargs] = DEBUG_TYPE_NULL;
}
if (! ieee_read_number (info, pp, &level)
|| ! ieee_read_optional_number (info, pp, &father, &present))
return FALSE;
 
/* We can't distinguish between a global function and a static
function. */
pv->kind = IEEE_FUNCTION;
 
if (pv->namlen > 0
&& debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER)
{
/* Set up the return type as an indirect type pointing to
the variable slot, so that we can change it to a
reference later if appropriate. */
pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot);
*pv->pslot = rtype;
rtype = debug_make_indirect_type (dhandle, pv->pslot,
(const char *) NULL);
}
 
type = debug_make_function_type (dhandle, rtype, arg_types, varargs);
}
break;
}
 
/* Record the type in the table. */
 
if (type == DEBUG_TYPE_NULL)
return FALSE;
 
info->vars.vars[varindx].type = type;
 
if ((tag || typdef)
&& info->vars.vars[varindx].namlen > 0)
{
const char *name;
 
name = savestring (info->vars.vars[varindx].name,
info->vars.vars[varindx].namlen);
if (typdef)
type = debug_name_type (dhandle, name, type);
else if (tc == 'E' || tc == 'N')
type = debug_tag_type (dhandle, name, type);
else
{
struct ieee_tag *it;
 
/* We must allocate all struct tags as indirect types, so
that if we later see a definition of the tag as a C++
record we can update the indirect slot and automatically
change all the existing references. */
it = (struct ieee_tag *) xmalloc (sizeof *it);
memset (it, 0, sizeof *it);
it->next = info->tags;
info->tags = it;
it->name = name;
it->slot = type;
 
type = debug_make_indirect_type (dhandle, &it->slot, name);
type = debug_tag_type (dhandle, name, type);
 
it->type = type;
}
if (type == NULL)
return FALSE;
}
 
info->types.types[typeindx].type = type;
info->types.types[typeindx].arg_slots = arg_slots;
info->types.types[typeindx].bitsize = type_bitsize;
 
/* We may have already allocated type as an indirect type pointing
to slot. It does no harm to replace the indirect type with the
real type. Filling in slot as well handles the indirect types
which are already hanging around. */
if (info->types.types[typeindx].pslot != NULL)
*info->types.types[typeindx].pslot = type;
 
return TRUE;
}
 
/* Parse an ATN record. */
 
static bfd_boolean
parse_ieee_atn (struct ieee_info *info, const bfd_byte **pp)
{
const bfd_byte *atn_start, *atn_code_start;
bfd_vma varindx;
struct ieee_var *pvar;
debug_type type;
bfd_vma atn_code;
void *dhandle;
bfd_vma v, v2, v3, v4, v5;
const char *name;
unsigned long namlen;
char *namcopy;
bfd_boolean present;
int blocktype;
 
atn_start = *pp;
 
if (! ieee_read_number (info, pp, &varindx)
|| ! ieee_read_type_index (info, pp, &type))
return FALSE;
 
atn_code_start = *pp;
 
if (! ieee_read_number (info, pp, &atn_code))
return FALSE;
 
if (varindx == 0)
{
pvar = NULL;
name = "";
namlen = 0;
}
else if (varindx < 32)
{
/* The MRI compiler reportedly sometimes emits variable lifetime
information for a register. We just ignore it. */
if (atn_code == 9)
return ieee_read_number (info, pp, &v);
 
ieee_error (info, atn_start, _("illegal variable index"));
return FALSE;
}
else
{
varindx -= 32;
if (varindx >= info->vars.alloc
|| info->vars.vars[varindx].name == NULL)
{
/* The MRI compiler or linker sometimes omits the NN record
for a pmisc record. */
if (atn_code == 62)
{
if (varindx >= info->vars.alloc)
{
unsigned int alloc;
 
alloc = info->vars.alloc;
if (alloc == 0)
alloc = 4;
while (varindx >= alloc)
alloc *= 2;
info->vars.vars = ((struct ieee_var *)
xrealloc (info->vars.vars,
(alloc
* sizeof *info->vars.vars)));
memset (info->vars.vars + info->vars.alloc, 0,
((alloc - info->vars.alloc)
* sizeof *info->vars.vars));
info->vars.alloc = alloc;
}
 
pvar = info->vars.vars + varindx;
pvar->name = "";
pvar->namlen = 0;
}
else
{
ieee_error (info, atn_start, _("undefined variable in ATN"));
return FALSE;
}
}
 
pvar = info->vars.vars + varindx;
 
pvar->type = type;
 
name = pvar->name;
namlen = pvar->namlen;
}
 
dhandle = info->dhandle;
 
/* If we are going to call debug_record_variable with a pointer
type, change the type to an indirect type so that we can later
change it to a reference type if we encounter a C++ pmisc 'R'
record. */
if (pvar != NULL
&& type != DEBUG_TYPE_NULL
&& debug_get_type_kind (dhandle, type) == DEBUG_KIND_POINTER)
{
switch (atn_code)
{
case 1:
case 2:
case 3:
case 5:
case 8:
case 10:
pvar->pslot = (debug_type *) xmalloc (sizeof *pvar->pslot);
*pvar->pslot = type;
type = debug_make_indirect_type (dhandle, pvar->pslot,
(const char *) NULL);
pvar->type = type;
break;
}
}
 
switch (atn_code)
{
default:
ieee_error (info, atn_code_start, _("unknown ATN type"));
return FALSE;
 
case 1:
/* Automatic variable. */
if (! ieee_read_number (info, pp, &v))
return FALSE;
namcopy = savestring (name, namlen);
if (type == NULL)
type = debug_make_void_type (dhandle);
if (pvar != NULL)
pvar->kind = IEEE_LOCAL;
return debug_record_variable (dhandle, namcopy, type, DEBUG_LOCAL, v);
 
case 2:
/* Register variable. */
if (! ieee_read_number (info, pp, &v))
return FALSE;
namcopy = savestring (name, namlen);
if (type == NULL)
type = debug_make_void_type (dhandle);
if (pvar != NULL)
pvar->kind = IEEE_LOCAL;
return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER,
ieee_regno_to_genreg (info->abfd, v));
 
case 3:
/* Static variable. */
if (! ieee_require_asn (info, pp, &v))
return FALSE;
namcopy = savestring (name, namlen);
if (type == NULL)
type = debug_make_void_type (dhandle);
if (info->blockstack.bsp <= info->blockstack.stack)
blocktype = 0;
else
blocktype = info->blockstack.bsp[-1].kind;
if (pvar != NULL)
{
if (blocktype == 4 || blocktype == 6)
pvar->kind = IEEE_LOCAL;
else
pvar->kind = IEEE_STATIC;
}
return debug_record_variable (dhandle, namcopy, type,
(blocktype == 4 || blocktype == 6
? DEBUG_LOCAL_STATIC
: DEBUG_STATIC),
v);
 
case 4:
/* External function. We don't currently record these. FIXME. */
if (pvar != NULL)
pvar->kind = IEEE_EXTERNAL;
return TRUE;
 
case 5:
/* External variable. We don't currently record these. FIXME. */
if (pvar != NULL)
pvar->kind = IEEE_EXTERNAL;
return TRUE;
 
case 7:
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_number (info, pp, &v2)
|| ! ieee_read_optional_number (info, pp, &v3, &present))
return FALSE;
if (present)
{
if (! ieee_read_optional_number (info, pp, &v4, &present))
return FALSE;
}
 
/* We just ignore the two optional fields in v3 and v4, since
they are not defined. */
 
if (! ieee_require_asn (info, pp, &v3))
return FALSE;
 
/* We have no way to record the column number. FIXME. */
 
return debug_record_line (dhandle, v, v3);
 
case 8:
/* Global variable. */
if (! ieee_require_asn (info, pp, &v))
return FALSE;
namcopy = savestring (name, namlen);
if (type == NULL)
type = debug_make_void_type (dhandle);
if (pvar != NULL)
pvar->kind = IEEE_GLOBAL;
return debug_record_variable (dhandle, namcopy, type, DEBUG_GLOBAL, v);
 
case 9:
/* Variable lifetime information. */
if (! ieee_read_number (info, pp, &v))
return FALSE;
 
/* We have no way to record this information. FIXME. */
return TRUE;
 
case 10:
/* Locked register. The spec says that there are two required
fields, but at least on occasion the MRI compiler only emits
one. */
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_optional_number (info, pp, &v2, &present))
return FALSE;
 
/* I think this means a variable that is both in a register and
a frame slot. We ignore the frame slot. FIXME. */
 
namcopy = savestring (name, namlen);
if (type == NULL)
type = debug_make_void_type (dhandle);
if (pvar != NULL)
pvar->kind = IEEE_LOCAL;
return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER, v);
 
case 11:
/* Reserved for FORTRAN common. */
ieee_error (info, atn_code_start, _("unsupported ATN11"));
 
/* Return TRUE to keep going. */
return TRUE;
 
case 12:
/* Based variable. */
v3 = 0;
v4 = 0x80;
v5 = 0;
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_number (info, pp, &v2)
|| ! ieee_read_optional_number (info, pp, &v3, &present))
return FALSE;
if (present)
{
if (! ieee_read_optional_number (info, pp, &v4, &present))
return FALSE;
if (present)
{
if (! ieee_read_optional_number (info, pp, &v5, &present))
return FALSE;
}
}
 
/* We have no way to record this information. FIXME. */
 
ieee_error (info, atn_code_start, _("unsupported ATN12"));
 
/* Return TRUE to keep going. */
return TRUE;
 
case 16:
/* Constant. The description of this that I have is ambiguous,
so I'm not going to try to implement it. */
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_optional_number (info, pp, &v2, &present))
return FALSE;
if (present)
{
if (! ieee_read_optional_number (info, pp, &v2, &present))
return FALSE;
if (present)
{
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
}
}
 
if ((ieee_record_enum_type) **pp == ieee_e2_first_byte_enum)
{
if (! ieee_require_asn (info, pp, &v3))
return FALSE;
}
 
return TRUE;
 
case 19:
/* Static variable from assembler. */
v2 = 0;
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_optional_number (info, pp, &v2, &present)
|| ! ieee_require_asn (info, pp, &v3))
return FALSE;
namcopy = savestring (name, namlen);
/* We don't really handle this correctly. FIXME. */
return debug_record_variable (dhandle, namcopy,
debug_make_void_type (dhandle),
v2 != 0 ? DEBUG_GLOBAL : DEBUG_STATIC,
v3);
 
case 62:
/* Procedure miscellaneous information. */
case 63:
/* Variable miscellaneous information. */
case 64:
/* Module miscellaneous information. */
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_number (info, pp, &v2)
|| ! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
 
if (atn_code == 62 && v == 80)
{
if (present)
{
ieee_error (info, atn_code_start,
_("unexpected string in C++ misc"));
return FALSE;
}
return ieee_read_cxx_misc (info, pp, v2);
}
 
/* We just ignore all of this stuff. FIXME. */
 
for (; v2 > 0; --v2)
{
switch ((ieee_record_enum_type) **pp)
{
default:
ieee_error (info, *pp, _("bad misc record"));
return FALSE;
 
case ieee_at_record_enum:
if (! ieee_require_atn65 (info, pp, &name, &namlen))
return FALSE;
break;
 
case ieee_e2_first_byte_enum:
if (! ieee_require_asn (info, pp, &v3))
return FALSE;
break;
}
}
 
return TRUE;
}
 
/*NOTREACHED*/
}
 
/* Handle C++ debugging miscellaneous records. This is called for
procedure miscellaneous records of type 80. */
 
static bfd_boolean
ieee_read_cxx_misc (struct ieee_info *info, const bfd_byte **pp,
unsigned long count)
{
const bfd_byte *start;
bfd_vma category;
 
start = *pp;
 
/* Get the category of C++ misc record. */
if (! ieee_require_asn (info, pp, &category))
return FALSE;
--count;
 
switch (category)
{
default:
ieee_error (info, start, _("unrecognized C++ misc record"));
return FALSE;
 
case 'T':
if (! ieee_read_cxx_class (info, pp, count))
return FALSE;
break;
 
case 'M':
{
bfd_vma flags;
const char *name;
unsigned long namlen;
 
/* The IEEE spec indicates that the 'M' record only has a
flags field. The MRI compiler also emits the name of the
function. */
 
if (! ieee_require_asn (info, pp, &flags))
return FALSE;
if (*pp < info->pend
&& (ieee_record_enum_type) **pp == ieee_at_record_enum)
{
if (! ieee_require_atn65 (info, pp, &name, &namlen))
return FALSE;
}
 
/* This is emitted for method functions, but I don't think we
care very much. It might help if it told us useful
information like the class with which this function is
associated, but it doesn't, so it isn't helpful. */
}
break;
 
case 'B':
if (! ieee_read_cxx_defaults (info, pp, count))
return FALSE;
break;
 
case 'z':
{
const char *name, *mangled, *cxx_class;
unsigned long namlen, mangledlen, classlen;
bfd_vma control;
 
/* Pointer to member. */
 
if (! ieee_require_atn65 (info, pp, &name, &namlen)
|| ! ieee_require_atn65 (info, pp, &mangled, &mangledlen)
|| ! ieee_require_atn65 (info, pp, &cxx_class, &classlen)
|| ! ieee_require_asn (info, pp, &control))
return FALSE;
 
/* FIXME: We should now track down name and change its type. */
}
break;
 
case 'R':
if (! ieee_read_reference (info, pp))
return FALSE;
break;
}
 
return TRUE;
}
 
/* Read a C++ class definition. This is a pmisc type 80 record of
category 'T'. */
 
static bfd_boolean
ieee_read_cxx_class (struct ieee_info *info, const bfd_byte **pp,
unsigned long count)
{
const bfd_byte *start;
bfd_vma cxx_class;
const char *tag;
unsigned long taglen;
struct ieee_tag *it;
void *dhandle;
debug_field *fields;
unsigned int field_count, field_alloc;
debug_baseclass *baseclasses;
unsigned int baseclasses_count, baseclasses_alloc;
const debug_field *structfields;
struct ieee_method
{
const char *name;
unsigned long namlen;
debug_method_variant *variants;
unsigned count;
unsigned int alloc;
} *methods;
unsigned int methods_count, methods_alloc;
debug_type vptrbase;
bfd_boolean ownvptr;
debug_method *dmethods;
 
start = *pp;
 
if (! ieee_require_asn (info, pp, &cxx_class))
return FALSE;
--count;
 
if (! ieee_require_atn65 (info, pp, &tag, &taglen))
return FALSE;
--count;
 
/* Find the C struct with this name. */
for (it = info->tags; it != NULL; it = it->next)
if (it->name[0] == tag[0]
&& strncmp (it->name, tag, taglen) == 0
&& strlen (it->name) == taglen)
break;
if (it == NULL)
{
ieee_error (info, start, _("undefined C++ object"));
return FALSE;
}
 
dhandle = info->dhandle;
 
fields = NULL;
field_count = 0;
field_alloc = 0;
baseclasses = NULL;
baseclasses_count = 0;
baseclasses_alloc = 0;
methods = NULL;
methods_count = 0;
methods_alloc = 0;
vptrbase = DEBUG_TYPE_NULL;
ownvptr = FALSE;
 
structfields = debug_get_fields (dhandle, it->type);
 
while (count > 0)
{
bfd_vma id;
const bfd_byte *spec_start;
 
spec_start = *pp;
 
if (! ieee_require_asn (info, pp, &id))
return FALSE;
--count;
 
switch (id)
{
default:
ieee_error (info, spec_start, _("unrecognized C++ object spec"));
return FALSE;
 
case 'b':
{
bfd_vma flags, cinline;
const char *base, *fieldname;
unsigned long baselen, fieldlen;
char *basecopy;
debug_type basetype;
bfd_vma bitpos;
bfd_boolean virtualp;
enum debug_visibility visibility;
debug_baseclass baseclass;
 
/* This represents a base or friend class. */
 
if (! ieee_require_asn (info, pp, &flags)
|| ! ieee_require_atn65 (info, pp, &base, &baselen)
|| ! ieee_require_asn (info, pp, &cinline)
|| ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen))
return FALSE;
count -= 4;
 
/* We have no way of recording friend information, so we
just ignore it. */
if ((flags & BASEFLAGS_FRIEND) != 0)
break;
 
/* I assume that either all of the members of the
baseclass are included in the object, starting at the
beginning of the object, or that none of them are
included. */
 
if ((fieldlen == 0) == (cinline == 0))
{
ieee_error (info, start, _("unsupported C++ object type"));
return FALSE;
}
 
basecopy = savestring (base, baselen);
basetype = debug_find_tagged_type (dhandle, basecopy,
DEBUG_KIND_ILLEGAL);
free (basecopy);
if (basetype == DEBUG_TYPE_NULL)
{
ieee_error (info, start, _("C++ base class not defined"));
return FALSE;
}
 
if (fieldlen == 0)
bitpos = 0;
else
{
const debug_field *pf;
 
if (structfields == NULL)
{
ieee_error (info, start, _("C++ object has no fields"));
return FALSE;
}
 
for (pf = structfields; *pf != DEBUG_FIELD_NULL; pf++)
{
const char *fname;
 
fname = debug_get_field_name (dhandle, *pf);
if (fname == NULL)
return FALSE;
if (fname[0] == fieldname[0]
&& strncmp (fname, fieldname, fieldlen) == 0
&& strlen (fname) == fieldlen)
break;
}
if (*pf == DEBUG_FIELD_NULL)
{
ieee_error (info, start,
_("C++ base class not found in container"));
return FALSE;
}
 
bitpos = debug_get_field_bitpos (dhandle, *pf);
}
 
if ((flags & BASEFLAGS_VIRTUAL) != 0)
virtualp = TRUE;
else
virtualp = FALSE;
if ((flags & BASEFLAGS_PRIVATE) != 0)
visibility = DEBUG_VISIBILITY_PRIVATE;
else
visibility = DEBUG_VISIBILITY_PUBLIC;
 
baseclass = debug_make_baseclass (dhandle, basetype, bitpos,
virtualp, visibility);
if (baseclass == DEBUG_BASECLASS_NULL)
return FALSE;
 
if (baseclasses_count + 1 >= baseclasses_alloc)
{
baseclasses_alloc += 10;
baseclasses = ((debug_baseclass *)
xrealloc (baseclasses,
(baseclasses_alloc
* sizeof *baseclasses)));
}
 
baseclasses[baseclasses_count] = baseclass;
++baseclasses_count;
baseclasses[baseclasses_count] = DEBUG_BASECLASS_NULL;
}
break;
 
case 'd':
{
bfd_vma flags;
const char *fieldname, *mangledname;
unsigned long fieldlen, mangledlen;
char *fieldcopy;
bfd_boolean staticp;
debug_type ftype;
const debug_field *pf = NULL;
enum debug_visibility visibility;
debug_field field;
 
/* This represents a data member. */
 
if (! ieee_require_asn (info, pp, &flags)
|| ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen)
|| ! ieee_require_atn65 (info, pp, &mangledname, &mangledlen))
return FALSE;
count -= 3;
 
fieldcopy = savestring (fieldname, fieldlen);
 
staticp = (flags & CXXFLAGS_STATIC) != 0 ? TRUE : FALSE;
 
if (staticp)
{
struct ieee_var *pv, *pvend;
 
/* See if we can find a definition for this variable. */
pv = info->vars.vars;
pvend = pv + info->vars.alloc;
for (; pv < pvend; pv++)
if (pv->namlen == mangledlen
&& strncmp (pv->name, mangledname, mangledlen) == 0)
break;
if (pv < pvend)
ftype = pv->type;
else
{
/* This can happen if the variable is never used. */
ftype = ieee_builtin_type (info, start,
(unsigned int) builtin_void);
}
}
else
{
unsigned int findx;
 
if (structfields == NULL)
{
ieee_error (info, start, _("C++ object has no fields"));
return FALSE;
}
 
for (pf = structfields, findx = 0;
*pf != DEBUG_FIELD_NULL;
pf++, findx++)
{
const char *fname;
 
fname = debug_get_field_name (dhandle, *pf);
if (fname == NULL)
return FALSE;
if (fname[0] == mangledname[0]
&& strncmp (fname, mangledname, mangledlen) == 0
&& strlen (fname) == mangledlen)
break;
}
if (*pf == DEBUG_FIELD_NULL)
{
ieee_error (info, start,
_("C++ data member not found in container"));
return FALSE;
}
 
ftype = debug_get_field_type (dhandle, *pf);
 
if (debug_get_type_kind (dhandle, ftype) == DEBUG_KIND_POINTER)
{
/* We might need to convert this field into a
reference type later on, so make it an indirect
type. */
if (it->fslots == NULL)
{
unsigned int fcnt;
const debug_field *pfcnt;
 
fcnt = 0;
for (pfcnt = structfields;
*pfcnt != DEBUG_FIELD_NULL;
pfcnt++)
++fcnt;
it->fslots = ((debug_type *)
xmalloc (fcnt * sizeof *it->fslots));
memset (it->fslots, 0,
fcnt * sizeof *it->fslots);
}
 
if (ftype == DEBUG_TYPE_NULL)
return FALSE;
it->fslots[findx] = ftype;
ftype = debug_make_indirect_type (dhandle,
it->fslots + findx,
(const char *) NULL);
}
}
if (ftype == DEBUG_TYPE_NULL)
return FALSE;
 
switch (flags & CXXFLAGS_VISIBILITY)
{
default:
ieee_error (info, start, _("unknown C++ visibility"));
return FALSE;
 
case CXXFLAGS_VISIBILITY_PUBLIC:
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
 
case CXXFLAGS_VISIBILITY_PRIVATE:
visibility = DEBUG_VISIBILITY_PRIVATE;
break;
 
case CXXFLAGS_VISIBILITY_PROTECTED:
visibility = DEBUG_VISIBILITY_PROTECTED;
break;
}
 
if (staticp)
{
char *mangledcopy;
 
mangledcopy = savestring (mangledname, mangledlen);
 
field = debug_make_static_member (dhandle, fieldcopy,
ftype, mangledcopy,
visibility);
}
else
{
bfd_vma bitpos, bitsize;
 
bitpos = debug_get_field_bitpos (dhandle, *pf);
bitsize = debug_get_field_bitsize (dhandle, *pf);
if (bitpos == (bfd_vma) -1 || bitsize == (bfd_vma) -1)
{
ieee_error (info, start, _("bad C++ field bit pos or size"));
return FALSE;
}
field = debug_make_field (dhandle, fieldcopy, ftype, bitpos,
bitsize, visibility);
}
 
if (field == DEBUG_FIELD_NULL)
return FALSE;
 
if (field_count + 1 >= field_alloc)
{
field_alloc += 10;
fields = ((debug_field *)
xrealloc (fields, field_alloc * sizeof *fields));
}
 
fields[field_count] = field;
++field_count;
fields[field_count] = DEBUG_FIELD_NULL;
}
break;
 
case 'm':
case 'v':
{
bfd_vma flags, voffset, control;
const char *name, *mangled;
unsigned long namlen, mangledlen;
struct ieee_var *pv, *pvend;
debug_type type;
enum debug_visibility visibility;
bfd_boolean constp, volatilep;
char *mangledcopy;
debug_method_variant mv;
struct ieee_method *meth;
unsigned int im;
 
if (! ieee_require_asn (info, pp, &flags)
|| ! ieee_require_atn65 (info, pp, &name, &namlen)
|| ! ieee_require_atn65 (info, pp, &mangled, &mangledlen))
return FALSE;
count -= 3;
if (id != 'v')
voffset = 0;
else
{
if (! ieee_require_asn (info, pp, &voffset))
return FALSE;
--count;
}
if (! ieee_require_asn (info, pp, &control))
return FALSE;
--count;
 
/* We just ignore the control information. */
 
/* We have no way to represent friend information, so we
just ignore it. */
if ((flags & CXXFLAGS_FRIEND) != 0)
break;
 
/* We should already have seen a type for the function. */
pv = info->vars.vars;
pvend = pv + info->vars.alloc;
for (; pv < pvend; pv++)
if (pv->namlen == mangledlen
&& strncmp (pv->name, mangled, mangledlen) == 0)
break;
 
if (pv >= pvend)
{
/* We won't have type information for this function if
it is not included in this file. We don't try to
handle this case. FIXME. */
type = (debug_make_function_type
(dhandle,
ieee_builtin_type (info, start,
(unsigned int) builtin_void),
(debug_type *) NULL,
FALSE));
}
else
{
debug_type return_type;
const debug_type *arg_types;
bfd_boolean varargs;
 
if (debug_get_type_kind (dhandle, pv->type)
!= DEBUG_KIND_FUNCTION)
{
ieee_error (info, start,
_("bad type for C++ method function"));
return FALSE;
}
 
return_type = debug_get_return_type (dhandle, pv->type);
arg_types = debug_get_parameter_types (dhandle, pv->type,
&varargs);
if (return_type == DEBUG_TYPE_NULL || arg_types == NULL)
{
ieee_error (info, start,
_("no type information for C++ method function"));
return FALSE;
}
 
type = debug_make_method_type (dhandle, return_type, it->type,
(debug_type *) arg_types,
varargs);
}
if (type == DEBUG_TYPE_NULL)
return FALSE;
 
switch (flags & CXXFLAGS_VISIBILITY)
{
default:
ieee_error (info, start, _("unknown C++ visibility"));
return FALSE;
 
case CXXFLAGS_VISIBILITY_PUBLIC:
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
 
case CXXFLAGS_VISIBILITY_PRIVATE:
visibility = DEBUG_VISIBILITY_PRIVATE;
break;
 
case CXXFLAGS_VISIBILITY_PROTECTED:
visibility = DEBUG_VISIBILITY_PROTECTED;
break;
}
 
constp = (flags & CXXFLAGS_CONST) != 0 ? TRUE : FALSE;
volatilep = (flags & CXXFLAGS_VOLATILE) != 0 ? TRUE : FALSE;
 
mangledcopy = savestring (mangled, mangledlen);
 
if ((flags & CXXFLAGS_STATIC) != 0)
{
if (id == 'v')
{
ieee_error (info, start, _("C++ static virtual method"));
return FALSE;
}
mv = debug_make_static_method_variant (dhandle, mangledcopy,
type, visibility,
constp, volatilep);
}
else
{
debug_type vcontext;
 
if (id != 'v')
vcontext = DEBUG_TYPE_NULL;
else
{
/* FIXME: How can we calculate this correctly? */
vcontext = it->type;
}
mv = debug_make_method_variant (dhandle, mangledcopy, type,
visibility, constp,
volatilep, voffset,
vcontext);
}
if (mv == DEBUG_METHOD_VARIANT_NULL)
return FALSE;
 
for (meth = methods, im = 0; im < methods_count; meth++, im++)
if (meth->namlen == namlen
&& strncmp (meth->name, name, namlen) == 0)
break;
if (im >= methods_count)
{
if (methods_count >= methods_alloc)
{
methods_alloc += 10;
methods = ((struct ieee_method *)
xrealloc (methods,
methods_alloc * sizeof *methods));
}
methods[methods_count].name = name;
methods[methods_count].namlen = namlen;
methods[methods_count].variants = NULL;
methods[methods_count].count = 0;
methods[methods_count].alloc = 0;
meth = methods + methods_count;
++methods_count;
}
 
if (meth->count + 1 >= meth->alloc)
{
meth->alloc += 10;
meth->variants = ((debug_method_variant *)
xrealloc (meth->variants,
(meth->alloc
* sizeof *meth->variants)));
}
 
meth->variants[meth->count] = mv;
++meth->count;
meth->variants[meth->count] = DEBUG_METHOD_VARIANT_NULL;
}
break;
 
case 'o':
{
bfd_vma spec;
 
/* We have no way to store this information, so we just
ignore it. */
if (! ieee_require_asn (info, pp, &spec))
return FALSE;
--count;
if ((spec & 4) != 0)
{
const char *filename;
unsigned long filenamlen;
bfd_vma lineno;
 
if (! ieee_require_atn65 (info, pp, &filename, &filenamlen)
|| ! ieee_require_asn (info, pp, &lineno))
return FALSE;
count -= 2;
}
else if ((spec & 8) != 0)
{
const char *mangled;
unsigned long mangledlen;
 
if (! ieee_require_atn65 (info, pp, &mangled, &mangledlen))
return FALSE;
--count;
}
else
{
ieee_error (info, start,
_("unrecognized C++ object overhead spec"));
return FALSE;
}
}
break;
 
case 'z':
{
const char *vname, *base;
unsigned long vnamelen, baselen;
bfd_vma vsize, control;
 
/* A virtual table pointer. */
 
if (! ieee_require_atn65 (info, pp, &vname, &vnamelen)
|| ! ieee_require_asn (info, pp, &vsize)
|| ! ieee_require_atn65 (info, pp, &base, &baselen)
|| ! ieee_require_asn (info, pp, &control))
return FALSE;
count -= 4;
 
/* We just ignore the control number. We don't care what
the virtual table name is. We have no way to store the
virtual table size, and I don't think we care anyhow. */
 
/* FIXME: We can't handle multiple virtual table pointers. */
 
if (baselen == 0)
ownvptr = TRUE;
else
{
char *basecopy;
 
basecopy = savestring (base, baselen);
vptrbase = debug_find_tagged_type (dhandle, basecopy,
DEBUG_KIND_ILLEGAL);
free (basecopy);
if (vptrbase == DEBUG_TYPE_NULL)
{
ieee_error (info, start, _("undefined C++ vtable"));
return FALSE;
}
}
}
break;
}
}
 
/* Now that we have seen all the method variants, we can call
debug_make_method for each one. */
 
if (methods_count == 0)
dmethods = NULL;
else
{
unsigned int i;
 
dmethods = ((debug_method *)
xmalloc ((methods_count + 1) * sizeof *dmethods));
for (i = 0; i < methods_count; i++)
{
char *namcopy;
 
namcopy = savestring (methods[i].name, methods[i].namlen);
dmethods[i] = debug_make_method (dhandle, namcopy,
methods[i].variants);
if (dmethods[i] == DEBUG_METHOD_NULL)
return FALSE;
}
dmethods[i] = DEBUG_METHOD_NULL;
free (methods);
}
 
/* The struct type was created as an indirect type pointing at
it->slot. We update it->slot to automatically update all
references to this struct. */
it->slot = debug_make_object_type (dhandle,
cxx_class != 'u',
debug_get_type_size (dhandle,
it->slot),
fields, baseclasses, dmethods,
vptrbase, ownvptr);
if (it->slot == DEBUG_TYPE_NULL)
return FALSE;
 
return TRUE;
}
 
/* Read C++ default argument value and reference type information. */
 
static bfd_boolean
ieee_read_cxx_defaults (struct ieee_info *info, const bfd_byte **pp,
unsigned long count)
{
const bfd_byte *start;
const char *fnname;
unsigned long fnlen;
bfd_vma defcount;
 
start = *pp;
 
/* Giving the function name before the argument count is an addendum
to the spec. The function name is demangled, though, so this
record must always refer to the current function. */
 
if (info->blockstack.bsp <= info->blockstack.stack
|| info->blockstack.bsp[-1].fnindx == (unsigned int) -1)
{
ieee_error (info, start, _("C++ default values not in a function"));
return FALSE;
}
 
if (! ieee_require_atn65 (info, pp, &fnname, &fnlen)
|| ! ieee_require_asn (info, pp, &defcount))
return FALSE;
count -= 2;
 
while (defcount-- > 0)
{
bfd_vma type, val;
const char *strval;
unsigned long strvallen;
 
if (! ieee_require_asn (info, pp, &type))
return FALSE;
--count;
 
switch (type)
{
case 0:
case 4:
break;
 
case 1:
case 2:
if (! ieee_require_asn (info, pp, &val))
return FALSE;
--count;
break;
 
case 3:
case 7:
if (! ieee_require_atn65 (info, pp, &strval, &strvallen))
return FALSE;
--count;
break;
 
default:
ieee_error (info, start, _("unrecognized C++ default type"));
return FALSE;
}
 
/* We have no way to record the default argument values, so we
just ignore them. FIXME. */
}
 
/* Any remaining arguments are indices of parameters that are really
reference type. */
if (count > 0)
{
void *dhandle;
debug_type *arg_slots;
 
dhandle = info->dhandle;
arg_slots = info->types.types[info->blockstack.bsp[-1].fnindx].arg_slots;
while (count-- > 0)
{
bfd_vma indx;
debug_type target;
 
if (! ieee_require_asn (info, pp, &indx))
return FALSE;
/* The index is 1 based. */
--indx;
if (arg_slots == NULL
|| arg_slots[indx] == DEBUG_TYPE_NULL
|| (debug_get_type_kind (dhandle, arg_slots[indx])
!= DEBUG_KIND_POINTER))
{
ieee_error (info, start, _("reference parameter is not a pointer"));
return FALSE;
}
 
target = debug_get_target_type (dhandle, arg_slots[indx]);
arg_slots[indx] = debug_make_reference_type (dhandle, target);
if (arg_slots[indx] == DEBUG_TYPE_NULL)
return FALSE;
}
}
 
return TRUE;
}
 
/* Read a C++ reference definition. */
 
static bfd_boolean
ieee_read_reference (struct ieee_info *info, const bfd_byte **pp)
{
const bfd_byte *start;
bfd_vma flags;
const char *cxx_class, *name;
unsigned long classlen, namlen;
debug_type *pslot;
debug_type target;
 
start = *pp;
 
if (! ieee_require_asn (info, pp, &flags))
return FALSE;
 
/* Giving the class name before the member name is in an addendum to
the spec. */
if (flags == 3)
{
if (! ieee_require_atn65 (info, pp, &cxx_class, &classlen))
return FALSE;
}
 
if (! ieee_require_atn65 (info, pp, &name, &namlen))
return FALSE;
 
pslot = NULL;
if (flags != 3)
{
int pass;
 
/* We search from the last variable indices to the first in
hopes of finding local variables correctly. We search the
local variables on the first pass, and the global variables
on the second. FIXME: This probably won't work in all cases.
On the other hand, I don't know what will. */
for (pass = 0; pass < 2; pass++)
{
struct ieee_vars *vars;
int i;
struct ieee_var *pv = NULL;
 
if (pass == 0)
vars = &info->vars;
else
{
vars = info->global_vars;
if (vars == NULL)
break;
}
 
for (i = (int) vars->alloc - 1; i >= 0; i--)
{
bfd_boolean found;
 
pv = vars->vars + i;
 
if (pv->pslot == NULL
|| pv->namlen != namlen
|| strncmp (pv->name, name, namlen) != 0)
continue;
 
found = FALSE;
switch (flags)
{
default:
ieee_error (info, start,
_("unrecognized C++ reference type"));
return FALSE;
 
case 0:
/* Global variable or function. */
if (pv->kind == IEEE_GLOBAL
|| pv->kind == IEEE_EXTERNAL
|| pv->kind == IEEE_FUNCTION)
found = TRUE;
break;
 
case 1:
/* Global static variable or function. */
if (pv->kind == IEEE_STATIC
|| pv->kind == IEEE_FUNCTION)
found = TRUE;
break;
 
case 2:
/* Local variable. */
if (pv->kind == IEEE_LOCAL)
found = TRUE;
break;
}
 
if (found)
break;
}
 
if (i >= 0)
{
pslot = pv->pslot;
break;
}
}
}
else
{
struct ieee_tag *it;
 
for (it = info->tags; it != NULL; it = it->next)
{
if (it->name[0] == cxx_class[0]
&& strncmp (it->name, cxx_class, classlen) == 0
&& strlen (it->name) == classlen)
{
if (it->fslots != NULL)
{
const debug_field *pf;
unsigned int findx;
 
pf = debug_get_fields (info->dhandle, it->type);
if (pf == NULL)
{
ieee_error (info, start,
"C++ reference in class with no fields");
return FALSE;
}
 
for (findx = 0; *pf != DEBUG_FIELD_NULL; pf++, findx++)
{
const char *fname;
 
fname = debug_get_field_name (info->dhandle, *pf);
if (fname == NULL)
return FALSE;
if (strncmp (fname, name, namlen) == 0
&& strlen (fname) == namlen)
{
pslot = it->fslots + findx;
break;
}
}
}
 
break;
}
}
}
 
if (pslot == NULL)
{
ieee_error (info, start, _("C++ reference not found"));
return FALSE;
}
 
/* We allocated the type of the object as an indirect type pointing
to *pslot, which we can now update to be a reference type. */
if (debug_get_type_kind (info->dhandle, *pslot) != DEBUG_KIND_POINTER)
{
ieee_error (info, start, _("C++ reference is not pointer"));
return FALSE;
}
 
target = debug_get_target_type (info->dhandle, *pslot);
*pslot = debug_make_reference_type (info->dhandle, target);
if (*pslot == DEBUG_TYPE_NULL)
return FALSE;
 
return TRUE;
}
 
/* Require an ASN record. */
 
static bfd_boolean
ieee_require_asn (struct ieee_info *info, const bfd_byte **pp, bfd_vma *pv)
{
const bfd_byte *start;
ieee_record_enum_type c;
bfd_vma varindx;
 
start = *pp;
 
c = (ieee_record_enum_type) **pp;
if (c != ieee_e2_first_byte_enum)
{
ieee_error (info, start, _("missing required ASN"));
return FALSE;
}
++*pp;
 
c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp);
if (c != ieee_asn_record_enum)
{
ieee_error (info, start, _("missing required ASN"));
return FALSE;
}
++*pp;
 
/* Just ignore the variable index. */
if (! ieee_read_number (info, pp, &varindx))
return FALSE;
 
return ieee_read_expression (info, pp, pv);
}
 
/* Require an ATN65 record. */
 
static bfd_boolean
ieee_require_atn65 (struct ieee_info *info, const bfd_byte **pp,
const char **pname, unsigned long *pnamlen)
{
const bfd_byte *start;
ieee_record_enum_type c;
bfd_vma name_indx, type_indx, atn_code;
 
start = *pp;
 
c = (ieee_record_enum_type) **pp;
if (c != ieee_at_record_enum)
{
ieee_error (info, start, _("missing required ATN65"));
return FALSE;
}
++*pp;
 
c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp);
if (c != ieee_atn_record_enum)
{
ieee_error (info, start, _("missing required ATN65"));
return FALSE;
}
++*pp;
 
if (! ieee_read_number (info, pp, &name_indx)
|| ! ieee_read_number (info, pp, &type_indx)
|| ! ieee_read_number (info, pp, &atn_code))
return FALSE;
 
/* Just ignore name_indx. */
 
if (type_indx != 0 || atn_code != 65)
{
ieee_error (info, start, _("bad ATN65 record"));
return FALSE;
}
 
return ieee_read_id (info, pp, pname, pnamlen);
}
/* Convert a register number in IEEE debugging information into a
generic register number. */
 
static int
ieee_regno_to_genreg (bfd *abfd, int r)
{
switch (bfd_get_arch (abfd))
{
case bfd_arch_m68k:
/* For some reasons stabs adds 2 to the floating point register
numbers. */
if (r >= 16)
r += 2;
break;
 
case bfd_arch_i960:
/* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and
32 to 35 for fp0 to fp3. */
--r;
break;
 
default:
break;
}
 
return r;
}
 
/* Convert a generic register number to an IEEE specific one. */
 
static int
ieee_genreg_to_regno (bfd *abfd, int r)
{
switch (bfd_get_arch (abfd))
{
case bfd_arch_m68k:
/* For some reason stabs add 2 to the floating point register
numbers. */
if (r >= 18)
r -= 2;
break;
 
case bfd_arch_i960:
/* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and
32 to 35 for fp0 to fp3. */
++r;
break;
 
default:
break;
}
 
return r;
}
/* These routines build IEEE debugging information out of the generic
debugging information. */
 
/* We build the IEEE debugging information byte by byte. Rather than
waste time copying data around, we use a linked list of buffers to
hold the data. */
 
#define IEEE_BUFSIZE (490)
 
struct ieee_buf
{
/* Next buffer. */
struct ieee_buf *next;
/* Number of data bytes in this buffer. */
unsigned int c;
/* Bytes. */
bfd_byte buf[IEEE_BUFSIZE];
};
 
/* A list of buffers. */
 
struct ieee_buflist
{
/* Head of list. */
struct ieee_buf *head;
/* Tail--last buffer on list. */
struct ieee_buf *tail;
};
 
/* In order to generate the BB11 blocks required by the HP emulator,
we keep track of ranges of addresses which correspond to a given
compilation unit. */
 
struct ieee_range
{
/* Next range. */
struct ieee_range *next;
/* Low address. */
bfd_vma low;
/* High address. */
bfd_vma high;
};
 
/* This structure holds information for a class on the type stack. */
 
struct ieee_type_class
{
/* The name index in the debugging information. */
unsigned int indx;
/* The pmisc records for the class. */
struct ieee_buflist pmiscbuf;
/* The number of pmisc records. */
unsigned int pmisccount;
/* The name of the class holding the virtual table, if not this
class. */
const char *vclass;
/* Whether this class holds its own virtual table. */
bfd_boolean ownvptr;
/* The largest virtual table offset seen so far. */
bfd_vma voffset;
/* The current method. */
const char *method;
/* Additional pmisc records used to record fields of reference type. */
struct ieee_buflist refs;
};
 
/* This is how we store types for the writing routines. Most types
are simply represented by a type index. */
 
struct ieee_write_type
{
/* Type index. */
unsigned int indx;
/* The size of the type, if known. */
unsigned int size;
/* The name of the type, if any. */
const char *name;
/* If this is a function or method type, we build the type here, and
only add it to the output buffers if we need it. */
struct ieee_buflist fndef;
/* If this is a struct, this is where the struct definition is
built. */
struct ieee_buflist strdef;
/* If this is a class, this is where the class information is built. */
struct ieee_type_class *classdef;
/* Whether the type is unsigned. */
unsigned int unsignedp : 1;
/* Whether this is a reference type. */
unsigned int referencep : 1;
/* Whether this is in the local type block. */
unsigned int localp : 1;
/* Whether this is a duplicate struct definition which we are
ignoring. */
unsigned int ignorep : 1;
};
 
/* This is the type stack used by the debug writing routines. FIXME:
We could generate more efficient output if we remembered when we
have output a particular type before. */
 
struct ieee_type_stack
{
/* Next entry on stack. */
struct ieee_type_stack *next;
/* Type information. */
struct ieee_write_type type;
};
 
/* This is a list of associations between a name and some types.
These are used for typedefs and tags. */
 
struct ieee_name_type
{
/* Next type for this name. */
struct ieee_name_type *next;
/* ID number. For a typedef, this is the index of the type to which
this name is typedefed. */
unsigned int id;
/* Type. */
struct ieee_write_type type;
/* If this is a tag which has not yet been defined, this is the
kind. If the tag has been defined, this is DEBUG_KIND_ILLEGAL. */
enum debug_type_kind kind;
};
 
/* We use a hash table to associate names and types. */
 
struct ieee_name_type_hash_table
{
struct bfd_hash_table root;
};
 
struct ieee_name_type_hash_entry
{
struct bfd_hash_entry root;
/* Information for this name. */
struct ieee_name_type *types;
};
 
/* This is a list of enums. */
 
struct ieee_defined_enum
{
/* Next enum. */
struct ieee_defined_enum *next;
/* Type index. */
unsigned int indx;
/* Whether this enum has been defined. */
bfd_boolean defined;
/* Tag. */
const char *tag;
/* Names. */
const char **names;
/* Values. */
bfd_signed_vma *vals;
};
 
/* We keep a list of modified versions of types, so that we don't
output them more than once. */
 
struct ieee_modified_type
{
/* Pointer to this type. */
unsigned int pointer;
/* Function with unknown arguments returning this type. */
unsigned int function;
/* Const version of this type. */
unsigned int const_qualified;
/* Volatile version of this type. */
unsigned int volatile_qualified;
/* List of arrays of this type of various bounds. */
struct ieee_modified_array_type *arrays;
};
 
/* A list of arrays bounds. */
 
struct ieee_modified_array_type
{
/* Next array bounds. */
struct ieee_modified_array_type *next;
/* Type index with these bounds. */
unsigned int indx;
/* Low bound. */
bfd_signed_vma low;
/* High bound. */
bfd_signed_vma high;
};
 
/* This is a list of pending function parameter information. We don't
output them until we see the first block. */
 
struct ieee_pending_parm
{
/* Next pending parameter. */
struct ieee_pending_parm *next;
/* Name. */
const char *name;
/* Type index. */
unsigned int type;
/* Whether the type is a reference. */
bfd_boolean referencep;
/* Kind. */
enum debug_parm_kind kind;
/* Value. */
bfd_vma val;
};
 
/* This is the handle passed down by debug_write. */
 
struct ieee_handle
{
/* BFD we are writing to. */
bfd *abfd;
/* Whether we got an error in a subroutine called via traverse or
map_over_sections. */
bfd_boolean error;
/* Current data buffer list. */
struct ieee_buflist *current;
/* Current data buffer. */
struct ieee_buf *curbuf;
/* Filename of current compilation unit. */
const char *filename;
/* Module name of current compilation unit. */
const char *modname;
/* List of buffer for global types. */
struct ieee_buflist global_types;
/* List of finished data buffers. */
struct ieee_buflist data;
/* List of buffers for typedefs in the current compilation unit. */
struct ieee_buflist types;
/* List of buffers for variables and functions in the current
compilation unit. */
struct ieee_buflist vars;
/* List of buffers for C++ class definitions in the current
compilation unit. */
struct ieee_buflist cxx;
/* List of buffers for line numbers in the current compilation unit. */
struct ieee_buflist linenos;
/* Ranges for the current compilation unit. */
struct ieee_range *ranges;
/* Ranges for all debugging information. */
struct ieee_range *global_ranges;
/* Nested pending ranges. */
struct ieee_range *pending_ranges;
/* Type stack. */
struct ieee_type_stack *type_stack;
/* Next unallocated type index. */
unsigned int type_indx;
/* Next unallocated name index. */
unsigned int name_indx;
/* Typedefs. */
struct ieee_name_type_hash_table typedefs;
/* Tags. */
struct ieee_name_type_hash_table tags;
/* Enums. */
struct ieee_defined_enum *enums;
/* Modified versions of types. */
struct ieee_modified_type *modified;
/* Number of entries allocated in modified. */
unsigned int modified_alloc;
/* 4 byte complex type. */
unsigned int complex_float_index;
/* 8 byte complex type. */
unsigned int complex_double_index;
/* The depth of block nesting. This is 0 outside a function, and 1
just after start_function is called. */
unsigned int block_depth;
/* The name of the current function. */
const char *fnname;
/* List of buffers for the type of the function we are currently
writing out. */
struct ieee_buflist fntype;
/* List of buffers for the parameters of the function we are
currently writing out. */
struct ieee_buflist fnargs;
/* Number of arguments written to fnargs. */
unsigned int fnargcount;
/* Pending function parameters. */
struct ieee_pending_parm *pending_parms;
/* Current line number filename. */
const char *lineno_filename;
/* Line number name index. */
unsigned int lineno_name_indx;
/* Filename of pending line number. */
const char *pending_lineno_filename;
/* Pending line number. */
unsigned long pending_lineno;
/* Address of pending line number. */
bfd_vma pending_lineno_addr;
/* Highest address seen at end of procedure. */
bfd_vma highaddr;
};
 
static bfd_boolean ieee_init_buffer
(struct ieee_handle *, struct ieee_buflist *);
static bfd_boolean ieee_change_buffer
(struct ieee_handle *, struct ieee_buflist *);
static bfd_boolean ieee_append_buffer
(struct ieee_handle *, struct ieee_buflist *, struct ieee_buflist *);
static bfd_boolean ieee_real_write_byte (struct ieee_handle *, int);
static bfd_boolean ieee_write_2bytes (struct ieee_handle *, int);
static bfd_boolean ieee_write_number (struct ieee_handle *, bfd_vma);
static bfd_boolean ieee_write_id (struct ieee_handle *, const char *);
static bfd_boolean ieee_write_asn
(struct ieee_handle *, unsigned int, bfd_vma);
static bfd_boolean ieee_write_atn65
(struct ieee_handle *, unsigned int, const char *);
static bfd_boolean ieee_push_type
(struct ieee_handle *, unsigned int, unsigned int, bfd_boolean,
bfd_boolean);
static unsigned int ieee_pop_type (struct ieee_handle *);
static void ieee_pop_unused_type (struct ieee_handle *);
static unsigned int ieee_pop_type_used (struct ieee_handle *, bfd_boolean);
static bfd_boolean ieee_add_range
(struct ieee_handle *, bfd_boolean, bfd_vma, bfd_vma);
static bfd_boolean ieee_start_range (struct ieee_handle *, bfd_vma);
static bfd_boolean ieee_end_range (struct ieee_handle *, bfd_vma);
static bfd_boolean ieee_define_type
(struct ieee_handle *, unsigned int, bfd_boolean, bfd_boolean);
static bfd_boolean ieee_define_named_type
(struct ieee_handle *, const char *, unsigned int, unsigned int,
bfd_boolean, bfd_boolean, struct ieee_buflist *);
static struct ieee_modified_type *ieee_get_modified_info
(struct ieee_handle *, unsigned int);
static struct bfd_hash_entry *ieee_name_type_newfunc
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
static bfd_boolean ieee_write_undefined_tag
(struct ieee_name_type_hash_entry *, void *);
static bfd_boolean ieee_finish_compilation_unit (struct ieee_handle *);
static void ieee_add_bb11_blocks (bfd *, asection *, void *);
static bfd_boolean ieee_add_bb11
(struct ieee_handle *, asection *, bfd_vma, bfd_vma);
static bfd_boolean ieee_output_pending_parms (struct ieee_handle *);
static unsigned int ieee_vis_to_flags (enum debug_visibility);
static bfd_boolean ieee_class_method_var
(struct ieee_handle *, const char *, enum debug_visibility, bfd_boolean,
bfd_boolean, bfd_boolean, bfd_vma, bfd_boolean);
 
static bfd_boolean ieee_start_compilation_unit (void *, const char *);
static bfd_boolean ieee_start_source (void *, const char *);
static bfd_boolean ieee_empty_type (void *);
static bfd_boolean ieee_void_type (void *);
static bfd_boolean ieee_int_type (void *, unsigned int, bfd_boolean);
static bfd_boolean ieee_float_type (void *, unsigned int);
static bfd_boolean ieee_complex_type (void *, unsigned int);
static bfd_boolean ieee_bool_type (void *, unsigned int);
static bfd_boolean ieee_enum_type
(void *, const char *, const char **, bfd_signed_vma *);
static bfd_boolean ieee_pointer_type (void *);
static bfd_boolean ieee_function_type (void *, int, bfd_boolean);
static bfd_boolean ieee_reference_type (void *);
static bfd_boolean ieee_range_type (void *, bfd_signed_vma, bfd_signed_vma);
static bfd_boolean ieee_array_type
(void *, bfd_signed_vma, bfd_signed_vma, bfd_boolean);
static bfd_boolean ieee_set_type (void *, bfd_boolean);
static bfd_boolean ieee_offset_type (void *);
static bfd_boolean ieee_method_type (void *, bfd_boolean, int, bfd_boolean);
static bfd_boolean ieee_const_type (void *);
static bfd_boolean ieee_volatile_type (void *);
static bfd_boolean ieee_start_struct_type
(void *, const char *, unsigned int, bfd_boolean, unsigned int);
static bfd_boolean ieee_struct_field
(void *, const char *, bfd_vma, bfd_vma, enum debug_visibility);
static bfd_boolean ieee_end_struct_type (void *);
static bfd_boolean ieee_start_class_type
(void *, const char *, unsigned int, bfd_boolean, unsigned int, bfd_boolean,
bfd_boolean);
static bfd_boolean ieee_class_static_member
(void *, const char *, const char *, enum debug_visibility);
static bfd_boolean ieee_class_baseclass
(void *, bfd_vma, bfd_boolean, enum debug_visibility);
static bfd_boolean ieee_class_start_method (void *, const char *);
static bfd_boolean ieee_class_method_variant
(void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean,
bfd_vma, bfd_boolean);
static bfd_boolean ieee_class_static_method_variant
(void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean);
static bfd_boolean ieee_class_end_method (void *);
static bfd_boolean ieee_end_class_type (void *);
static bfd_boolean ieee_typedef_type (void *, const char *);
static bfd_boolean ieee_tag_type
(void *, const char *, unsigned int, enum debug_type_kind);
static bfd_boolean ieee_typdef (void *, const char *);
static bfd_boolean ieee_tag (void *, const char *);
static bfd_boolean ieee_int_constant (void *, const char *, bfd_vma);
static bfd_boolean ieee_float_constant (void *, const char *, double);
static bfd_boolean ieee_typed_constant (void *, const char *, bfd_vma);
static bfd_boolean ieee_variable
(void *, const char *, enum debug_var_kind, bfd_vma);
static bfd_boolean ieee_start_function (void *, const char *, bfd_boolean);
static bfd_boolean ieee_function_parameter
(void *, const char *, enum debug_parm_kind, bfd_vma);
static bfd_boolean ieee_start_block (void *, bfd_vma);
static bfd_boolean ieee_end_block (void *, bfd_vma);
static bfd_boolean ieee_end_function (void *);
static bfd_boolean ieee_lineno (void *, const char *, unsigned long, bfd_vma);
 
static const struct debug_write_fns ieee_fns =
{
ieee_start_compilation_unit,
ieee_start_source,
ieee_empty_type,
ieee_void_type,
ieee_int_type,
ieee_float_type,
ieee_complex_type,
ieee_bool_type,
ieee_enum_type,
ieee_pointer_type,
ieee_function_type,
ieee_reference_type,
ieee_range_type,
ieee_array_type,
ieee_set_type,
ieee_offset_type,
ieee_method_type,
ieee_const_type,
ieee_volatile_type,
ieee_start_struct_type,
ieee_struct_field,
ieee_end_struct_type,
ieee_start_class_type,
ieee_class_static_member,
ieee_class_baseclass,
ieee_class_start_method,
ieee_class_method_variant,
ieee_class_static_method_variant,
ieee_class_end_method,
ieee_end_class_type,
ieee_typedef_type,
ieee_tag_type,
ieee_typdef,
ieee_tag,
ieee_int_constant,
ieee_float_constant,
ieee_typed_constant,
ieee_variable,
ieee_start_function,
ieee_function_parameter,
ieee_start_block,
ieee_end_block,
ieee_end_function,
ieee_lineno
};
 
/* Initialize a buffer to be empty. */
 
static bfd_boolean
ieee_init_buffer (struct ieee_handle *info ATTRIBUTE_UNUSED,
struct ieee_buflist *buflist)
{
buflist->head = NULL;
buflist->tail = NULL;
return TRUE;
}
 
/* See whether a buffer list has any data. */
 
#define ieee_buffer_emptyp(buflist) ((buflist)->head == NULL)
 
/* Change the current buffer to a specified buffer chain. */
 
static bfd_boolean
ieee_change_buffer (struct ieee_handle *info, struct ieee_buflist *buflist)
{
if (buflist->head == NULL)
{
struct ieee_buf *buf;
 
buf = (struct ieee_buf *) xmalloc (sizeof *buf);
buf->next = NULL;
buf->c = 0;
buflist->head = buf;
buflist->tail = buf;
}
 
info->current = buflist;
info->curbuf = buflist->tail;
 
return TRUE;
}
 
/* Append a buffer chain. */
 
static bfd_boolean
ieee_append_buffer (struct ieee_handle *info ATTRIBUTE_UNUSED,
struct ieee_buflist *mainbuf,
struct ieee_buflist *newbuf)
{
if (newbuf->head != NULL)
{
if (mainbuf->head == NULL)
mainbuf->head = newbuf->head;
else
mainbuf->tail->next = newbuf->head;
mainbuf->tail = newbuf->tail;
}
return TRUE;
}
 
/* Write a byte into the buffer. We use a macro for speed and a
function for the complex cases. */
 
#define ieee_write_byte(info, b) \
((info)->curbuf->c < IEEE_BUFSIZE \
? ((info)->curbuf->buf[(info)->curbuf->c++] = (b), TRUE) \
: ieee_real_write_byte ((info), (b)))
 
static bfd_boolean
ieee_real_write_byte (struct ieee_handle *info, int b)
{
if (info->curbuf->c >= IEEE_BUFSIZE)
{
struct ieee_buf *n;
 
n = (struct ieee_buf *) xmalloc (sizeof *n);
n->next = NULL;
n->c = 0;
if (info->current->head == NULL)
info->current->head = n;
else
info->current->tail->next = n;
info->current->tail = n;
info->curbuf = n;
}
 
info->curbuf->buf[info->curbuf->c] = b;
++info->curbuf->c;
 
return TRUE;
}
 
/* Write out two bytes. */
 
static bfd_boolean
ieee_write_2bytes (struct ieee_handle *info, int i)
{
return (ieee_write_byte (info, i >> 8)
&& ieee_write_byte (info, i & 0xff));
}
 
/* Write out an integer. */
 
static bfd_boolean
ieee_write_number (struct ieee_handle *info, bfd_vma v)
{
bfd_vma t;
bfd_byte ab[20];
bfd_byte *p;
unsigned int c;
 
if (v <= (bfd_vma) ieee_number_end_enum)
return ieee_write_byte (info, (int) v);
 
t = v;
p = ab + sizeof ab;
while (t != 0)
{
*--p = t & 0xff;
t >>= 8;
}
c = (ab + 20) - p;
 
if (c > (unsigned int) (ieee_number_repeat_end_enum
- ieee_number_repeat_start_enum))
{
fprintf (stderr, _("IEEE numeric overflow: 0x"));
fprintf_vma (stderr, v);
fprintf (stderr, "\n");
return FALSE;
}
 
if (! ieee_write_byte (info, (int) ieee_number_repeat_start_enum + c))
return FALSE;
for (; c > 0; --c, ++p)
{
if (! ieee_write_byte (info, *p))
return FALSE;
}
 
return TRUE;
}
 
/* Write out a string. */
 
static bfd_boolean
ieee_write_id (struct ieee_handle *info, const char *s)
{
unsigned int len;
 
len = strlen (s);
if (len <= 0x7f)
{
if (! ieee_write_byte (info, len))
return FALSE;
}
else if (len <= 0xff)
{
if (! ieee_write_byte (info, (int) ieee_extension_length_1_enum)
|| ! ieee_write_byte (info, len))
return FALSE;
}
else if (len <= 0xffff)
{
if (! ieee_write_byte (info, (int) ieee_extension_length_2_enum)
|| ! ieee_write_2bytes (info, len))
return FALSE;
}
else
{
fprintf (stderr, _("IEEE string length overflow: %u\n"), len);
return FALSE;
}
 
for (; *s != '\0'; s++)
if (! ieee_write_byte (info, *s))
return FALSE;
 
return TRUE;
}
 
/* Write out an ASN record. */
 
static bfd_boolean
ieee_write_asn (struct ieee_handle *info, unsigned int indx, bfd_vma val)
{
return (ieee_write_2bytes (info, (int) ieee_asn_record_enum)
&& ieee_write_number (info, indx)
&& ieee_write_number (info, val));
}
 
/* Write out an ATN65 record. */
 
static bfd_boolean
ieee_write_atn65 (struct ieee_handle *info, unsigned int indx, const char *s)
{
return (ieee_write_2bytes (info, (int) ieee_atn_record_enum)
&& ieee_write_number (info, indx)
&& ieee_write_number (info, 0)
&& ieee_write_number (info, 65)
&& ieee_write_id (info, s));
}
 
/* Push a type index onto the type stack. */
 
static bfd_boolean
ieee_push_type (struct ieee_handle *info, unsigned int indx,
unsigned int size, bfd_boolean unsignedp, bfd_boolean localp)
{
struct ieee_type_stack *ts;
 
ts = (struct ieee_type_stack *) xmalloc (sizeof *ts);
memset (ts, 0, sizeof *ts);
 
ts->type.indx = indx;
ts->type.size = size;
ts->type.unsignedp = unsignedp;
ts->type.localp = localp;
 
ts->next = info->type_stack;
info->type_stack = ts;
 
return TRUE;
}
 
/* Pop a type index off the type stack. */
 
static unsigned int
ieee_pop_type (struct ieee_handle *info)
{
return ieee_pop_type_used (info, TRUE);
}
 
/* Pop an unused type index off the type stack. */
 
static void
ieee_pop_unused_type (struct ieee_handle *info)
{
(void) ieee_pop_type_used (info, FALSE);
}
 
/* Pop a used or unused type index off the type stack. */
 
static unsigned int
ieee_pop_type_used (struct ieee_handle *info, bfd_boolean used)
{
struct ieee_type_stack *ts;
unsigned int ret;
 
ts = info->type_stack;
assert (ts != NULL);
 
/* If this is a function type, and we need it, we need to append the
actual definition to the typedef block now. */
if (used && ! ieee_buffer_emptyp (&ts->type.fndef))
{
struct ieee_buflist *buflist;
 
if (ts->type.localp)
{
/* Make sure we have started the types block. */
if (ieee_buffer_emptyp (&info->types))
{
if (! ieee_change_buffer (info, &info->types)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 1)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, info->modname))
return FALSE;
}
buflist = &info->types;
}
else
{
/* Make sure we started the global type block. */
if (ieee_buffer_emptyp (&info->global_types))
{
if (! ieee_change_buffer (info, &info->global_types)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 2)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, ""))
return FALSE;
}
buflist = &info->global_types;
}
 
if (! ieee_append_buffer (info, buflist, &ts->type.fndef))
return FALSE;
}
 
ret = ts->type.indx;
info->type_stack = ts->next;
free (ts);
return ret;
}
 
/* Add a range of bytes included in the current compilation unit. */
 
static bfd_boolean
ieee_add_range (struct ieee_handle *info, bfd_boolean global, bfd_vma low,
bfd_vma high)
{
struct ieee_range **plist, *r, **pr;
 
if (low == (bfd_vma) -1 || high == (bfd_vma) -1 || low == high)
return TRUE;
 
if (global)
plist = &info->global_ranges;
else
plist = &info->ranges;
 
for (r = *plist; r != NULL; r = r->next)
{
if (high >= r->low && low <= r->high)
{
/* The new range overlaps r. */
if (low < r->low)
r->low = low;
if (high > r->high)
r->high = high;
pr = &r->next;
while (*pr != NULL && (*pr)->low <= r->high)
{
struct ieee_range *n;
 
if ((*pr)->high > r->high)
r->high = (*pr)->high;
n = (*pr)->next;
free (*pr);
*pr = n;
}
return TRUE;
}
}
 
r = (struct ieee_range *) xmalloc (sizeof *r);
memset (r, 0, sizeof *r);
 
r->low = low;
r->high = high;
 
/* Store the ranges sorted by address. */
for (pr = plist; *pr != NULL; pr = &(*pr)->next)
if ((*pr)->low > high)
break;
r->next = *pr;
*pr = r;
 
return TRUE;
}
 
/* Start a new range for which we only have the low address. */
 
static bfd_boolean
ieee_start_range (struct ieee_handle *info, bfd_vma low)
{
struct ieee_range *r;
 
r = (struct ieee_range *) xmalloc (sizeof *r);
memset (r, 0, sizeof *r);
r->low = low;
r->next = info->pending_ranges;
info->pending_ranges = r;
return TRUE;
}
 
/* Finish a range started by ieee_start_range. */
 
static bfd_boolean
ieee_end_range (struct ieee_handle *info, bfd_vma high)
{
struct ieee_range *r;
bfd_vma low;
 
assert (info->pending_ranges != NULL);
r = info->pending_ranges;
low = r->low;
info->pending_ranges = r->next;
free (r);
return ieee_add_range (info, FALSE, low, high);
}
 
/* Start defining a type. */
 
static bfd_boolean
ieee_define_type (struct ieee_handle *info, unsigned int size,
bfd_boolean unsignedp, bfd_boolean localp)
{
return ieee_define_named_type (info, (const char *) NULL,
(unsigned int) -1, size, unsignedp,
localp, (struct ieee_buflist *) NULL);
}
 
/* Start defining a named type. */
 
static bfd_boolean
ieee_define_named_type (struct ieee_handle *info, const char *name,
unsigned int indx, unsigned int size,
bfd_boolean unsignedp, bfd_boolean localp,
struct ieee_buflist *buflist)
{
unsigned int type_indx;
unsigned int name_indx;
 
if (indx != (unsigned int) -1)
type_indx = indx;
else
{
type_indx = info->type_indx;
++info->type_indx;
}
 
name_indx = info->name_indx;
++info->name_indx;
 
if (name == NULL)
name = "";
 
/* If we were given a buffer, use it; otherwise, use either the
local or the global type information, and make sure that the type
block is started. */
if (buflist != NULL)
{
if (! ieee_change_buffer (info, buflist))
return FALSE;
}
else if (localp)
{
if (! ieee_buffer_emptyp (&info->types))
{
if (! ieee_change_buffer (info, &info->types))
return FALSE;
}
else
{
if (! ieee_change_buffer (info, &info->types)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 1)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, info->modname))
return FALSE;
}
}
else
{
if (! ieee_buffer_emptyp (&info->global_types))
{
if (! ieee_change_buffer (info, &info->global_types))
return FALSE;
}
else
{
if (! ieee_change_buffer (info, &info->global_types)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 2)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, ""))
return FALSE;
}
}
 
/* Push the new type on the type stack, write out an NN record, and
write out the start of a TY record. The caller will then finish
the TY record. */
if (! ieee_push_type (info, type_indx, size, unsignedp, localp))
return FALSE;
 
return (ieee_write_byte (info, (int) ieee_nn_record)
&& ieee_write_number (info, name_indx)
&& ieee_write_id (info, name)
&& ieee_write_byte (info, (int) ieee_ty_record_enum)
&& ieee_write_number (info, type_indx)
&& ieee_write_byte (info, 0xce)
&& ieee_write_number (info, name_indx));
}
 
/* Get an entry to the list of modified versions of a type. */
 
static struct ieee_modified_type *
ieee_get_modified_info (struct ieee_handle *info, unsigned int indx)
{
if (indx >= info->modified_alloc)
{
unsigned int nalloc;
 
nalloc = info->modified_alloc;
if (nalloc == 0)
nalloc = 16;
while (indx >= nalloc)
nalloc *= 2;
info->modified = ((struct ieee_modified_type *)
xrealloc (info->modified,
nalloc * sizeof *info->modified));
memset (info->modified + info->modified_alloc, 0,
(nalloc - info->modified_alloc) * sizeof *info->modified);
info->modified_alloc = nalloc;
}
 
return info->modified + indx;
}
/* Routines for the hash table mapping names to types. */
 
/* Initialize an entry in the hash table. */
 
static struct bfd_hash_entry *
ieee_name_type_newfunc (struct bfd_hash_entry *entry,
struct bfd_hash_table *table, const char *string)
{
struct ieee_name_type_hash_entry *ret =
(struct ieee_name_type_hash_entry *) entry;
 
/* Allocate the structure if it has not already been allocated by a
subclass. */
if (ret == NULL)
ret = ((struct ieee_name_type_hash_entry *)
bfd_hash_allocate (table, sizeof *ret));
if (ret == NULL)
return NULL;
 
/* Call the allocation method of the superclass. */
ret = ((struct ieee_name_type_hash_entry *)
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
if (ret)
{
/* Set local fields. */
ret->types = NULL;
}
 
return (struct bfd_hash_entry *) ret;
}
 
/* Look up an entry in the hash table. */
 
#define ieee_name_type_hash_lookup(table, string, create, copy) \
((struct ieee_name_type_hash_entry *) \
bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
 
/* Traverse the hash table. */
 
#define ieee_name_type_hash_traverse(table, func, info) \
(bfd_hash_traverse \
(&(table)->root, \
(bfd_boolean (*) (struct bfd_hash_entry *, void *)) (func), \
(info)))
/* The general routine to write out IEEE debugging information. */
 
bfd_boolean
write_ieee_debugging_info (bfd *abfd, void *dhandle)
{
struct ieee_handle info;
asection *s;
const char *err;
struct ieee_buf *b;
 
memset (&info, 0, sizeof info);
info.abfd = abfd;
info.type_indx = 256;
info.name_indx = 32;
 
if (!bfd_hash_table_init (&info.typedefs.root, ieee_name_type_newfunc,
sizeof (struct ieee_name_type_hash_entry))
|| !bfd_hash_table_init (&info.tags.root, ieee_name_type_newfunc,
sizeof (struct ieee_name_type_hash_entry)))
return FALSE;
 
if (! ieee_init_buffer (&info, &info.global_types)
|| ! ieee_init_buffer (&info, &info.data)
|| ! ieee_init_buffer (&info, &info.types)
|| ! ieee_init_buffer (&info, &info.vars)
|| ! ieee_init_buffer (&info, &info.cxx)
|| ! ieee_init_buffer (&info, &info.linenos)
|| ! ieee_init_buffer (&info, &info.fntype)
|| ! ieee_init_buffer (&info, &info.fnargs))
return FALSE;
 
if (! debug_write (dhandle, &ieee_fns, (void *) &info))
return FALSE;
 
if (info.filename != NULL)
{
if (! ieee_finish_compilation_unit (&info))
return FALSE;
}
 
/* Put any undefined tags in the global typedef information. */
info.error = FALSE;
ieee_name_type_hash_traverse (&info.tags,
ieee_write_undefined_tag,
(void *) &info);
if (info.error)
return FALSE;
 
/* Prepend the global typedef information to the other data. */
if (! ieee_buffer_emptyp (&info.global_types))
{
/* The HP debugger seems to have a bug in which it ignores the
last entry in the global types, so we add a dummy entry. */
if (! ieee_change_buffer (&info, &info.global_types)
|| ! ieee_write_byte (&info, (int) ieee_nn_record)
|| ! ieee_write_number (&info, info.name_indx)
|| ! ieee_write_id (&info, "")
|| ! ieee_write_byte (&info, (int) ieee_ty_record_enum)
|| ! ieee_write_number (&info, info.type_indx)
|| ! ieee_write_byte (&info, 0xce)
|| ! ieee_write_number (&info, info.name_indx)
|| ! ieee_write_number (&info, 'P')
|| ! ieee_write_number (&info, (int) builtin_void + 32)
|| ! ieee_write_byte (&info, (int) ieee_be_record_enum))
return FALSE;
 
if (! ieee_append_buffer (&info, &info.global_types, &info.data))
return FALSE;
info.data = info.global_types;
}
 
/* Make sure that we have declare BB11 blocks for each range in the
file. They are added to info->vars. */
info.error = FALSE;
if (! ieee_init_buffer (&info, &info.vars))
return FALSE;
bfd_map_over_sections (abfd, ieee_add_bb11_blocks, (void *) &info);
if (info.error)
return FALSE;
if (! ieee_buffer_emptyp (&info.vars))
{
if (! ieee_change_buffer (&info, &info.vars)
|| ! ieee_write_byte (&info, (int) ieee_be_record_enum))
return FALSE;
 
if (! ieee_append_buffer (&info, &info.data, &info.vars))
return FALSE;
}
 
/* Now all the data is in info.data. Write it out to the BFD. We
normally would need to worry about whether all the other sections
are set up yet, but the IEEE backend will handle this particular
case correctly regardless. */
if (ieee_buffer_emptyp (&info.data))
{
/* There is no debugging information. */
return TRUE;
}
err = NULL;
s = bfd_make_section_with_flags (abfd, ".debug",
SEC_DEBUGGING | SEC_HAS_CONTENTS);
if (s == NULL)
err = "bfd_make_section";
if (err == NULL)
{
bfd_size_type size;
 
size = 0;
for (b = info.data.head; b != NULL; b = b->next)
size += b->c;
if (! bfd_set_section_size (abfd, s, size))
err = "bfd_set_section_size";
}
if (err == NULL)
{
file_ptr offset;
 
offset = 0;
for (b = info.data.head; b != NULL; b = b->next)
{
if (! bfd_set_section_contents (abfd, s, b->buf, offset, b->c))
{
err = "bfd_set_section_contents";
break;
}
offset += b->c;
}
}
 
if (err != NULL)
{
fprintf (stderr, "%s: %s: %s\n", bfd_get_filename (abfd), err,
bfd_errmsg (bfd_get_error ()));
return FALSE;
}
 
bfd_hash_table_free (&info.typedefs.root);
bfd_hash_table_free (&info.tags.root);
 
return TRUE;
}
 
/* Write out information for an undefined tag. This is called via
ieee_name_type_hash_traverse. */
 
static bfd_boolean
ieee_write_undefined_tag (struct ieee_name_type_hash_entry *h, void *p)
{
struct ieee_handle *info = (struct ieee_handle *) p;
struct ieee_name_type *nt;
 
for (nt = h->types; nt != NULL; nt = nt->next)
{
unsigned int name_indx;
char code;
 
if (nt->kind == DEBUG_KIND_ILLEGAL)
continue;
 
if (ieee_buffer_emptyp (&info->global_types))
{
if (! ieee_change_buffer (info, &info->global_types)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 2)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, ""))
{
info->error = TRUE;
return FALSE;
}
}
else
{
if (! ieee_change_buffer (info, &info->global_types))
{
info->error = TRUE;
return FALSE;
}
}
 
name_indx = info->name_indx;
++info->name_indx;
if (! ieee_write_byte (info, (int) ieee_nn_record)
|| ! ieee_write_number (info, name_indx)
|| ! ieee_write_id (info, nt->type.name)
|| ! ieee_write_byte (info, (int) ieee_ty_record_enum)
|| ! ieee_write_number (info, nt->type.indx)
|| ! ieee_write_byte (info, 0xce)
|| ! ieee_write_number (info, name_indx))
{
info->error = TRUE;
return FALSE;
}
 
switch (nt->kind)
{
default:
abort ();
info->error = TRUE;
return FALSE;
case DEBUG_KIND_STRUCT:
case DEBUG_KIND_CLASS:
code = 'S';
break;
case DEBUG_KIND_UNION:
case DEBUG_KIND_UNION_CLASS:
code = 'U';
break;
case DEBUG_KIND_ENUM:
code = 'E';
break;
}
if (! ieee_write_number (info, code)
|| ! ieee_write_number (info, 0))
{
info->error = TRUE;
return FALSE;
}
}
 
return TRUE;
}
 
/* Start writing out information for a compilation unit. */
 
static bfd_boolean
ieee_start_compilation_unit (void *p, const char *filename)
{
struct ieee_handle *info = (struct ieee_handle *) p;
const char *modname;
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
const char *backslash;
#endif
char *c, *s;
 
if (info->filename != NULL)
{
if (! ieee_finish_compilation_unit (info))
return FALSE;
}
 
info->filename = filename;
modname = strrchr (filename, '/');
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
/* We could have a mixed forward/back slash case. */
backslash = strrchr (filename, '\\');
if (modname == NULL || (backslash != NULL && backslash > modname))
modname = backslash;
#endif
 
if (modname != NULL)
++modname;
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
else if (filename[0] && filename[1] == ':')
modname = filename + 2;
#endif
else
modname = filename;
 
c = xstrdup (modname);
s = strrchr (c, '.');
if (s != NULL)
*s = '\0';
info->modname = c;
 
if (! ieee_init_buffer (info, &info->types)
|| ! ieee_init_buffer (info, &info->vars)
|| ! ieee_init_buffer (info, &info->cxx)
|| ! ieee_init_buffer (info, &info->linenos))
return FALSE;
info->ranges = NULL;
 
/* Always include a BB1 and a BB3 block. That is what the output of
the MRI linker seems to look like. */
if (! ieee_change_buffer (info, &info->types)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 1)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, info->modname))
return FALSE;
 
++info->name_indx;
if (! ieee_change_buffer (info, &info->vars)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 3)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, info->modname))
return FALSE;
 
return TRUE;
}
 
/* Finish up a compilation unit. */
 
static bfd_boolean
ieee_finish_compilation_unit (struct ieee_handle *info)
{
struct ieee_range *r;
 
if (! ieee_buffer_emptyp (&info->types))
{
if (! ieee_change_buffer (info, &info->types)
|| ! ieee_write_byte (info, (int) ieee_be_record_enum))
return FALSE;
}
 
if (! ieee_buffer_emptyp (&info->cxx))
{
/* Append any C++ information to the global function and
variable information. */
assert (! ieee_buffer_emptyp (&info->vars));
if (! ieee_change_buffer (info, &info->vars))
return FALSE;
 
/* We put the pmisc records in a dummy procedure, just as the
MRI compiler does. */
if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 6)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, "__XRYCPP")
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, info->highaddr - 1)
|| ! ieee_append_buffer (info, &info->vars, &info->cxx)
|| ! ieee_change_buffer (info, &info->vars)
|| ! ieee_write_byte (info, (int) ieee_be_record_enum)
|| ! ieee_write_number (info, info->highaddr - 1))
return FALSE;
}
 
if (! ieee_buffer_emptyp (&info->vars))
{
if (! ieee_change_buffer (info, &info->vars)
|| ! ieee_write_byte (info, (int) ieee_be_record_enum))
return FALSE;
}
 
if (info->pending_lineno_filename != NULL)
{
/* Force out the pending line number. */
if (! ieee_lineno ((void *) info, (const char *) NULL, 0, (bfd_vma) -1))
return FALSE;
}
if (! ieee_buffer_emptyp (&info->linenos))
{
if (! ieee_change_buffer (info, &info->linenos)
|| ! ieee_write_byte (info, (int) ieee_be_record_enum))
return FALSE;
if (filename_cmp (info->filename, info->lineno_filename) != 0)
{
/* We were not in the main file. We just closed the
included line number block, and now we must close the
main line number block. */
if (! ieee_write_byte (info, (int) ieee_be_record_enum))
return FALSE;
}
}
 
if (! ieee_append_buffer (info, &info->data, &info->types)
|| ! ieee_append_buffer (info, &info->data, &info->vars)
|| ! ieee_append_buffer (info, &info->data, &info->linenos))
return FALSE;
 
/* Build BB10/BB11 blocks based on the ranges we recorded. */
if (! ieee_change_buffer (info, &info->data))
return FALSE;
 
if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 10)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, info->modname)
|| ! ieee_write_id (info, "")
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, "GNU objcopy"))
return FALSE;
 
for (r = info->ranges; r != NULL; r = r->next)
{
bfd_vma low, high;
asection *s;
int kind;
 
low = r->low;
high = r->high;
 
/* Find the section corresponding to this range. */
for (s = info->abfd->sections; s != NULL; s = s->next)
{
if (bfd_get_section_vma (info->abfd, s) <= low
&& high <= (bfd_get_section_vma (info->abfd, s)
+ bfd_section_size (info->abfd, s)))
break;
}
 
if (s == NULL)
{
/* Just ignore this range. */
continue;
}
 
/* Coalesce ranges if it seems reasonable. */
while (r->next != NULL
&& high + 0x1000 >= r->next->low
&& (r->next->high
<= (bfd_get_section_vma (info->abfd, s)
+ bfd_section_size (info->abfd, s))))
{
r = r->next;
high = r->high;
}
 
if ((s->flags & SEC_CODE) != 0)
kind = 1;
else if ((s->flags & SEC_READONLY) != 0)
kind = 3;
else
kind = 2;
 
if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 11)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, "")
|| ! ieee_write_number (info, kind)
|| ! ieee_write_number (info, s->index + IEEE_SECTION_NUMBER_BASE)
|| ! ieee_write_number (info, low)
|| ! ieee_write_byte (info, (int) ieee_be_record_enum)
|| ! ieee_write_number (info, high - low))
return FALSE;
 
/* Add this range to the list of global ranges. */
if (! ieee_add_range (info, TRUE, low, high))
return FALSE;
}
 
if (! ieee_write_byte (info, (int) ieee_be_record_enum))
return FALSE;
 
return TRUE;
}
 
/* Add BB11 blocks describing each range that we have not already
described. */
 
static void
ieee_add_bb11_blocks (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *data)
{
struct ieee_handle *info = (struct ieee_handle *) data;
bfd_vma low, high;
struct ieee_range *r;
 
low = bfd_get_section_vma (abfd, sec);
high = low + bfd_section_size (abfd, sec);
 
/* Find the first range at or after this section. The ranges are
sorted by address. */
for (r = info->global_ranges; r != NULL; r = r->next)
if (r->high > low)
break;
 
while (low < high)
{
if (r == NULL || r->low >= high)
{
if (! ieee_add_bb11 (info, sec, low, high))
info->error = TRUE;
return;
}
 
if (low < r->low
&& r->low - low > 0x100)
{
if (! ieee_add_bb11 (info, sec, low, r->low))
{
info->error = TRUE;
return;
}
}
low = r->high;
 
r = r->next;
}
}
 
/* Add a single BB11 block for a range. We add it to info->vars. */
 
static bfd_boolean
ieee_add_bb11 (struct ieee_handle *info, asection *sec, bfd_vma low,
bfd_vma high)
{
int kind;
 
if (! ieee_buffer_emptyp (&info->vars))
{
if (! ieee_change_buffer (info, &info->vars))
return FALSE;
}
else
{
const char *filename, *modname;
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
const char *backslash;
#endif
char *c, *s;
 
/* Start the enclosing BB10 block. */
filename = bfd_get_filename (info->abfd);
modname = strrchr (filename, '/');
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
backslash = strrchr (filename, '\\');
if (modname == NULL || (backslash != NULL && backslash > modname))
modname = backslash;
#endif
 
if (modname != NULL)
++modname;
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
else if (filename[0] && filename[1] == ':')
modname = filename + 2;
#endif
else
modname = filename;
 
c = xstrdup (modname);
s = strrchr (c, '.');
if (s != NULL)
*s = '\0';
 
if (! ieee_change_buffer (info, &info->vars)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 10)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, c)
|| ! ieee_write_id (info, "")
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, "GNU objcopy"))
{
free (c);
return FALSE;
}
 
free (c);
}
 
if ((sec->flags & SEC_CODE) != 0)
kind = 1;
else if ((sec->flags & SEC_READONLY) != 0)
kind = 3;
else
kind = 2;
 
if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 11)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, "")
|| ! ieee_write_number (info, kind)
|| ! ieee_write_number (info, sec->index + IEEE_SECTION_NUMBER_BASE)
|| ! ieee_write_number (info, low)
|| ! ieee_write_byte (info, (int) ieee_be_record_enum)
|| ! ieee_write_number (info, high - low))
return FALSE;
 
return TRUE;
}
 
/* Start recording information from a particular source file. This is
used to record which file defined which types, variables, etc. It
is not used for line numbers, since the lineno entry point passes
down the file name anyhow. IEEE debugging information doesn't seem
to store this information anywhere. */
 
static bfd_boolean
ieee_start_source (void *p ATTRIBUTE_UNUSED,
const char *filename ATTRIBUTE_UNUSED)
{
return TRUE;
}
 
/* Make an empty type. */
 
static bfd_boolean
ieee_empty_type (void *p)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
return ieee_push_type (info, (int) builtin_unknown, 0, FALSE, FALSE);
}
 
/* Make a void type. */
 
static bfd_boolean
ieee_void_type (void *p)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
return ieee_push_type (info, (int) builtin_void, 0, FALSE, FALSE);
}
 
/* Make an integer type. */
 
static bfd_boolean
ieee_int_type (void *p, unsigned int size, bfd_boolean unsignedp)
{
struct ieee_handle *info = (struct ieee_handle *) p;
unsigned int indx;
 
switch (size)
{
case 1:
indx = (int) builtin_signed_char;
break;
case 2:
indx = (int) builtin_signed_short_int;
break;
case 4:
indx = (int) builtin_signed_long;
break;
case 8:
indx = (int) builtin_signed_long_long;
break;
default:
fprintf (stderr, _("IEEE unsupported integer type size %u\n"), size);
return FALSE;
}
 
if (unsignedp)
++indx;
 
return ieee_push_type (info, indx, size, unsignedp, FALSE);
}
 
/* Make a floating point type. */
 
static bfd_boolean
ieee_float_type (void *p, unsigned int size)
{
struct ieee_handle *info = (struct ieee_handle *) p;
unsigned int indx;
 
switch (size)
{
case 4:
indx = (int) builtin_float;
break;
case 8:
indx = (int) builtin_double;
break;
case 12:
/* FIXME: This size really depends upon the processor. */
indx = (int) builtin_long_double;
break;
case 16:
indx = (int) builtin_long_long_double;
break;
default:
fprintf (stderr, _("IEEE unsupported float type size %u\n"), size);
return FALSE;
}
 
return ieee_push_type (info, indx, size, FALSE, FALSE);
}
 
/* Make a complex type. */
 
static bfd_boolean
ieee_complex_type (void *p, unsigned int size)
{
struct ieee_handle *info = (struct ieee_handle *) p;
char code;
 
switch (size)
{
case 4:
if (info->complex_float_index != 0)
return ieee_push_type (info, info->complex_float_index, size * 2,
FALSE, FALSE);
code = 'c';
break;
case 12:
case 16:
/* These cases can be output by gcc -gstabs. Outputting the
wrong type is better than crashing. */
case 8:
if (info->complex_double_index != 0)
return ieee_push_type (info, info->complex_double_index, size * 2,
FALSE, FALSE);
code = 'd';
break;
default:
fprintf (stderr, _("IEEE unsupported complex type size %u\n"), size);
return FALSE;
}
 
/* FIXME: I don't know what the string is for. */
if (! ieee_define_type (info, size * 2, FALSE, FALSE)
|| ! ieee_write_number (info, code)
|| ! ieee_write_id (info, ""))
return FALSE;
 
if (size == 4)
info->complex_float_index = info->type_stack->type.indx;
else
info->complex_double_index = info->type_stack->type.indx;
 
return TRUE;
}
 
/* Make a boolean type. IEEE doesn't support these, so we just make
an integer type instead. */
 
static bfd_boolean
ieee_bool_type (void *p, unsigned int size)
{
return ieee_int_type (p, size, TRUE);
}
 
/* Make an enumeration. */
 
static bfd_boolean
ieee_enum_type (void *p, const char *tag, const char **names,
bfd_signed_vma *vals)
{
struct ieee_handle *info = (struct ieee_handle *) p;
struct ieee_defined_enum *e;
bfd_boolean localp, simple;
unsigned int indx;
int i = 0;
 
localp = FALSE;
indx = (unsigned int) -1;
for (e = info->enums; e != NULL; e = e->next)
{
if (tag == NULL)
{
if (e->tag != NULL)
continue;
}
else
{
if (e->tag == NULL
|| tag[0] != e->tag[0]
|| strcmp (tag, e->tag) != 0)
continue;
}
 
if (! e->defined)
{
/* This enum tag has been seen but not defined. */
indx = e->indx;
break;
}
 
if (names != NULL && e->names != NULL)
{
for (i = 0; names[i] != NULL && e->names[i] != NULL; i++)
{
if (names[i][0] != e->names[i][0]
|| vals[i] != e->vals[i]
|| strcmp (names[i], e->names[i]) != 0)
break;
}
}
 
if ((names == NULL && e->names == NULL)
|| (names != NULL
&& e->names != NULL
&& names[i] == NULL
&& e->names[i] == NULL))
{
/* We've seen this enum before. */
return ieee_push_type (info, e->indx, 0, TRUE, FALSE);
}
 
if (tag != NULL)
{
/* We've already seen an enum of the same name, so we must make
sure to output this one locally. */
localp = TRUE;
break;
}
}
 
/* If this is a simple enumeration, in which the values start at 0
and always increment by 1, we can use type E. Otherwise we must
use type N. */
 
simple = TRUE;
if (names != NULL)
{
for (i = 0; names[i] != NULL; i++)
{
if (vals[i] != i)
{
simple = FALSE;
break;
}
}
}
 
if (! ieee_define_named_type (info, tag, indx, 0, TRUE, localp,
(struct ieee_buflist *) NULL)
|| ! ieee_write_number (info, simple ? 'E' : 'N'))
return FALSE;
if (simple)
{
/* FIXME: This is supposed to be the enumeration size, but we
don't store that. */
if (! ieee_write_number (info, 4))
return FALSE;
}
if (names != NULL)
{
for (i = 0; names[i] != NULL; i++)
{
if (! ieee_write_id (info, names[i]))
return FALSE;
if (! simple)
{
if (! ieee_write_number (info, vals[i]))
return FALSE;
}
}
}
 
if (! localp)
{
if (indx == (unsigned int) -1)
{
e = (struct ieee_defined_enum *) xmalloc (sizeof *e);
memset (e, 0, sizeof *e);
e->indx = info->type_stack->type.indx;
e->tag = tag;
 
e->next = info->enums;
info->enums = e;
}
 
e->names = names;
e->vals = vals;
e->defined = TRUE;
}
 
return TRUE;
}
 
/* Make a pointer type. */
 
static bfd_boolean
ieee_pointer_type (void *p)
{
struct ieee_handle *info = (struct ieee_handle *) p;
bfd_boolean localp;
unsigned int indx;
struct ieee_modified_type *m = NULL;
 
localp = info->type_stack->type.localp;
indx = ieee_pop_type (info);
 
/* A pointer to a simple builtin type can be obtained by adding 32.
FIXME: Will this be a short pointer, and will that matter? */
if (indx < 32)
return ieee_push_type (info, indx + 32, 0, TRUE, FALSE);
 
if (! localp)
{
m = ieee_get_modified_info ((struct ieee_handle *) p, indx);
if (m == NULL)
return FALSE;
 
/* FIXME: The size should depend upon the architecture. */
if (m->pointer > 0)
return ieee_push_type (info, m->pointer, 4, TRUE, FALSE);
}
 
if (! ieee_define_type (info, 4, TRUE, localp)
|| ! ieee_write_number (info, 'P')
|| ! ieee_write_number (info, indx))
return FALSE;
 
if (! localp)
m->pointer = info->type_stack->type.indx;
 
return TRUE;
}
 
/* Make a function type. This will be called for a method, but we
don't want to actually add it to the type table in that case. We
handle this by defining the type in a private buffer, and only
adding that buffer to the typedef block if we are going to use it. */
 
static bfd_boolean
ieee_function_type (void *p, int argcount, bfd_boolean varargs)
{
struct ieee_handle *info = (struct ieee_handle *) p;
bfd_boolean localp;
unsigned int *args = NULL;
int i;
unsigned int retindx;
struct ieee_buflist fndef;
struct ieee_modified_type *m;
 
localp = FALSE;
 
if (argcount > 0)
{
args = (unsigned int *) xmalloc (argcount * sizeof *args);
for (i = argcount - 1; i >= 0; i--)
{
if (info->type_stack->type.localp)
localp = TRUE;
args[i] = ieee_pop_type (info);
}
}
else if (argcount < 0)
varargs = FALSE;
 
if (info->type_stack->type.localp)
localp = TRUE;
retindx = ieee_pop_type (info);
 
m = NULL;
if (argcount < 0 && ! localp)
{
m = ieee_get_modified_info ((struct ieee_handle *) p, retindx);
if (m == NULL)
return FALSE;
 
if (m->function > 0)
return ieee_push_type (info, m->function, 0, TRUE, FALSE);
}
 
/* An attribute of 0x41 means that the frame and push mask are
unknown. */
if (! ieee_init_buffer (info, &fndef)
|| ! ieee_define_named_type (info, (const char *) NULL,
(unsigned int) -1, 0, TRUE, localp,
&fndef)
|| ! ieee_write_number (info, 'x')
|| ! ieee_write_number (info, 0x41)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, retindx)
|| ! ieee_write_number (info, (bfd_vma) argcount + (varargs ? 1 : 0)))
{
free (args);
return FALSE;
}
if (argcount > 0)
{
for (i = 0; i < argcount; i++)
if (! ieee_write_number (info, args[i]))
return FALSE;
free (args);
}
if (varargs)
{
/* A varargs function is represented by writing out the last
argument as type void *, although this makes little sense. */
if (! ieee_write_number (info, (bfd_vma) builtin_void + 32))
return FALSE;
}
 
if (! ieee_write_number (info, 0))
return FALSE;
 
/* We wrote the information into fndef, in case we don't need it.
It will be appended to info->types by ieee_pop_type. */
info->type_stack->type.fndef = fndef;
 
if (m != NULL)
m->function = info->type_stack->type.indx;
 
return TRUE;
}
 
/* Make a reference type. */
 
static bfd_boolean
ieee_reference_type (void *p)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
/* IEEE appears to record a normal pointer type, and then use a
pmisc record to indicate that it is really a reference. */
 
if (! ieee_pointer_type (p))
return FALSE;
info->type_stack->type.referencep = TRUE;
return TRUE;
}
 
/* Make a range type. */
 
static bfd_boolean
ieee_range_type (void *p, bfd_signed_vma low, bfd_signed_vma high)
{
struct ieee_handle *info = (struct ieee_handle *) p;
unsigned int size;
bfd_boolean unsignedp, localp;
 
size = info->type_stack->type.size;
unsignedp = info->type_stack->type.unsignedp;
localp = info->type_stack->type.localp;
ieee_pop_unused_type (info);
return (ieee_define_type (info, size, unsignedp, localp)
&& ieee_write_number (info, 'R')
&& ieee_write_number (info, (bfd_vma) low)
&& ieee_write_number (info, (bfd_vma) high)
&& ieee_write_number (info, unsignedp ? 0 : 1)
&& ieee_write_number (info, size));
}
 
/* Make an array type. */
 
static bfd_boolean
ieee_array_type (void *p, bfd_signed_vma low, bfd_signed_vma high,
bfd_boolean stringp ATTRIBUTE_UNUSED)
{
struct ieee_handle *info = (struct ieee_handle *) p;
unsigned int eleindx;
bfd_boolean localp;
unsigned int size;
struct ieee_modified_type *m = NULL;
struct ieee_modified_array_type *a;
 
/* IEEE does not store the range, so we just ignore it. */
ieee_pop_unused_type (info);
localp = info->type_stack->type.localp;
size = info->type_stack->type.size;
eleindx = ieee_pop_type (info);
 
/* If we don't know the range, treat the size as exactly one
element. */
if (low < high)
size *= (high - low) + 1;
 
if (! localp)
{
m = ieee_get_modified_info (info, eleindx);
if (m == NULL)
return FALSE;
 
for (a = m->arrays; a != NULL; a = a->next)
{
if (a->low == low && a->high == high)
return ieee_push_type (info, a->indx, size, FALSE, FALSE);
}
}
 
if (! ieee_define_type (info, size, FALSE, localp)
|| ! ieee_write_number (info, low == 0 ? 'Z' : 'C')
|| ! ieee_write_number (info, eleindx))
return FALSE;
if (low != 0)
{
if (! ieee_write_number (info, low))
return FALSE;
}
 
if (! ieee_write_number (info, high + 1))
return FALSE;
 
if (! localp)
{
a = (struct ieee_modified_array_type *) xmalloc (sizeof *a);
memset (a, 0, sizeof *a);
 
a->indx = info->type_stack->type.indx;
a->low = low;
a->high = high;
 
a->next = m->arrays;
m->arrays = a;
}
 
return TRUE;
}
 
/* Make a set type. */
 
static bfd_boolean
ieee_set_type (void *p, bfd_boolean bitstringp ATTRIBUTE_UNUSED)
{
struct ieee_handle *info = (struct ieee_handle *) p;
bfd_boolean localp;
unsigned int eleindx;
 
localp = info->type_stack->type.localp;
eleindx = ieee_pop_type (info);
 
/* FIXME: We don't know the size, so we just use 4. */
 
return (ieee_define_type (info, 0, TRUE, localp)
&& ieee_write_number (info, 's')
&& ieee_write_number (info, 4)
&& ieee_write_number (info, eleindx));
}
 
/* Make an offset type. */
 
static bfd_boolean
ieee_offset_type (void *p)
{
/* FIXME: The MRI C++ compiler does not appear to generate any
useful type information about an offset type. It just records a
pointer to member as an integer. The MRI/HP IEEE spec does
describe a pmisc record which can be used for a pointer to
member. Unfortunately, it does not describe the target type,
which seems pretty important. I'm going to punt this for now. */
 
return ieee_int_type (p, 4, TRUE);
}
 
/* Make a method type. */
 
static bfd_boolean
ieee_method_type (void *p, bfd_boolean domain, int argcount,
bfd_boolean varargs)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
/* FIXME: The MRI/HP IEEE spec defines a pmisc record to use for a
method, but the definition is incomplete. We just output an 'x'
type. */
 
if (domain)
ieee_pop_unused_type (info);
 
return ieee_function_type (p, argcount, varargs);
}
 
/* Make a const qualified type. */
 
static bfd_boolean
ieee_const_type (void *p)
{
struct ieee_handle *info = (struct ieee_handle *) p;
unsigned int size;
bfd_boolean unsignedp, localp;
unsigned int indx;
struct ieee_modified_type *m = NULL;
 
size = info->type_stack->type.size;
unsignedp = info->type_stack->type.unsignedp;
localp = info->type_stack->type.localp;
indx = ieee_pop_type (info);
 
if (! localp)
{
m = ieee_get_modified_info (info, indx);
if (m == NULL)
return FALSE;
 
if (m->const_qualified > 0)
return ieee_push_type (info, m->const_qualified, size, unsignedp,
FALSE);
}
 
if (! ieee_define_type (info, size, unsignedp, localp)
|| ! ieee_write_number (info, 'n')
|| ! ieee_write_number (info, 1)
|| ! ieee_write_number (info, indx))
return FALSE;
 
if (! localp)
m->const_qualified = info->type_stack->type.indx;
 
return TRUE;
}
 
/* Make a volatile qualified type. */
 
static bfd_boolean
ieee_volatile_type (void *p)
{
struct ieee_handle *info = (struct ieee_handle *) p;
unsigned int size;
bfd_boolean unsignedp, localp;
unsigned int indx;
struct ieee_modified_type *m = NULL;
 
size = info->type_stack->type.size;
unsignedp = info->type_stack->type.unsignedp;
localp = info->type_stack->type.localp;
indx = ieee_pop_type (info);
 
if (! localp)
{
m = ieee_get_modified_info (info, indx);
if (m == NULL)
return FALSE;
 
if (m->volatile_qualified > 0)
return ieee_push_type (info, m->volatile_qualified, size, unsignedp,
FALSE);
}
 
if (! ieee_define_type (info, size, unsignedp, localp)
|| ! ieee_write_number (info, 'n')
|| ! ieee_write_number (info, 2)
|| ! ieee_write_number (info, indx))
return FALSE;
 
if (! localp)
m->volatile_qualified = info->type_stack->type.indx;
 
return TRUE;
}
 
/* Convert an enum debug_visibility into a CXXFLAGS value. */
 
static unsigned int
ieee_vis_to_flags (enum debug_visibility visibility)
{
switch (visibility)
{
default:
abort ();
case DEBUG_VISIBILITY_PUBLIC:
return CXXFLAGS_VISIBILITY_PUBLIC;
case DEBUG_VISIBILITY_PRIVATE:
return CXXFLAGS_VISIBILITY_PRIVATE;
case DEBUG_VISIBILITY_PROTECTED:
return CXXFLAGS_VISIBILITY_PROTECTED;
}
/*NOTREACHED*/
}
 
/* Start defining a struct type. We build it in the strdef field on
the stack, to avoid confusing type definitions required by the
fields with the struct type itself. */
 
static bfd_boolean
ieee_start_struct_type (void *p, const char *tag, unsigned int id,
bfd_boolean structp, unsigned int size)
{
struct ieee_handle *info = (struct ieee_handle *) p;
bfd_boolean localp, ignorep;
bfd_boolean copy;
char ab[20];
const char *look;
struct ieee_name_type_hash_entry *h;
struct ieee_name_type *nt, *ntlook;
struct ieee_buflist strdef;
 
localp = FALSE;
ignorep = FALSE;
 
/* We need to create a tag for internal use even if we don't want
one for external use. This will let us refer to an anonymous
struct. */
if (tag != NULL)
{
look = tag;
copy = FALSE;
}
else
{
sprintf (ab, "__anon%u", id);
look = ab;
copy = TRUE;
}
 
/* If we already have references to the tag, we must use the
existing type index. */
h = ieee_name_type_hash_lookup (&info->tags, look, TRUE, copy);
if (h == NULL)
return FALSE;
 
nt = NULL;
for (ntlook = h->types; ntlook != NULL; ntlook = ntlook->next)
{
if (ntlook->id == id)
nt = ntlook;
else if (! ntlook->type.localp)
{
/* We are creating a duplicate definition of a globally
defined tag. Force it to be local to avoid
confusion. */
localp = TRUE;
}
}
 
if (nt != NULL)
{
assert (localp == nt->type.localp);
if (nt->kind == DEBUG_KIND_ILLEGAL && ! localp)
{
/* We've already seen a global definition of the type.
Ignore this new definition. */
ignorep = TRUE;
}
}
else
{
nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
memset (nt, 0, sizeof *nt);
nt->id = id;
nt->type.name = h->root.string;
nt->next = h->types;
h->types = nt;
nt->type.indx = info->type_indx;
++info->type_indx;
}
 
nt->kind = DEBUG_KIND_ILLEGAL;
 
if (! ieee_init_buffer (info, &strdef)
|| ! ieee_define_named_type (info, tag, nt->type.indx, size, TRUE,
localp, &strdef)
|| ! ieee_write_number (info, structp ? 'S' : 'U')
|| ! ieee_write_number (info, size))
return FALSE;
 
if (! ignorep)
{
const char *hold;
 
/* We never want nt->type.name to be NULL. We want the rest of
the type to be the object set up on the type stack; it will
have a NULL name if tag is NULL. */
hold = nt->type.name;
nt->type = info->type_stack->type;
nt->type.name = hold;
}
 
info->type_stack->type.name = tag;
info->type_stack->type.strdef = strdef;
info->type_stack->type.ignorep = ignorep;
 
return TRUE;
}
 
/* Add a field to a struct. */
 
static bfd_boolean
ieee_struct_field (void *p, const char *name, bfd_vma bitpos, bfd_vma bitsize,
enum debug_visibility visibility)
{
struct ieee_handle *info = (struct ieee_handle *) p;
unsigned int size;
bfd_boolean unsignedp;
bfd_boolean referencep;
bfd_boolean localp;
unsigned int indx;
bfd_vma offset;
 
assert (info->type_stack != NULL
&& info->type_stack->next != NULL
&& ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef));
 
/* If we are ignoring this struct definition, just pop and ignore
the type. */
if (info->type_stack->next->type.ignorep)
{
ieee_pop_unused_type (info);
return TRUE;
}
 
size = info->type_stack->type.size;
unsignedp = info->type_stack->type.unsignedp;
referencep = info->type_stack->type.referencep;
localp = info->type_stack->type.localp;
indx = ieee_pop_type (info);
 
if (localp)
info->type_stack->type.localp = TRUE;
 
if (info->type_stack->type.classdef != NULL)
{
unsigned int flags;
unsigned int nindx;
 
/* This is a class. We must add a description of this field to
the class records we are building. */
 
flags = ieee_vis_to_flags (visibility);
nindx = info->type_stack->type.classdef->indx;
if (! ieee_change_buffer (info,
&info->type_stack->type.classdef->pmiscbuf)
|| ! ieee_write_asn (info, nindx, 'd')
|| ! ieee_write_asn (info, nindx, flags)
|| ! ieee_write_atn65 (info, nindx, name)
|| ! ieee_write_atn65 (info, nindx, name))
return FALSE;
info->type_stack->type.classdef->pmisccount += 4;
 
if (referencep)
{
/* We need to output a record recording that this field is
really of reference type. We put this on the refs field
of classdef, so that it can be appended to the C++
records after the class is defined. */
 
nindx = info->name_indx;
++info->name_indx;
 
if (! ieee_change_buffer (info,
&info->type_stack->type.classdef->refs)
|| ! ieee_write_byte (info, (int) ieee_nn_record)
|| ! ieee_write_number (info, nindx)
|| ! ieee_write_id (info, "")
|| ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
|| ! ieee_write_number (info, nindx)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, 62)
|| ! ieee_write_number (info, 80)
|| ! ieee_write_number (info, 4)
|| ! ieee_write_asn (info, nindx, 'R')
|| ! ieee_write_asn (info, nindx, 3)
|| ! ieee_write_atn65 (info, nindx, info->type_stack->type.name)
|| ! ieee_write_atn65 (info, nindx, name))
return FALSE;
}
}
 
/* If the bitsize doesn't match the expected size, we need to output
a bitfield type. */
if (size == 0 || bitsize == 0 || bitsize == size * 8)
offset = bitpos / 8;
else
{
if (! ieee_define_type (info, 0, unsignedp,
info->type_stack->type.localp)
|| ! ieee_write_number (info, 'g')
|| ! ieee_write_number (info, unsignedp ? 0 : 1)
|| ! ieee_write_number (info, bitsize)
|| ! ieee_write_number (info, indx))
return FALSE;
indx = ieee_pop_type (info);
offset = bitpos;
}
 
/* Switch to the struct we are building in order to output this
field definition. */
return (ieee_change_buffer (info, &info->type_stack->type.strdef)
&& ieee_write_id (info, name)
&& ieee_write_number (info, indx)
&& ieee_write_number (info, offset));
}
 
/* Finish up a struct type. */
 
static bfd_boolean
ieee_end_struct_type (void *p)
{
struct ieee_handle *info = (struct ieee_handle *) p;
struct ieee_buflist *pb;
 
assert (info->type_stack != NULL
&& ! ieee_buffer_emptyp (&info->type_stack->type.strdef));
 
/* If we were ignoring this struct definition because it was a
duplicate definition, just through away whatever bytes we have
accumulated. Leave the type on the stack. */
if (info->type_stack->type.ignorep)
return TRUE;
 
/* If this is not a duplicate definition of this tag, then localp
will be FALSE, and we can put it in the global type block.
FIXME: We should avoid outputting duplicate definitions which are
the same. */
if (! info->type_stack->type.localp)
{
/* Make sure we have started the global type block. */
if (ieee_buffer_emptyp (&info->global_types))
{
if (! ieee_change_buffer (info, &info->global_types)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 2)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, ""))
return FALSE;
}
pb = &info->global_types;
}
else
{
/* Make sure we have started the types block. */
if (ieee_buffer_emptyp (&info->types))
{
if (! ieee_change_buffer (info, &info->types)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 1)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, info->modname))
return FALSE;
}
pb = &info->types;
}
 
/* Append the struct definition to the types. */
if (! ieee_append_buffer (info, pb, &info->type_stack->type.strdef)
|| ! ieee_init_buffer (info, &info->type_stack->type.strdef))
return FALSE;
 
/* Leave the struct on the type stack. */
 
return TRUE;
}
 
/* Start a class type. */
 
static bfd_boolean
ieee_start_class_type (void *p, const char *tag, unsigned int id,
bfd_boolean structp, unsigned int size,
bfd_boolean vptr, bfd_boolean ownvptr)
{
struct ieee_handle *info = (struct ieee_handle *) p;
const char *vclass;
struct ieee_buflist pmiscbuf;
unsigned int indx;
struct ieee_type_class *classdef;
 
/* A C++ class is output as a C++ struct along with a set of pmisc
records describing the class. */
 
/* We need to have a name so that we can associate the struct and
the class. */
if (tag == NULL)
{
char *t;
 
t = (char *) xmalloc (20);
sprintf (t, "__anon%u", id);
tag = t;
}
 
/* We can't write out the virtual table information until we have
finished the class, because we don't know the virtual table size.
We get the size from the largest voffset we see. */
vclass = NULL;
if (vptr && ! ownvptr)
{
vclass = info->type_stack->type.name;
assert (vclass != NULL);
/* We don't call ieee_pop_unused_type, since the class should
get defined. */
(void) ieee_pop_type (info);
}
 
if (! ieee_start_struct_type (p, tag, id, structp, size))
return FALSE;
 
indx = info->name_indx;
++info->name_indx;
 
/* We write out pmisc records into the classdef field. We will
write out the pmisc start after we know the number of records we
need. */
if (! ieee_init_buffer (info, &pmiscbuf)
|| ! ieee_change_buffer (info, &pmiscbuf)
|| ! ieee_write_asn (info, indx, 'T')
|| ! ieee_write_asn (info, indx, structp ? 'o' : 'u')
|| ! ieee_write_atn65 (info, indx, tag))
return FALSE;
 
classdef = (struct ieee_type_class *) xmalloc (sizeof *classdef);
memset (classdef, 0, sizeof *classdef);
 
classdef->indx = indx;
classdef->pmiscbuf = pmiscbuf;
classdef->pmisccount = 3;
classdef->vclass = vclass;
classdef->ownvptr = ownvptr;
 
info->type_stack->type.classdef = classdef;
 
return TRUE;
}
 
/* Add a static member to a class. */
 
static bfd_boolean
ieee_class_static_member (void *p, const char *name, const char *physname,
enum debug_visibility visibility)
{
struct ieee_handle *info = (struct ieee_handle *) p;
unsigned int flags;
unsigned int nindx;
 
/* We don't care about the type. Hopefully there will be a call to
ieee_variable declaring the physical name and the type, since
that is where an IEEE consumer must get the type. */
ieee_pop_unused_type (info);
 
assert (info->type_stack != NULL
&& info->type_stack->type.classdef != NULL);
 
flags = ieee_vis_to_flags (visibility);
flags |= CXXFLAGS_STATIC;
 
nindx = info->type_stack->type.classdef->indx;
 
if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf)
|| ! ieee_write_asn (info, nindx, 'd')
|| ! ieee_write_asn (info, nindx, flags)
|| ! ieee_write_atn65 (info, nindx, name)
|| ! ieee_write_atn65 (info, nindx, physname))
return FALSE;
info->type_stack->type.classdef->pmisccount += 4;
 
return TRUE;
}
 
/* Add a base class to a class. */
 
static bfd_boolean
ieee_class_baseclass (void *p, bfd_vma bitpos, bfd_boolean is_virtual,
enum debug_visibility visibility)
{
struct ieee_handle *info = (struct ieee_handle *) p;
const char *bname;
bfd_boolean localp;
unsigned int bindx;
char *fname;
unsigned int flags;
unsigned int nindx;
 
assert (info->type_stack != NULL
&& info->type_stack->type.name != NULL
&& info->type_stack->next != NULL
&& info->type_stack->next->type.classdef != NULL
&& ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef));
 
bname = info->type_stack->type.name;
localp = info->type_stack->type.localp;
bindx = ieee_pop_type (info);
 
/* We are currently defining both a struct and a class. We must
write out a field definition in the struct which holds the base
class. The stabs debugging reader will create a field named
_vb$CLASS for a virtual base class, so we just use that. FIXME:
we should not depend upon a detail of stabs debugging. */
if (is_virtual)
{
fname = (char *) xmalloc (strlen (bname) + sizeof "_vb$");
sprintf (fname, "_vb$%s", bname);
flags = BASEFLAGS_VIRTUAL;
}
else
{
if (localp)
info->type_stack->type.localp = TRUE;
 
fname = (char *) xmalloc (strlen (bname) + sizeof "_b$");
sprintf (fname, "_b$%s", bname);
 
if (! ieee_change_buffer (info, &info->type_stack->type.strdef)
|| ! ieee_write_id (info, fname)
|| ! ieee_write_number (info, bindx)
|| ! ieee_write_number (info, bitpos / 8))
{
free (fname);
return FALSE;
}
flags = 0;
}
 
if (visibility == DEBUG_VISIBILITY_PRIVATE)
flags |= BASEFLAGS_PRIVATE;
 
nindx = info->type_stack->type.classdef->indx;
 
if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf)
|| ! ieee_write_asn (info, nindx, 'b')
|| ! ieee_write_asn (info, nindx, flags)
|| ! ieee_write_atn65 (info, nindx, bname)
|| ! ieee_write_asn (info, nindx, 0)
|| ! ieee_write_atn65 (info, nindx, fname))
{
free (fname);
return FALSE;
}
info->type_stack->type.classdef->pmisccount += 5;
 
free (fname);
 
return TRUE;
}
 
/* Start building a method for a class. */
 
static bfd_boolean
ieee_class_start_method (void *p, const char *name)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
assert (info->type_stack != NULL
&& info->type_stack->type.classdef != NULL
&& info->type_stack->type.classdef->method == NULL);
 
info->type_stack->type.classdef->method = name;
 
return TRUE;
}
 
/* Define a new method variant, either static or not. */
 
static bfd_boolean
ieee_class_method_var (struct ieee_handle *info, const char *physname,
enum debug_visibility visibility,
bfd_boolean staticp, bfd_boolean constp,
bfd_boolean volatilep, bfd_vma voffset,
bfd_boolean context)
{
unsigned int flags;
unsigned int nindx;
bfd_boolean is_virtual;
 
/* We don't need the type of the method. An IEEE consumer which
wants the type must track down the function by the physical name
and get the type from that. */
ieee_pop_unused_type (info);
 
/* We don't use the context. FIXME: We probably ought to use it to
adjust the voffset somehow, but I don't really know how. */
if (context)
ieee_pop_unused_type (info);
 
assert (info->type_stack != NULL
&& info->type_stack->type.classdef != NULL
&& info->type_stack->type.classdef->method != NULL);
 
flags = ieee_vis_to_flags (visibility);
 
/* FIXME: We never set CXXFLAGS_OVERRIDE, CXXFLAGS_OPERATOR,
CXXFLAGS_CTORDTOR, CXXFLAGS_CTOR, or CXXFLAGS_INLINE. */
 
if (staticp)
flags |= CXXFLAGS_STATIC;
if (constp)
flags |= CXXFLAGS_CONST;
if (volatilep)
flags |= CXXFLAGS_VOLATILE;
 
nindx = info->type_stack->type.classdef->indx;
 
is_virtual = context || voffset > 0;
 
if (! ieee_change_buffer (info,
&info->type_stack->type.classdef->pmiscbuf)
|| ! ieee_write_asn (info, nindx, is_virtual ? 'v' : 'm')
|| ! ieee_write_asn (info, nindx, flags)
|| ! ieee_write_atn65 (info, nindx,
info->type_stack->type.classdef->method)
|| ! ieee_write_atn65 (info, nindx, physname))
return FALSE;
 
if (is_virtual)
{
if (voffset > info->type_stack->type.classdef->voffset)
info->type_stack->type.classdef->voffset = voffset;
if (! ieee_write_asn (info, nindx, voffset))
return FALSE;
++info->type_stack->type.classdef->pmisccount;
}
 
if (! ieee_write_asn (info, nindx, 0))
return FALSE;
 
info->type_stack->type.classdef->pmisccount += 5;
 
return TRUE;
}
 
/* Define a new method variant. */
 
static bfd_boolean
ieee_class_method_variant (void *p, const char *physname,
enum debug_visibility visibility,
bfd_boolean constp, bfd_boolean volatilep,
bfd_vma voffset, bfd_boolean context)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
return ieee_class_method_var (info, physname, visibility, FALSE, constp,
volatilep, voffset, context);
}
 
/* Define a new static method variant. */
 
static bfd_boolean
ieee_class_static_method_variant (void *p, const char *physname,
enum debug_visibility visibility,
bfd_boolean constp, bfd_boolean volatilep)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
return ieee_class_method_var (info, physname, visibility, TRUE, constp,
volatilep, 0, FALSE);
}
 
/* Finish up a method. */
 
static bfd_boolean
ieee_class_end_method (void *p)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
assert (info->type_stack != NULL
&& info->type_stack->type.classdef != NULL
&& info->type_stack->type.classdef->method != NULL);
 
info->type_stack->type.classdef->method = NULL;
 
return TRUE;
}
 
/* Finish up a class. */
 
static bfd_boolean
ieee_end_class_type (void *p)
{
struct ieee_handle *info = (struct ieee_handle *) p;
unsigned int nindx;
 
assert (info->type_stack != NULL
&& info->type_stack->type.classdef != NULL);
 
/* If we were ignoring this class definition because it was a
duplicate definition, just through away whatever bytes we have
accumulated. Leave the type on the stack. */
if (info->type_stack->type.ignorep)
return TRUE;
 
nindx = info->type_stack->type.classdef->indx;
 
/* If we have a virtual table, we can write out the information now. */
if (info->type_stack->type.classdef->vclass != NULL
|| info->type_stack->type.classdef->ownvptr)
{
if (! ieee_change_buffer (info,
&info->type_stack->type.classdef->pmiscbuf)
|| ! ieee_write_asn (info, nindx, 'z')
|| ! ieee_write_atn65 (info, nindx, "")
|| ! ieee_write_asn (info, nindx,
info->type_stack->type.classdef->voffset))
return FALSE;
if (info->type_stack->type.classdef->ownvptr)
{
if (! ieee_write_atn65 (info, nindx, ""))
return FALSE;
}
else
{
if (! ieee_write_atn65 (info, nindx,
info->type_stack->type.classdef->vclass))
return FALSE;
}
if (! ieee_write_asn (info, nindx, 0))
return FALSE;
info->type_stack->type.classdef->pmisccount += 5;
}
 
/* Now that we know the number of pmisc records, we can write out
the atn62 which starts the pmisc records, and append them to the
C++ buffers. */
 
if (! ieee_change_buffer (info, &info->cxx)
|| ! ieee_write_byte (info, (int) ieee_nn_record)
|| ! ieee_write_number (info, nindx)
|| ! ieee_write_id (info, "")
|| ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
|| ! ieee_write_number (info, nindx)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, 62)
|| ! ieee_write_number (info, 80)
|| ! ieee_write_number (info,
info->type_stack->type.classdef->pmisccount))
return FALSE;
 
if (! ieee_append_buffer (info, &info->cxx,
&info->type_stack->type.classdef->pmiscbuf))
return FALSE;
if (! ieee_buffer_emptyp (&info->type_stack->type.classdef->refs))
{
if (! ieee_append_buffer (info, &info->cxx,
&info->type_stack->type.classdef->refs))
return FALSE;
}
 
return ieee_end_struct_type (p);
}
 
/* Push a previously seen typedef onto the type stack. */
 
static bfd_boolean
ieee_typedef_type (void *p, const char *name)
{
struct ieee_handle *info = (struct ieee_handle *) p;
struct ieee_name_type_hash_entry *h;
struct ieee_name_type *nt;
 
h = ieee_name_type_hash_lookup (&info->typedefs, name, FALSE, FALSE);
 
/* h should never be NULL, since that would imply that the generic
debugging code has asked for a typedef which it has not yet
defined. */
assert (h != NULL);
 
/* We always use the most recently defined type for this name, which
will be the first one on the list. */
 
nt = h->types;
if (! ieee_push_type (info, nt->type.indx, nt->type.size,
nt->type.unsignedp, nt->type.localp))
return FALSE;
 
/* Copy over any other type information we may have. */
info->type_stack->type = nt->type;
 
return TRUE;
}
 
/* Push a tagged type onto the type stack. */
 
static bfd_boolean
ieee_tag_type (void *p, const char *name, unsigned int id,
enum debug_type_kind kind)
{
struct ieee_handle *info = (struct ieee_handle *) p;
bfd_boolean localp;
bfd_boolean copy;
char ab[20];
struct ieee_name_type_hash_entry *h;
struct ieee_name_type *nt;
 
if (kind == DEBUG_KIND_ENUM)
{
struct ieee_defined_enum *e;
 
if (name == NULL)
abort ();
for (e = info->enums; e != NULL; e = e->next)
if (e->tag != NULL && strcmp (e->tag, name) == 0)
return ieee_push_type (info, e->indx, 0, TRUE, FALSE);
 
e = (struct ieee_defined_enum *) xmalloc (sizeof *e);
memset (e, 0, sizeof *e);
 
e->indx = info->type_indx;
++info->type_indx;
e->tag = name;
e->defined = FALSE;
 
e->next = info->enums;
info->enums = e;
 
return ieee_push_type (info, e->indx, 0, TRUE, FALSE);
}
 
localp = FALSE;
 
copy = FALSE;
if (name == NULL)
{
sprintf (ab, "__anon%u", id);
name = ab;
copy = TRUE;
}
 
h = ieee_name_type_hash_lookup (&info->tags, name, TRUE, copy);
if (h == NULL)
return FALSE;
 
for (nt = h->types; nt != NULL; nt = nt->next)
{
if (nt->id == id)
{
if (! ieee_push_type (info, nt->type.indx, nt->type.size,
nt->type.unsignedp, nt->type.localp))
return FALSE;
/* Copy over any other type information we may have. */
info->type_stack->type = nt->type;
return TRUE;
}
 
if (! nt->type.localp)
{
/* This is a duplicate of a global type, so it must be
local. */
localp = TRUE;
}
}
 
nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
memset (nt, 0, sizeof *nt);
 
nt->id = id;
nt->type.name = h->root.string;
nt->type.indx = info->type_indx;
nt->type.localp = localp;
++info->type_indx;
nt->kind = kind;
 
nt->next = h->types;
h->types = nt;
 
if (! ieee_push_type (info, nt->type.indx, 0, FALSE, localp))
return FALSE;
 
info->type_stack->type.name = h->root.string;
 
return TRUE;
}
 
/* Output a typedef. */
 
static bfd_boolean
ieee_typdef (void *p, const char *name)
{
struct ieee_handle *info = (struct ieee_handle *) p;
struct ieee_write_type type;
unsigned int indx;
bfd_boolean found;
bfd_boolean localp;
struct ieee_name_type_hash_entry *h;
struct ieee_name_type *nt;
 
type = info->type_stack->type;
indx = type.indx;
 
/* If this is a simple builtin type using a builtin name, we don't
want to output the typedef itself. We also want to change the
type index to correspond to the name being used. We recognize
names used in stabs debugging output even if they don't exactly
correspond to the names used for the IEEE builtin types. */
found = FALSE;
if (indx <= (unsigned int) builtin_bcd_float)
{
switch ((enum builtin_types) indx)
{
default:
break;
 
case builtin_void:
if (strcmp (name, "void") == 0)
found = TRUE;
break;
 
case builtin_signed_char:
case builtin_char:
if (strcmp (name, "signed char") == 0)
{
indx = (unsigned int) builtin_signed_char;
found = TRUE;
}
else if (strcmp (name, "char") == 0)
{
indx = (unsigned int) builtin_char;
found = TRUE;
}
break;
 
case builtin_unsigned_char:
if (strcmp (name, "unsigned char") == 0)
found = TRUE;
break;
 
case builtin_signed_short_int:
case builtin_short:
case builtin_short_int:
case builtin_signed_short:
if (strcmp (name, "signed short int") == 0)
{
indx = (unsigned int) builtin_signed_short_int;
found = TRUE;
}
else if (strcmp (name, "short") == 0)
{
indx = (unsigned int) builtin_short;
found = TRUE;
}
else if (strcmp (name, "short int") == 0)
{
indx = (unsigned int) builtin_short_int;
found = TRUE;
}
else if (strcmp (name, "signed short") == 0)
{
indx = (unsigned int) builtin_signed_short;
found = TRUE;
}
break;
 
case builtin_unsigned_short_int:
case builtin_unsigned_short:
if (strcmp (name, "unsigned short int") == 0
|| strcmp (name, "short unsigned int") == 0)
{
indx = builtin_unsigned_short_int;
found = TRUE;
}
else if (strcmp (name, "unsigned short") == 0)
{
indx = builtin_unsigned_short;
found = TRUE;
}
break;
 
case builtin_signed_long:
case builtin_int: /* FIXME: Size depends upon architecture. */
case builtin_long:
if (strcmp (name, "signed long") == 0)
{
indx = builtin_signed_long;
found = TRUE;
}
else if (strcmp (name, "int") == 0)
{
indx = builtin_int;
found = TRUE;
}
else if (strcmp (name, "long") == 0
|| strcmp (name, "long int") == 0)
{
indx = builtin_long;
found = TRUE;
}
break;
 
case builtin_unsigned_long:
case builtin_unsigned: /* FIXME: Size depends upon architecture. */
case builtin_unsigned_int: /* FIXME: Like builtin_unsigned. */
if (strcmp (name, "unsigned long") == 0
|| strcmp (name, "long unsigned int") == 0)
{
indx = builtin_unsigned_long;
found = TRUE;
}
else if (strcmp (name, "unsigned") == 0)
{
indx = builtin_unsigned;
found = TRUE;
}
else if (strcmp (name, "unsigned int") == 0)
{
indx = builtin_unsigned_int;
found = TRUE;
}
break;
 
case builtin_signed_long_long:
if (strcmp (name, "signed long long") == 0
|| strcmp (name, "long long int") == 0)
found = TRUE;
break;
 
case builtin_unsigned_long_long:
if (strcmp (name, "unsigned long long") == 0
|| strcmp (name, "long long unsigned int") == 0)
found = TRUE;
break;
 
case builtin_float:
if (strcmp (name, "float") == 0)
found = TRUE;
break;
 
case builtin_double:
if (strcmp (name, "double") == 0)
found = TRUE;
break;
 
case builtin_long_double:
if (strcmp (name, "long double") == 0)
found = TRUE;
break;
 
case builtin_long_long_double:
if (strcmp (name, "long long double") == 0)
found = TRUE;
break;
}
 
if (found)
type.indx = indx;
}
 
h = ieee_name_type_hash_lookup (&info->typedefs, name, TRUE, FALSE);
if (h == NULL)
return FALSE;
 
/* See if we have already defined this type with this name. */
localp = type.localp;
for (nt = h->types; nt != NULL; nt = nt->next)
{
if (nt->id == indx)
{
/* If this is a global definition, then we don't need to
do anything here. */
if (! nt->type.localp)
{
ieee_pop_unused_type (info);
return TRUE;
}
}
else
{
/* This is a duplicate definition, so make this one local. */
localp = TRUE;
}
}
 
/* We need to add a new typedef for this type. */
 
nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
memset (nt, 0, sizeof *nt);
nt->id = indx;
nt->type = type;
nt->type.name = name;
nt->type.localp = localp;
nt->kind = DEBUG_KIND_ILLEGAL;
 
nt->next = h->types;
h->types = nt;
 
if (found)
{
/* This is one of the builtin typedefs, so we don't need to
actually define it. */
ieee_pop_unused_type (info);
return TRUE;
}
 
indx = ieee_pop_type (info);
 
if (! ieee_define_named_type (info, name, (unsigned int) -1, type.size,
type.unsignedp, localp,
(struct ieee_buflist *) NULL)
|| ! ieee_write_number (info, 'T')
|| ! ieee_write_number (info, indx))
return FALSE;
 
/* Remove the type we just added to the type stack. This should not
be ieee_pop_unused_type, since the type is used, we just don't
need it now. */
(void) ieee_pop_type (info);
 
return TRUE;
}
 
/* Output a tag for a type. We don't have to do anything here. */
 
static bfd_boolean
ieee_tag (void *p, const char *name ATTRIBUTE_UNUSED)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
/* This should not be ieee_pop_unused_type, since we want the type
to be defined. */
(void) ieee_pop_type (info);
return TRUE;
}
 
/* Output an integer constant. */
 
static bfd_boolean
ieee_int_constant (void *p ATTRIBUTE_UNUSED, const char *name ATTRIBUTE_UNUSED,
bfd_vma val ATTRIBUTE_UNUSED)
{
/* FIXME. */
return TRUE;
}
 
/* Output a floating point constant. */
 
static bfd_boolean
ieee_float_constant (void *p ATTRIBUTE_UNUSED,
const char *name ATTRIBUTE_UNUSED,
double val ATTRIBUTE_UNUSED)
{
/* FIXME. */
return TRUE;
}
 
/* Output a typed constant. */
 
static bfd_boolean
ieee_typed_constant (void *p, const char *name ATTRIBUTE_UNUSED,
bfd_vma val ATTRIBUTE_UNUSED)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
/* FIXME. */
ieee_pop_unused_type (info);
return TRUE;
}
 
/* Output a variable. */
 
static bfd_boolean
ieee_variable (void *p, const char *name, enum debug_var_kind kind,
bfd_vma val)
{
struct ieee_handle *info = (struct ieee_handle *) p;
unsigned int name_indx;
unsigned int size;
bfd_boolean referencep;
unsigned int type_indx;
bfd_boolean asn;
int refflag;
 
size = info->type_stack->type.size;
referencep = info->type_stack->type.referencep;
type_indx = ieee_pop_type (info);
 
assert (! ieee_buffer_emptyp (&info->vars));
if (! ieee_change_buffer (info, &info->vars))
return FALSE;
 
name_indx = info->name_indx;
++info->name_indx;
 
/* Write out an NN and an ATN record for this variable. */
if (! ieee_write_byte (info, (int) ieee_nn_record)
|| ! ieee_write_number (info, name_indx)
|| ! ieee_write_id (info, name)
|| ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
|| ! ieee_write_number (info, name_indx)
|| ! ieee_write_number (info, type_indx))
return FALSE;
switch (kind)
{
default:
abort ();
return FALSE;
case DEBUG_GLOBAL:
if (! ieee_write_number (info, 8)
|| ! ieee_add_range (info, FALSE, val, val + size))
return FALSE;
refflag = 0;
asn = TRUE;
break;
case DEBUG_STATIC:
if (! ieee_write_number (info, 3)
|| ! ieee_add_range (info, FALSE, val, val + size))
return FALSE;
refflag = 1;
asn = TRUE;
break;
case DEBUG_LOCAL_STATIC:
if (! ieee_write_number (info, 3)
|| ! ieee_add_range (info, FALSE, val, val + size))
return FALSE;
refflag = 2;
asn = TRUE;
break;
case DEBUG_LOCAL:
if (! ieee_write_number (info, 1)
|| ! ieee_write_number (info, val))
return FALSE;
refflag = 2;
asn = FALSE;
break;
case DEBUG_REGISTER:
if (! ieee_write_number (info, 2)
|| ! ieee_write_number (info,
ieee_genreg_to_regno (info->abfd, val)))
return FALSE;
refflag = 2;
asn = FALSE;
break;
}
 
if (asn)
{
if (! ieee_write_asn (info, name_indx, val))
return FALSE;
}
 
/* If this is really a reference type, then we just output it with
pointer type, and must now output a C++ record indicating that it
is really reference type. */
if (referencep)
{
unsigned int nindx;
 
nindx = info->name_indx;
++info->name_indx;
 
/* If this is a global variable, we want to output the misc
record in the C++ misc record block. Otherwise, we want to
output it just after the variable definition, which is where
the current buffer is. */
if (refflag != 2)
{
if (! ieee_change_buffer (info, &info->cxx))
return FALSE;
}
 
if (! ieee_write_byte (info, (int) ieee_nn_record)
|| ! ieee_write_number (info, nindx)
|| ! ieee_write_id (info, "")
|| ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
|| ! ieee_write_number (info, nindx)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, 62)
|| ! ieee_write_number (info, 80)
|| ! ieee_write_number (info, 3)
|| ! ieee_write_asn (info, nindx, 'R')
|| ! ieee_write_asn (info, nindx, refflag)
|| ! ieee_write_atn65 (info, nindx, name))
return FALSE;
}
 
return TRUE;
}
 
/* Start outputting information for a function. */
 
static bfd_boolean
ieee_start_function (void *p, const char *name, bfd_boolean global)
{
struct ieee_handle *info = (struct ieee_handle *) p;
bfd_boolean referencep;
unsigned int retindx, typeindx;
 
referencep = info->type_stack->type.referencep;
retindx = ieee_pop_type (info);
 
/* Besides recording a BB4 or BB6 block, we record the type of the
function in the BB1 typedef block. We can't write out the full
type until we have seen all the parameters, so we accumulate it
in info->fntype and info->fnargs. */
if (! ieee_buffer_emptyp (&info->fntype))
{
/* FIXME: This might happen someday if we support nested
functions. */
abort ();
}
 
info->fnname = name;
 
/* An attribute of 0x40 means that the push mask is unknown. */
if (! ieee_define_named_type (info, name, (unsigned int) -1, 0, FALSE, TRUE,
&info->fntype)
|| ! ieee_write_number (info, 'x')
|| ! ieee_write_number (info, 0x40)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, retindx))
return FALSE;
 
typeindx = ieee_pop_type (info);
 
if (! ieee_init_buffer (info, &info->fnargs))
return FALSE;
info->fnargcount = 0;
 
/* If the function return value is actually a reference type, we
must add a record indicating that. */
if (referencep)
{
unsigned int nindx;
 
nindx = info->name_indx;
++info->name_indx;
if (! ieee_change_buffer (info, &info->cxx)
|| ! ieee_write_byte (info, (int) ieee_nn_record)
|| ! ieee_write_number (info, nindx)
|| ! ieee_write_id (info, "")
|| ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
|| ! ieee_write_number (info, nindx)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, 62)
|| ! ieee_write_number (info, 80)
|| ! ieee_write_number (info, 3)
|| ! ieee_write_asn (info, nindx, 'R')
|| ! ieee_write_asn (info, nindx, global ? 0 : 1)
|| ! ieee_write_atn65 (info, nindx, name))
return FALSE;
}
 
assert (! ieee_buffer_emptyp (&info->vars));
if (! ieee_change_buffer (info, &info->vars))
return FALSE;
 
/* The address is written out as the first block. */
 
++info->block_depth;
 
return (ieee_write_byte (info, (int) ieee_bb_record_enum)
&& ieee_write_byte (info, global ? 4 : 6)
&& ieee_write_number (info, 0)
&& ieee_write_id (info, name)
&& ieee_write_number (info, 0)
&& ieee_write_number (info, typeindx));
}
 
/* Add a function parameter. This will normally be called before the
first block, so we postpone them until we see the block. */
 
static bfd_boolean
ieee_function_parameter (void *p, const char *name, enum debug_parm_kind kind,
bfd_vma val)
{
struct ieee_handle *info = (struct ieee_handle *) p;
struct ieee_pending_parm *m, **pm;
 
assert (info->block_depth == 1);
 
m = (struct ieee_pending_parm *) xmalloc (sizeof *m);
memset (m, 0, sizeof *m);
 
m->next = NULL;
m->name = name;
m->referencep = info->type_stack->type.referencep;
m->type = ieee_pop_type (info);
m->kind = kind;
m->val = val;
 
for (pm = &info->pending_parms; *pm != NULL; pm = &(*pm)->next)
;
*pm = m;
 
/* Add the type to the fnargs list. */
if (! ieee_change_buffer (info, &info->fnargs)
|| ! ieee_write_number (info, m->type))
return FALSE;
++info->fnargcount;
 
return TRUE;
}
 
/* Output pending function parameters. */
 
static bfd_boolean
ieee_output_pending_parms (struct ieee_handle *info)
{
struct ieee_pending_parm *m;
unsigned int refcount;
 
refcount = 0;
for (m = info->pending_parms; m != NULL; m = m->next)
{
enum debug_var_kind vkind;
 
switch (m->kind)
{
default:
abort ();
return FALSE;
case DEBUG_PARM_STACK:
case DEBUG_PARM_REFERENCE:
vkind = DEBUG_LOCAL;
break;
case DEBUG_PARM_REG:
case DEBUG_PARM_REF_REG:
vkind = DEBUG_REGISTER;
break;
}
 
if (! ieee_push_type (info, m->type, 0, FALSE, FALSE))
return FALSE;
info->type_stack->type.referencep = m->referencep;
if (m->referencep)
++refcount;
if (! ieee_variable ((void *) info, m->name, vkind, m->val))
return FALSE;
}
 
/* If there are any reference parameters, we need to output a
miscellaneous record indicating them. */
if (refcount > 0)
{
unsigned int nindx, varindx;
 
/* FIXME: The MRI compiler outputs the demangled function name
here, but we are outputting the mangled name. */
nindx = info->name_indx;
++info->name_indx;
if (! ieee_change_buffer (info, &info->vars)
|| ! ieee_write_byte (info, (int) ieee_nn_record)
|| ! ieee_write_number (info, nindx)
|| ! ieee_write_id (info, "")
|| ! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
|| ! ieee_write_number (info, nindx)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, 62)
|| ! ieee_write_number (info, 80)
|| ! ieee_write_number (info, refcount + 3)
|| ! ieee_write_asn (info, nindx, 'B')
|| ! ieee_write_atn65 (info, nindx, info->fnname)
|| ! ieee_write_asn (info, nindx, 0))
return FALSE;
for (m = info->pending_parms, varindx = 1;
m != NULL;
m = m->next, varindx++)
{
if (m->referencep)
{
if (! ieee_write_asn (info, nindx, varindx))
return FALSE;
}
}
}
 
m = info->pending_parms;
while (m != NULL)
{
struct ieee_pending_parm *next;
 
next = m->next;
free (m);
m = next;
}
 
info->pending_parms = NULL;
 
return TRUE;
}
 
/* Start a block. If this is the first block, we output the address
to finish the BB4 or BB6, and then output the function parameters. */
 
static bfd_boolean
ieee_start_block (void *p, bfd_vma addr)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
if (! ieee_change_buffer (info, &info->vars))
return FALSE;
 
if (info->block_depth == 1)
{
if (! ieee_write_number (info, addr)
|| ! ieee_output_pending_parms (info))
return FALSE;
}
else
{
if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 6)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, "")
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, addr))
return FALSE;
}
 
if (! ieee_start_range (info, addr))
return FALSE;
 
++info->block_depth;
 
return TRUE;
}
 
/* End a block. */
 
static bfd_boolean
ieee_end_block (void *p, bfd_vma addr)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
/* The address we are given is the end of the block, but IEEE seems
to want to the address of the last byte in the block, so we
subtract one. */
if (! ieee_change_buffer (info, &info->vars)
|| ! ieee_write_byte (info, (int) ieee_be_record_enum)
|| ! ieee_write_number (info, addr - 1))
return FALSE;
 
if (! ieee_end_range (info, addr))
return FALSE;
 
--info->block_depth;
 
if (addr > info->highaddr)
info->highaddr = addr;
 
return TRUE;
}
 
/* End a function. */
 
static bfd_boolean
ieee_end_function (void *p)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
assert (info->block_depth == 1);
 
--info->block_depth;
 
/* Now we can finish up fntype, and add it to the typdef section.
At this point, fntype is the 'x' type up to the argument count,
and fnargs is the argument types. We must add the argument
count, and we must add the level. FIXME: We don't record varargs
functions correctly. In fact, stabs debugging does not give us
enough information to do so. */
if (! ieee_change_buffer (info, &info->fntype)
|| ! ieee_write_number (info, info->fnargcount)
|| ! ieee_change_buffer (info, &info->fnargs)
|| ! ieee_write_number (info, 0))
return FALSE;
 
/* Make sure the typdef block has been started. */
if (ieee_buffer_emptyp (&info->types))
{
if (! ieee_change_buffer (info, &info->types)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 1)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, info->modname))
return FALSE;
}
 
if (! ieee_append_buffer (info, &info->types, &info->fntype)
|| ! ieee_append_buffer (info, &info->types, &info->fnargs))
return FALSE;
 
info->fnname = NULL;
if (! ieee_init_buffer (info, &info->fntype)
|| ! ieee_init_buffer (info, &info->fnargs))
return FALSE;
info->fnargcount = 0;
 
return TRUE;
}
 
/* Record line number information. */
 
static bfd_boolean
ieee_lineno (void *p, const char *filename, unsigned long lineno, bfd_vma addr)
{
struct ieee_handle *info = (struct ieee_handle *) p;
 
assert (info->filename != NULL);
 
/* The HP simulator seems to get confused when more than one line is
listed for the same address, at least if they are in different
files. We handle this by always listing the last line for a
given address, since that seems to be the one that gdb uses. */
if (info->pending_lineno_filename != NULL
&& addr != info->pending_lineno_addr)
{
/* Make sure we have a line number block. */
if (! ieee_buffer_emptyp (&info->linenos))
{
if (! ieee_change_buffer (info, &info->linenos))
return FALSE;
}
else
{
info->lineno_name_indx = info->name_indx;
++info->name_indx;
if (! ieee_change_buffer (info, &info->linenos)
|| ! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 5)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, info->filename)
|| ! ieee_write_byte (info, (int) ieee_nn_record)
|| ! ieee_write_number (info, info->lineno_name_indx)
|| ! ieee_write_id (info, ""))
return FALSE;
info->lineno_filename = info->filename;
}
 
if (filename_cmp (info->pending_lineno_filename,
info->lineno_filename) != 0)
{
if (filename_cmp (info->filename, info->lineno_filename) != 0)
{
/* We were not in the main file. Close the block for the
included file. */
if (! ieee_write_byte (info, (int) ieee_be_record_enum))
return FALSE;
if (filename_cmp (info->filename,
info->pending_lineno_filename) == 0)
{
/* We need a new NN record, and we aren't about to
output one. */
info->lineno_name_indx = info->name_indx;
++info->name_indx;
if (! ieee_write_byte (info, (int) ieee_nn_record)
|| ! ieee_write_number (info, info->lineno_name_indx)
|| ! ieee_write_id (info, ""))
return FALSE;
}
}
if (filename_cmp (info->filename,
info->pending_lineno_filename) != 0)
{
/* We are not changing to the main file. Open a block for
the new included file. */
info->lineno_name_indx = info->name_indx;
++info->name_indx;
if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
|| ! ieee_write_byte (info, 5)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_id (info, info->pending_lineno_filename)
|| ! ieee_write_byte (info, (int) ieee_nn_record)
|| ! ieee_write_number (info, info->lineno_name_indx)
|| ! ieee_write_id (info, ""))
return FALSE;
}
info->lineno_filename = info->pending_lineno_filename;
}
 
if (! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
|| ! ieee_write_number (info, info->lineno_name_indx)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_number (info, 7)
|| ! ieee_write_number (info, info->pending_lineno)
|| ! ieee_write_number (info, 0)
|| ! ieee_write_asn (info, info->lineno_name_indx,
info->pending_lineno_addr))
return FALSE;
}
 
info->pending_lineno_filename = filename;
info->pending_lineno = lineno;
info->pending_lineno_addr = addr;
 
return TRUE;
}
/contrib/toolchain/binutils/binutils/not-strip.c
0,0 → 1,23
/* Copyright 2007 Free Software Foundation, Inc.
 
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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
/* Linked with objcopy.o to flag that this program is 'objcopy' (not
'strip'). */
 
int is_strip = 0;
/contrib/toolchain/binutils/binutils/objcopy.c
0,0 → 1,4293
/* objcopy.c -- copy object file from input to output, optionally massaging it.
Copyright 1991-2013 Free Software Foundation, Inc.
 
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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "sysdep.h"
#include "bfd.h"
#include "progress.h"
#include "getopt.h"
#include "libiberty.h"
#include "bucomm.h"
#include "budbg.h"
#include "filenames.h"
#include "fnmatch.h"
#include "elf-bfd.h"
#include "libbfd.h"
#include "coff/internal.h"
#include "libcoff.h"
 
/* FIXME: See bfd/peXXigen.c for why we include an architecture specific
header in generic PE code. */
#include "coff/i386.h"
#include "coff/pe.h"
 
static bfd_vma pe_file_alignment = (bfd_vma) -1;
static bfd_vma pe_heap_commit = (bfd_vma) -1;
static bfd_vma pe_heap_reserve = (bfd_vma) -1;
static bfd_vma pe_image_base = (bfd_vma) -1;
static bfd_vma pe_section_alignment = (bfd_vma) -1;
static bfd_vma pe_stack_commit = (bfd_vma) -1;
static bfd_vma pe_stack_reserve = (bfd_vma) -1;
static short pe_subsystem = -1;
static short pe_major_subsystem_version = -1;
static short pe_minor_subsystem_version = -1;
 
struct is_specified_symbol_predicate_data
{
const char *name;
bfd_boolean found;
};
 
/* A list to support redefine_sym. */
struct redefine_node
{
char *source;
char *target;
struct redefine_node *next;
};
 
typedef struct section_rename
{
const char * old_name;
const char * new_name;
flagword flags;
struct section_rename * next;
}
section_rename;
 
/* List of sections to be renamed. */
static section_rename *section_rename_list;
 
static asymbol **isympp = NULL; /* Input symbols. */
static asymbol **osympp = NULL; /* Output symbols that survive stripping. */
 
/* If `copy_byte' >= 0, copy 'copy_width' byte(s) of every `interleave' bytes. */
static int copy_byte = -1;
static int interleave = 0; /* Initialised to 4 in copy_main(). */
static int copy_width = 1;
 
static bfd_boolean verbose; /* Print file and target names. */
static bfd_boolean preserve_dates; /* Preserve input file timestamp. */
static int deterministic = -1; /* Enable deterministic archives. */
static int status = 0; /* Exit status. */
 
enum strip_action
{
STRIP_UNDEF,
STRIP_NONE, /* Don't strip. */
STRIP_DEBUG, /* Strip all debugger symbols. */
STRIP_UNNEEDED, /* Strip unnecessary symbols. */
STRIP_NONDEBUG, /* Strip everything but debug info. */
STRIP_DWO, /* Strip all DWO info. */
STRIP_NONDWO, /* Strip everything but DWO info. */
STRIP_ALL /* Strip all symbols. */
};
 
/* Which symbols to remove. */
static enum strip_action strip_symbols = STRIP_UNDEF;
 
enum locals_action
{
LOCALS_UNDEF,
LOCALS_START_L, /* Discard locals starting with L. */
LOCALS_ALL /* Discard all locals. */
};
 
/* Which local symbols to remove. Overrides STRIP_ALL. */
static enum locals_action discard_locals;
 
/* Structure used to hold lists of sections and actions to take. */
struct section_list
{
struct section_list * next; /* Next section to change. */
const char * pattern; /* Section name pattern. */
bfd_boolean used; /* Whether this entry was used. */
 
unsigned int context; /* What to do with matching sections. */
/* Flag bits used in the context field.
COPY and REMOVE are mutually exlusive. SET and ALTER are mutually exclusive. */
#define SECTION_CONTEXT_REMOVE (1 << 0) /* Remove this section. */
#define SECTION_CONTEXT_COPY (1 << 1) /* Copy this section, delete all non-copied section. */
#define SECTION_CONTEXT_SET_VMA (1 << 2) /* Set the sections' VMA address. */
#define SECTION_CONTEXT_ALTER_VMA (1 << 3) /* Increment or decrement the section's VMA address. */
#define SECTION_CONTEXT_SET_LMA (1 << 4) /* Set the sections' LMA address. */
#define SECTION_CONTEXT_ALTER_LMA (1 << 5) /* Increment or decrement the section's LMA address. */
#define SECTION_CONTEXT_SET_FLAGS (1 << 6) /* Set the section's flags. */
 
bfd_vma vma_val; /* Amount to change by or set to. */
bfd_vma lma_val; /* Amount to change by or set to. */
flagword flags; /* What to set the section flags to. */
};
 
static struct section_list *change_sections;
 
/* TRUE if some sections are to be removed. */
static bfd_boolean sections_removed;
 
/* TRUE if only some sections are to be copied. */
static bfd_boolean sections_copied;
 
/* Changes to the start address. */
static bfd_vma change_start = 0;
static bfd_boolean set_start_set = FALSE;
static bfd_vma set_start;
 
/* Changes to section addresses. */
static bfd_vma change_section_address = 0;
 
/* Filling gaps between sections. */
static bfd_boolean gap_fill_set = FALSE;
static bfd_byte gap_fill = 0;
 
/* Pad to a given address. */
static bfd_boolean pad_to_set = FALSE;
static bfd_vma pad_to;
 
/* Use alternative machine code? */
static unsigned long use_alt_mach_code = 0;
 
/* Output BFD flags user wants to set or clear */
static flagword bfd_flags_to_set;
static flagword bfd_flags_to_clear;
 
/* List of sections to add. */
struct section_add
{
/* Next section to add. */
struct section_add *next;
/* Name of section to add. */
const char *name;
/* Name of file holding section contents. */
const char *filename;
/* Size of file. */
size_t size;
/* Contents of file. */
bfd_byte *contents;
/* BFD section, after it has been added. */
asection *section;
};
 
/* List of sections to add to the output BFD. */
static struct section_add *add_sections;
 
/* If non-NULL the argument to --add-gnu-debuglink.
This should be the filename to store in the .gnu_debuglink section. */
static const char * gnu_debuglink_filename = NULL;
 
/* Whether to convert debugging information. */
static bfd_boolean convert_debugging = FALSE;
 
/* Whether to compress/decompress DWARF debug sections. */
static enum
{
nothing,
compress,
decompress
} do_debug_sections = nothing;
 
/* Whether to change the leading character in symbol names. */
static bfd_boolean change_leading_char = FALSE;
 
/* Whether to remove the leading character from global symbol names. */
static bfd_boolean remove_leading_char = FALSE;
 
/* Whether to permit wildcard in symbol comparison. */
static bfd_boolean wildcard = FALSE;
 
/* True if --localize-hidden is in effect. */
static bfd_boolean localize_hidden = FALSE;
 
/* List of symbols to strip, keep, localize, keep-global, weaken,
or redefine. */
static htab_t strip_specific_htab = NULL;
static htab_t strip_unneeded_htab = NULL;
static htab_t keep_specific_htab = NULL;
static htab_t localize_specific_htab = NULL;
static htab_t globalize_specific_htab = NULL;
static htab_t keepglobal_specific_htab = NULL;
static htab_t weaken_specific_htab = NULL;
static struct redefine_node *redefine_sym_list = NULL;
 
/* If this is TRUE, we weaken global symbols (set BSF_WEAK). */
static bfd_boolean weaken = FALSE;
 
/* If this is TRUE, we retain BSF_FILE symbols. */
static bfd_boolean keep_file_symbols = FALSE;
 
/* Prefix symbols/sections. */
static char *prefix_symbols_string = 0;
static char *prefix_sections_string = 0;
static char *prefix_alloc_sections_string = 0;
 
/* True if --extract-symbol was passed on the command line. */
static bfd_boolean extract_symbol = FALSE;
 
/* If `reverse_bytes' is nonzero, then reverse the order of every chunk
of <reverse_bytes> bytes within each output section. */
static int reverse_bytes = 0;
 
/* For Coff objects, we may want to allow or disallow long section names,
or preserve them where found in the inputs. Debug info relies on them. */
enum long_section_name_handling
{
DISABLE,
ENABLE,
KEEP
};
 
/* The default long section handling mode is to preserve them.
This is also the only behaviour for 'strip'. */
static enum long_section_name_handling long_section_names = KEEP;
 
/* 150 isn't special; it's just an arbitrary non-ASCII char value. */
enum command_line_switch
{
OPTION_ADD_SECTION=150,
OPTION_CHANGE_ADDRESSES,
OPTION_CHANGE_LEADING_CHAR,
OPTION_CHANGE_START,
OPTION_CHANGE_SECTION_ADDRESS,
OPTION_CHANGE_SECTION_LMA,
OPTION_CHANGE_SECTION_VMA,
OPTION_CHANGE_WARNINGS,
OPTION_COMPRESS_DEBUG_SECTIONS,
OPTION_DEBUGGING,
OPTION_DECOMPRESS_DEBUG_SECTIONS,
OPTION_GAP_FILL,
OPTION_NO_CHANGE_WARNINGS,
OPTION_PAD_TO,
OPTION_REMOVE_LEADING_CHAR,
OPTION_SET_SECTION_FLAGS,
OPTION_SET_START,
OPTION_STRIP_UNNEEDED,
OPTION_WEAKEN,
OPTION_REDEFINE_SYM,
OPTION_REDEFINE_SYMS,
OPTION_SREC_LEN,
OPTION_SREC_FORCES3,
OPTION_STRIP_SYMBOLS,
OPTION_STRIP_UNNEEDED_SYMBOL,
OPTION_STRIP_UNNEEDED_SYMBOLS,
OPTION_KEEP_SYMBOLS,
OPTION_LOCALIZE_HIDDEN,
OPTION_LOCALIZE_SYMBOLS,
OPTION_LONG_SECTION_NAMES,
OPTION_GLOBALIZE_SYMBOL,
OPTION_GLOBALIZE_SYMBOLS,
OPTION_KEEPGLOBAL_SYMBOLS,
OPTION_WEAKEN_SYMBOLS,
OPTION_RENAME_SECTION,
OPTION_ALT_MACH_CODE,
OPTION_PREFIX_SYMBOLS,
OPTION_PREFIX_SECTIONS,
OPTION_PREFIX_ALLOC_SECTIONS,
OPTION_FORMATS_INFO,
OPTION_ADD_GNU_DEBUGLINK,
OPTION_ONLY_KEEP_DEBUG,
OPTION_KEEP_FILE_SYMBOLS,
OPTION_READONLY_TEXT,
OPTION_WRITABLE_TEXT,
OPTION_PURE,
OPTION_IMPURE,
OPTION_EXTRACT_SYMBOL,
OPTION_REVERSE_BYTES,
OPTION_FILE_ALIGNMENT,
OPTION_HEAP,
OPTION_IMAGE_BASE,
OPTION_SECTION_ALIGNMENT,
OPTION_STACK,
OPTION_INTERLEAVE_WIDTH,
OPTION_SUBSYSTEM,
OPTION_EXTRACT_DWO,
OPTION_STRIP_DWO
};
 
/* Options to handle if running as "strip". */
 
static struct option strip_options[] =
{
{"disable-deterministic-archives", no_argument, 0, 'U'},
{"discard-all", no_argument, 0, 'x'},
{"discard-locals", no_argument, 0, 'X'},
{"enable-deterministic-archives", no_argument, 0, 'D'},
{"format", required_argument, 0, 'F'}, /* Obsolete */
{"help", no_argument, 0, 'h'},
{"info", no_argument, 0, OPTION_FORMATS_INFO},
{"input-format", required_argument, 0, 'I'}, /* Obsolete */
{"input-target", required_argument, 0, 'I'},
{"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
{"keep-symbol", required_argument, 0, 'K'},
{"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"output-target", required_argument, 0, 'O'},
{"output-file", required_argument, 0, 'o'},
{"preserve-dates", no_argument, 0, 'p'},
{"remove-section", required_argument, 0, 'R'},
{"strip-all", no_argument, 0, 's'},
{"strip-debug", no_argument, 0, 'S'},
{"strip-dwo", no_argument, 0, OPTION_STRIP_DWO},
{"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED},
{"strip-symbol", required_argument, 0, 'N'},
{"target", required_argument, 0, 'F'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"wildcard", no_argument, 0, 'w'},
{0, no_argument, 0, 0}
};
 
/* Options to handle if running as "objcopy". */
 
static struct option copy_options[] =
{
{"add-gnu-debuglink", required_argument, 0, OPTION_ADD_GNU_DEBUGLINK},
{"add-section", required_argument, 0, OPTION_ADD_SECTION},
{"adjust-start", required_argument, 0, OPTION_CHANGE_START},
{"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES},
{"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
{"adjust-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS},
{"alt-machine-code", required_argument, 0, OPTION_ALT_MACH_CODE},
{"binary-architecture", required_argument, 0, 'B'},
{"byte", required_argument, 0, 'b'},
{"change-addresses", required_argument, 0, OPTION_CHANGE_ADDRESSES},
{"change-leading-char", no_argument, 0, OPTION_CHANGE_LEADING_CHAR},
{"change-section-address", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
{"change-section-lma", required_argument, 0, OPTION_CHANGE_SECTION_LMA},
{"change-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_VMA},
{"change-start", required_argument, 0, OPTION_CHANGE_START},
{"change-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS},
{"compress-debug-sections", no_argument, 0, OPTION_COMPRESS_DEBUG_SECTIONS},
{"debugging", no_argument, 0, OPTION_DEBUGGING},
{"decompress-debug-sections", no_argument, 0, OPTION_DECOMPRESS_DEBUG_SECTIONS},
{"disable-deterministic-archives", no_argument, 0, 'U'},
{"discard-all", no_argument, 0, 'x'},
{"discard-locals", no_argument, 0, 'X'},
{"enable-deterministic-archives", no_argument, 0, 'D'},
{"extract-dwo", no_argument, 0, OPTION_EXTRACT_DWO},
{"extract-symbol", no_argument, 0, OPTION_EXTRACT_SYMBOL},
{"format", required_argument, 0, 'F'}, /* Obsolete */
{"gap-fill", required_argument, 0, OPTION_GAP_FILL},
{"globalize-symbol", required_argument, 0, OPTION_GLOBALIZE_SYMBOL},
{"globalize-symbols", required_argument, 0, OPTION_GLOBALIZE_SYMBOLS},
{"help", no_argument, 0, 'h'},
{"impure", no_argument, 0, OPTION_IMPURE},
{"info", no_argument, 0, OPTION_FORMATS_INFO},
{"input-format", required_argument, 0, 'I'}, /* Obsolete */
{"input-target", required_argument, 0, 'I'},
{"interleave", optional_argument, 0, 'i'},
{"interleave-width", required_argument, 0, OPTION_INTERLEAVE_WIDTH},
{"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
{"keep-global-symbol", required_argument, 0, 'G'},
{"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS},
{"keep-symbol", required_argument, 0, 'K'},
{"keep-symbols", required_argument, 0, OPTION_KEEP_SYMBOLS},
{"localize-hidden", no_argument, 0, OPTION_LOCALIZE_HIDDEN},
{"localize-symbol", required_argument, 0, 'L'},
{"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS},
{"long-section-names", required_argument, 0, OPTION_LONG_SECTION_NAMES},
{"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
{"no-change-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
{"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
{"only-section", required_argument, 0, 'j'},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"output-target", required_argument, 0, 'O'},
{"pad-to", required_argument, 0, OPTION_PAD_TO},
{"prefix-symbols", required_argument, 0, OPTION_PREFIX_SYMBOLS},
{"prefix-sections", required_argument, 0, OPTION_PREFIX_SECTIONS},
{"prefix-alloc-sections", required_argument, 0, OPTION_PREFIX_ALLOC_SECTIONS},
{"preserve-dates", no_argument, 0, 'p'},
{"pure", no_argument, 0, OPTION_PURE},
{"readonly-text", no_argument, 0, OPTION_READONLY_TEXT},
{"redefine-sym", required_argument, 0, OPTION_REDEFINE_SYM},
{"redefine-syms", required_argument, 0, OPTION_REDEFINE_SYMS},
{"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR},
{"remove-section", required_argument, 0, 'R'},
{"rename-section", required_argument, 0, OPTION_RENAME_SECTION},
{"reverse-bytes", required_argument, 0, OPTION_REVERSE_BYTES},
{"set-section-flags", required_argument, 0, OPTION_SET_SECTION_FLAGS},
{"set-start", required_argument, 0, OPTION_SET_START},
{"srec-len", required_argument, 0, OPTION_SREC_LEN},
{"srec-forceS3", no_argument, 0, OPTION_SREC_FORCES3},
{"strip-all", no_argument, 0, 'S'},
{"strip-debug", no_argument, 0, 'g'},
{"strip-dwo", no_argument, 0, OPTION_STRIP_DWO},
{"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED},
{"strip-unneeded-symbol", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOL},
{"strip-unneeded-symbols", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOLS},
{"strip-symbol", required_argument, 0, 'N'},
{"strip-symbols", required_argument, 0, OPTION_STRIP_SYMBOLS},
{"target", required_argument, 0, 'F'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"weaken", no_argument, 0, OPTION_WEAKEN},
{"weaken-symbol", required_argument, 0, 'W'},
{"weaken-symbols", required_argument, 0, OPTION_WEAKEN_SYMBOLS},
{"wildcard", no_argument, 0, 'w'},
{"writable-text", no_argument, 0, OPTION_WRITABLE_TEXT},
{"file-alignment", required_argument, 0, OPTION_FILE_ALIGNMENT},
{"heap", required_argument, 0, OPTION_HEAP},
{"image-base", required_argument, 0 , OPTION_IMAGE_BASE},
{"section-alignment", required_argument, 0, OPTION_SECTION_ALIGNMENT},
{"stack", required_argument, 0, OPTION_STACK},
{"subsystem", required_argument, 0, OPTION_SUBSYSTEM},
{0, no_argument, 0, 0}
};
 
/* IMPORTS */
extern char *program_name;
 
/* This flag distinguishes between strip and objcopy:
1 means this is 'strip'; 0 means this is 'objcopy'.
-1 means if we should use argv[0] to decide. */
extern int is_strip;
 
/* The maximum length of an S record. This variable is declared in srec.c
and can be modified by the --srec-len parameter. */
extern unsigned int Chunk;
 
/* Restrict the generation of Srecords to type S3 only.
This variable is declare in bfd/srec.c and can be toggled
on by the --srec-forceS3 command line switch. */
extern bfd_boolean S3Forced;
 
/* Forward declarations. */
static void setup_section (bfd *, asection *, void *);
static void setup_bfd_headers (bfd *, bfd *);
static void copy_relocations_in_section (bfd *, asection *, void *);
static void copy_section (bfd *, asection *, void *);
static void get_sections (bfd *, asection *, void *);
static int compare_section_lma (const void *, const void *);
static void mark_symbols_used_in_relocations (bfd *, asection *, void *);
static bfd_boolean write_debugging_info (bfd *, void *, long *, asymbol ***);
static const char *lookup_sym_redefinition (const char *);
static void
copy_usage (FILE *stream, int exit_status)
{
fprintf (stream, _("Usage: %s [option(s)] in-file [out-file]\n"), program_name);
fprintf (stream, _(" Copies a binary file, possibly transforming it in the process\n"));
fprintf (stream, _(" The options are:\n"));
fprintf (stream, _("\
-I --input-target <bfdname> Assume input file is in format <bfdname>\n\
-O --output-target <bfdname> Create an output file in format <bfdname>\n\
-B --binary-architecture <arch> Set output arch, when input is arch-less\n\
-F --target <bfdname> Set both input and output format to <bfdname>\n\
--debugging Convert debugging information, if possible\n\
-p --preserve-dates Copy modified/access timestamps to the output\n"));
if (DEFAULT_AR_DETERMINISTIC)
fprintf (stream, _("\
-D --enable-deterministic-archives\n\
Produce deterministic output when stripping archives (default)\n\
-U --disable-deterministic-archives\n\
Disable -D behavior\n"));
else
fprintf (stream, _("\
-D --enable-deterministic-archives\n\
Produce deterministic output when stripping archives\n\
-U --disable-deterministic-archives\n\
Disable -D behavior (default)\n"));
fprintf (stream, _("\
-j --only-section <name> Only copy section <name> into the output\n\
--add-gnu-debuglink=<file> Add section .gnu_debuglink linking to <file>\n\
-R --remove-section <name> Remove section <name> from the output\n\
-S --strip-all Remove all symbol and relocation information\n\
-g --strip-debug Remove all debugging symbols & sections\n\
--strip-dwo Remove all DWO sections\n\
--strip-unneeded Remove all symbols not needed by relocations\n\
-N --strip-symbol <name> Do not copy symbol <name>\n\
--strip-unneeded-symbol <name>\n\
Do not copy symbol <name> unless needed by\n\
relocations\n\
--only-keep-debug Strip everything but the debug information\n\
--extract-dwo Copy only DWO sections\n\
--extract-symbol Remove section contents but keep symbols\n\
-K --keep-symbol <name> Do not strip symbol <name>\n\
--keep-file-symbols Do not strip file symbol(s)\n\
--localize-hidden Turn all ELF hidden symbols into locals\n\
-L --localize-symbol <name> Force symbol <name> to be marked as a local\n\
--globalize-symbol <name> Force symbol <name> to be marked as a global\n\
-G --keep-global-symbol <name> Localize all symbols except <name>\n\
-W --weaken-symbol <name> Force symbol <name> to be marked as a weak\n\
--weaken Force all global symbols to be marked as weak\n\
-w --wildcard Permit wildcard in symbol comparison\n\
-x --discard-all Remove all non-global symbols\n\
-X --discard-locals Remove any compiler-generated symbols\n\
-i --interleave [<number>] Only copy N out of every <number> bytes\n\
--interleave-width <number> Set N for --interleave\n\
-b --byte <num> Select byte <num> in every interleaved block\n\
--gap-fill <val> Fill gaps between sections with <val>\n\
--pad-to <addr> Pad the last section up to address <addr>\n\
--set-start <addr> Set the start address to <addr>\n\
{--change-start|--adjust-start} <incr>\n\
Add <incr> to the start address\n\
{--change-addresses|--adjust-vma} <incr>\n\
Add <incr> to LMA, VMA and start addresses\n\
{--change-section-address|--adjust-section-vma} <name>{=|+|-}<val>\n\
Change LMA and VMA of section <name> by <val>\n\
--change-section-lma <name>{=|+|-}<val>\n\
Change the LMA of section <name> by <val>\n\
--change-section-vma <name>{=|+|-}<val>\n\
Change the VMA of section <name> by <val>\n\
{--[no-]change-warnings|--[no-]adjust-warnings}\n\
Warn if a named section does not exist\n\
--set-section-flags <name>=<flags>\n\
Set section <name>'s properties to <flags>\n\
--add-section <name>=<file> Add section <name> found in <file> to output\n\
--rename-section <old>=<new>[,<flags>] Rename section <old> to <new>\n\
--long-section-names {enable|disable|keep}\n\
Handle long section names in Coff objects.\n\
--change-leading-char Force output format's leading character style\n\
--remove-leading-char Remove leading character from global symbols\n\
--reverse-bytes=<num> Reverse <num> bytes at a time, in output sections with content\n\
--redefine-sym <old>=<new> Redefine symbol name <old> to <new>\n\
--redefine-syms <file> --redefine-sym for all symbol pairs \n\
listed in <file>\n\
--srec-len <number> Restrict the length of generated Srecords\n\
--srec-forceS3 Restrict the type of generated Srecords to S3\n\
--strip-symbols <file> -N for all symbols listed in <file>\n\
--strip-unneeded-symbols <file>\n\
--strip-unneeded-symbol for all symbols listed\n\
in <file>\n\
--keep-symbols <file> -K for all symbols listed in <file>\n\
--localize-symbols <file> -L for all symbols listed in <file>\n\
--globalize-symbols <file> --globalize-symbol for all in <file>\n\
--keep-global-symbols <file> -G for all symbols listed in <file>\n\
--weaken-symbols <file> -W for all symbols listed in <file>\n\
--alt-machine-code <index> Use the target's <index>'th alternative machine\n\
--writable-text Mark the output text as writable\n\
--readonly-text Make the output text write protected\n\
--pure Mark the output file as demand paged\n\
--impure Mark the output file as impure\n\
--prefix-symbols <prefix> Add <prefix> to start of every symbol name\n\
--prefix-sections <prefix> Add <prefix> to start of every section name\n\
--prefix-alloc-sections <prefix>\n\
Add <prefix> to start of every allocatable\n\
section name\n\
--file-alignment <num> Set PE file alignment to <num>\n\
--heap <reserve>[,<commit>] Set PE reserve/commit heap to <reserve>/\n\
<commit>\n\
--image-base <address> Set PE image base to <address>\n\
--section-alignment <num> Set PE section alignment to <num>\n\
--stack <reserve>[,<commit>] Set PE reserve/commit stack to <reserve>/\n\
<commit>\n\
--subsystem <name>[:<version>]\n\
Set PE subsystem to <name> [& <version>]\n\
--compress-debug-sections Compress DWARF debug sections using zlib\n\
--decompress-debug-sections Decompress DWARF debug sections using zlib\n\
-v --verbose List all object files modified\n\
@<file> Read options from <file>\n\
-V --version Display this program's version number\n\
-h --help Display this output\n\
--info List object formats & architectures supported\n\
"));
list_supported_targets (program_name, stream);
if (REPORT_BUGS_TO[0] && exit_status == 0)
fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
exit (exit_status);
}
 
static void
strip_usage (FILE *stream, int exit_status)
{
fprintf (stream, _("Usage: %s <option(s)> in-file(s)\n"), program_name);
fprintf (stream, _(" Removes symbols and sections from files\n"));
fprintf (stream, _(" The options are:\n"));
fprintf (stream, _("\
-I --input-target=<bfdname> Assume input file is in format <bfdname>\n\
-O --output-target=<bfdname> Create an output file in format <bfdname>\n\
-F --target=<bfdname> Set both input and output format to <bfdname>\n\
-p --preserve-dates Copy modified/access timestamps to the output\n\
"));
if (DEFAULT_AR_DETERMINISTIC)
fprintf (stream, _("\
-D --enable-deterministic-archives\n\
Produce deterministic output when stripping archives (default)\n\
-U --disable-deterministic-archives\n\
Disable -D behavior\n"));
else
fprintf (stream, _("\
-D --enable-deterministic-archives\n\
Produce deterministic output when stripping archives\n\
-U --disable-deterministic-archives\n\
Disable -D behavior (default)\n"));
fprintf (stream, _("\
-R --remove-section=<name> Remove section <name> from the output\n\
-s --strip-all Remove all symbol and relocation information\n\
-g -S -d --strip-debug Remove all debugging symbols & sections\n\
--strip-dwo Remove all DWO sections\n\
--strip-unneeded Remove all symbols not needed by relocations\n\
--only-keep-debug Strip everything but the debug information\n\
-N --strip-symbol=<name> Do not copy symbol <name>\n\
-K --keep-symbol=<name> Do not strip symbol <name>\n\
--keep-file-symbols Do not strip file symbol(s)\n\
-w --wildcard Permit wildcard in symbol comparison\n\
-x --discard-all Remove all non-global symbols\n\
-X --discard-locals Remove any compiler-generated symbols\n\
-v --verbose List all object files modified\n\
-V --version Display this program's version number\n\
-h --help Display this output\n\
--info List object formats & architectures supported\n\
-o <file> Place stripped output into <file>\n\
"));
 
list_supported_targets (program_name, stream);
if (REPORT_BUGS_TO[0] && exit_status == 0)
fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
exit (exit_status);
}
 
/* Parse section flags into a flagword, with a fatal error if the
string can't be parsed. */
 
static flagword
parse_flags (const char *s)
{
flagword ret;
const char *snext;
int len;
 
ret = SEC_NO_FLAGS;
 
do
{
snext = strchr (s, ',');
if (snext == NULL)
len = strlen (s);
else
{
len = snext - s;
++snext;
}
 
if (0) ;
#define PARSE_FLAG(fname,fval) \
else if (strncasecmp (fname, s, len) == 0) ret |= fval
PARSE_FLAG ("alloc", SEC_ALLOC);
PARSE_FLAG ("load", SEC_LOAD);
PARSE_FLAG ("noload", SEC_NEVER_LOAD);
PARSE_FLAG ("readonly", SEC_READONLY);
PARSE_FLAG ("debug", SEC_DEBUGGING);
PARSE_FLAG ("code", SEC_CODE);
PARSE_FLAG ("data", SEC_DATA);
PARSE_FLAG ("rom", SEC_ROM);
PARSE_FLAG ("share", SEC_COFF_SHARED);
PARSE_FLAG ("contents", SEC_HAS_CONTENTS);
PARSE_FLAG ("merge", SEC_MERGE);
PARSE_FLAG ("strings", SEC_STRINGS);
#undef PARSE_FLAG
else
{
char *copy;
 
copy = (char *) xmalloc (len + 1);
strncpy (copy, s, len);
copy[len] = '\0';
non_fatal (_("unrecognized section flag `%s'"), copy);
fatal (_("supported flags: %s"),
"alloc, load, noload, readonly, debug, code, data, rom, share, contents, merge, strings");
}
 
s = snext;
}
while (s != NULL);
 
return ret;
}
 
/* Find and optionally add an entry in the change_sections list.
 
We need to be careful in how we match section names because of the support
for wildcard characters. For example suppose that the user has invoked
objcopy like this:
 
--set-section-flags .debug_*=debug
--set-section-flags .debug_str=readonly,debug
--change-section-address .debug_*ranges=0x1000
 
With the idea that all debug sections will receive the DEBUG flag, the
.debug_str section will also receive the READONLY flag and the
.debug_ranges and .debug_aranges sections will have their address set to
0x1000. (This may not make much sense, but it is just an example).
 
When adding the section name patterns to the section list we need to make
sure that previous entries do not match with the new entry, unless the
match is exact. (In which case we assume that the user is overriding
the previous entry with the new context).
 
When matching real section names to the section list we make use of the
wildcard characters, but we must do so in context. Eg if we are setting
section addresses then we match for .debug_ranges but not for .debug_info.
 
Finally, if ADD is false and we do find a match, we mark the section list
entry as used. */
 
static struct section_list *
find_section_list (const char *name, bfd_boolean add, unsigned int context)
{
struct section_list *p;
 
/* assert ((context & ((1 << 7) - 1)) != 0); */
 
for (p = change_sections; p != NULL; p = p->next)
{
if (add)
{
if (strcmp (p->pattern, name) == 0)
{
/* Check for context conflicts. */
if (((p->context & SECTION_CONTEXT_REMOVE)
&& (context & SECTION_CONTEXT_COPY))
|| ((context & SECTION_CONTEXT_REMOVE)
&& (p->context & SECTION_CONTEXT_COPY)))
fatal (_("error: %s both copied and removed"), name);
 
if (((p->context & SECTION_CONTEXT_SET_VMA)
&& (context & SECTION_CONTEXT_ALTER_VMA))
|| ((context & SECTION_CONTEXT_SET_VMA)
&& (context & SECTION_CONTEXT_ALTER_VMA)))
fatal (_("error: %s both sets and alters VMA"), name);
 
if (((p->context & SECTION_CONTEXT_SET_LMA)
&& (context & SECTION_CONTEXT_ALTER_LMA))
|| ((context & SECTION_CONTEXT_SET_LMA)
&& (context & SECTION_CONTEXT_ALTER_LMA)))
fatal (_("error: %s both sets and alters LMA"), name);
 
/* Extend the context. */
p->context |= context;
return p;
}
}
/* If we are not adding a new name/pattern then
only check for a match if the context applies. */
else if ((p->context & context)
/* We could check for the presence of wildchar characters
first and choose between calling strcmp and fnmatch,
but is that really worth it ? */
&& fnmatch (p->pattern, name, 0) == 0)
{
p->used = TRUE;
return p;
}
}
 
if (! add)
return NULL;
 
p = (struct section_list *) xmalloc (sizeof (struct section_list));
p->pattern = name;
p->used = FALSE;
p->context = context;
p->vma_val = 0;
p->lma_val = 0;
p->flags = 0;
p->next = change_sections;
change_sections = p;
 
return p;
}
 
/* There is htab_hash_string but no htab_eq_string. Makes sense. */
 
static int
eq_string (const void *s1, const void *s2)
{
return strcmp ((const char *) s1, (const char *) s2) == 0;
}
 
static htab_t
create_symbol_htab (void)
{
return htab_create_alloc (16, htab_hash_string, eq_string, NULL, xcalloc, free);
}
 
static void
create_symbol_htabs (void)
{
strip_specific_htab = create_symbol_htab ();
strip_unneeded_htab = create_symbol_htab ();
keep_specific_htab = create_symbol_htab ();
localize_specific_htab = create_symbol_htab ();
globalize_specific_htab = create_symbol_htab ();
keepglobal_specific_htab = create_symbol_htab ();
weaken_specific_htab = create_symbol_htab ();
}
 
/* Add a symbol to strip_specific_list. */
 
static void
add_specific_symbol (const char *name, htab_t htab)
{
*htab_find_slot (htab, name, INSERT) = (char *) name;
}
 
/* Add symbols listed in `filename' to strip_specific_list. */
 
#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t')
#define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
 
static void
add_specific_symbols (const char *filename, htab_t htab)
{
off_t size;
FILE * f;
char * line;
char * buffer;
unsigned int line_count;
 
size = get_file_size (filename);
if (size == 0)
{
status = 1;
return;
}
 
buffer = (char *) xmalloc (size + 2);
f = fopen (filename, FOPEN_RT);
if (f == NULL)
fatal (_("cannot open '%s': %s"), filename, strerror (errno));
 
if (fread (buffer, 1, size, f) == 0 || ferror (f))
fatal (_("%s: fread failed"), filename);
 
fclose (f);
buffer [size] = '\n';
buffer [size + 1] = '\0';
 
line_count = 1;
 
for (line = buffer; * line != '\0'; line ++)
{
char * eol;
char * name;
char * name_end;
int finished = FALSE;
 
for (eol = line;; eol ++)
{
switch (* eol)
{
case '\n':
* eol = '\0';
/* Cope with \n\r. */
if (eol[1] == '\r')
++ eol;
finished = TRUE;
break;
 
case '\r':
* eol = '\0';
/* Cope with \r\n. */
if (eol[1] == '\n')
++ eol;
finished = TRUE;
break;
 
case 0:
finished = TRUE;
break;
 
case '#':
/* Line comment, Terminate the line here, in case a
name is present and then allow the rest of the
loop to find the real end of the line. */
* eol = '\0';
break;
 
default:
break;
}
 
if (finished)
break;
}
 
/* A name may now exist somewhere between 'line' and 'eol'.
Strip off leading whitespace and trailing whitespace,
then add it to the list. */
for (name = line; IS_WHITESPACE (* name); name ++)
;
for (name_end = name;
(! IS_WHITESPACE (* name_end))
&& (! IS_LINE_TERMINATOR (* name_end));
name_end ++)
;
 
if (! IS_LINE_TERMINATOR (* name_end))
{
char * extra;
 
for (extra = name_end + 1; IS_WHITESPACE (* extra); extra ++)
;
 
if (! IS_LINE_TERMINATOR (* extra))
non_fatal (_("%s:%d: Ignoring rubbish found on this line"),
filename, line_count);
}
 
* name_end = '\0';
 
if (name_end > name)
add_specific_symbol (name, htab);
 
/* Advance line pointer to end of line. The 'eol ++' in the for
loop above will then advance us to the start of the next line. */
line = eol;
line_count ++;
}
}
 
/* See whether a symbol should be stripped or kept
based on strip_specific_list and keep_symbols. */
 
static int
is_specified_symbol_predicate (void **slot, void *data)
{
struct is_specified_symbol_predicate_data *d =
(struct is_specified_symbol_predicate_data *) data;
const char *slot_name = (char *) *slot;
 
if (*slot_name != '!')
{
if (! fnmatch (slot_name, d->name, 0))
{
d->found = TRUE;
/* Stop traversal. */
return 0;
}
}
else
{
if (fnmatch (slot_name + 1, d->name, 0))
{
d->found = TRUE;
/* Stop traversal. */
return 0;
}
}
 
/* Continue traversal. */
return 1;
}
 
static bfd_boolean
is_specified_symbol (const char *name, htab_t htab)
{
if (wildcard)
{
struct is_specified_symbol_predicate_data data;
 
data.name = name;
data.found = FALSE;
 
htab_traverse (htab, is_specified_symbol_predicate, &data);
 
return data.found;
}
 
return htab_find (htab, name) != NULL;
}
 
/* Return a pointer to the symbol used as a signature for GROUP. */
 
static asymbol *
group_signature (asection *group)
{
bfd *abfd = group->owner;
Elf_Internal_Shdr *ghdr;
 
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
return NULL;
 
ghdr = &elf_section_data (group)->this_hdr;
if (ghdr->sh_link < elf_numsections (abfd))
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
Elf_Internal_Shdr *symhdr = elf_elfsections (abfd) [ghdr->sh_link];
 
if (symhdr->sh_type == SHT_SYMTAB
&& ghdr->sh_info < symhdr->sh_size / bed->s->sizeof_sym)
return isympp[ghdr->sh_info - 1];
}
return NULL;
}
 
/* Return TRUE if the section is a DWO section. */
 
static bfd_boolean
is_dwo_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
{
const char *name = bfd_get_section_name (abfd, sec);
int len = strlen (name);
 
return strncmp (name + len - 4, ".dwo", 4) == 0;
}
 
/* See if a non-group section is being removed. */
 
static bfd_boolean
is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
{
if (sections_removed || sections_copied)
{
struct section_list *p;
struct section_list *q;
 
p = find_section_list (bfd_get_section_name (abfd, sec), FALSE,
SECTION_CONTEXT_REMOVE);
q = find_section_list (bfd_get_section_name (abfd, sec), FALSE,
SECTION_CONTEXT_COPY);
 
if (p && q)
fatal (_("error: section %s matches both remove and copy options"),
bfd_get_section_name (abfd, sec));
 
if (p != NULL)
return TRUE;
if (sections_copied && q == NULL)
return TRUE;
}
 
if ((bfd_get_section_flags (abfd, sec) & SEC_DEBUGGING) != 0)
{
if (strip_symbols == STRIP_DEBUG
|| strip_symbols == STRIP_UNNEEDED
|| strip_symbols == STRIP_ALL
|| discard_locals == LOCALS_ALL
|| convert_debugging)
{
/* By default we don't want to strip .reloc section.
This section has for pe-coff special meaning. See
pe-dll.c file in ld, and peXXigen.c in bfd for details. */
if (strcmp (bfd_get_section_name (abfd, sec), ".reloc") != 0)
return TRUE;
}
 
if (strip_symbols == STRIP_DWO)
return is_dwo_section (abfd, sec);
 
if (strip_symbols == STRIP_NONDEBUG)
return FALSE;
}
 
if (strip_symbols == STRIP_NONDWO)
return !is_dwo_section (abfd, sec);
 
return FALSE;
}
 
/* See if a section is being removed. */
 
static bfd_boolean
is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
{
if (is_strip_section_1 (abfd, sec))
return TRUE;
 
if ((bfd_get_section_flags (abfd, sec) & SEC_GROUP) != 0)
{
asymbol *gsym;
const char *gname;
asection *elt, *first;
 
/* PR binutils/3181
If we are going to strip the group signature symbol, then
strip the group section too. */
gsym = group_signature (sec);
if (gsym != NULL)
gname = gsym->name;
else
gname = sec->name;
if ((strip_symbols == STRIP_ALL
&& !is_specified_symbol (gname, keep_specific_htab))
|| is_specified_symbol (gname, strip_specific_htab))
return TRUE;
 
/* Remove the group section if all members are removed. */
first = elt = elf_next_in_group (sec);
while (elt != NULL)
{
if (!is_strip_section_1 (abfd, elt))
return FALSE;
elt = elf_next_in_group (elt);
if (elt == first)
break;
}
 
return TRUE;
}
 
return FALSE;
}
 
/* Return true if SYM is a hidden symbol. */
 
static bfd_boolean
is_hidden_symbol (asymbol *sym)
{
elf_symbol_type *elf_sym;
 
elf_sym = elf_symbol_from (sym->the_bfd, sym);
if (elf_sym != NULL)
switch (ELF_ST_VISIBILITY (elf_sym->internal_elf_sym.st_other))
{
case STV_HIDDEN:
case STV_INTERNAL:
return TRUE;
}
return FALSE;
}
 
/* Choose which symbol entries to copy; put the result in OSYMS.
We don't copy in place, because that confuses the relocs.
Return the number of symbols to print. */
 
static unsigned int
filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
asymbol **isyms, long symcount)
{
asymbol **from = isyms, **to = osyms;
long src_count = 0, dst_count = 0;
int relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
 
for (; src_count < symcount; src_count++)
{
asymbol *sym = from[src_count];
flagword flags = sym->flags;
char *name = (char *) bfd_asymbol_name (sym);
bfd_boolean keep;
bfd_boolean used_in_reloc = FALSE;
bfd_boolean undefined;
bfd_boolean rem_leading_char;
bfd_boolean add_leading_char;
 
undefined = bfd_is_und_section (bfd_get_section (sym));
 
if (redefine_sym_list)
{
char *old_name, *new_name;
 
old_name = (char *) bfd_asymbol_name (sym);
new_name = (char *) lookup_sym_redefinition (old_name);
bfd_asymbol_name (sym) = new_name;
name = new_name;
}
 
/* Check if we will remove the current leading character. */
rem_leading_char =
(name[0] == bfd_get_symbol_leading_char (abfd))
&& (change_leading_char
|| (remove_leading_char
&& ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
|| undefined
|| bfd_is_com_section (bfd_get_section (sym)))));
 
/* Check if we will add a new leading character. */
add_leading_char =
change_leading_char
&& (bfd_get_symbol_leading_char (obfd) != '\0')
&& (bfd_get_symbol_leading_char (abfd) == '\0'
|| (name[0] == bfd_get_symbol_leading_char (abfd)));
 
/* Short circuit for change_leading_char if we can do it in-place. */
if (rem_leading_char && add_leading_char && !prefix_symbols_string)
{
name[0] = bfd_get_symbol_leading_char (obfd);
bfd_asymbol_name (sym) = name;
rem_leading_char = FALSE;
add_leading_char = FALSE;
}
 
/* Remove leading char. */
if (rem_leading_char)
bfd_asymbol_name (sym) = ++name;
 
/* Add new leading char and/or prefix. */
if (add_leading_char || prefix_symbols_string)
{
char *n, *ptr;
 
ptr = n = (char *) xmalloc (1 + strlen (prefix_symbols_string)
+ strlen (name) + 1);
if (add_leading_char)
*ptr++ = bfd_get_symbol_leading_char (obfd);
 
if (prefix_symbols_string)
{
strcpy (ptr, prefix_symbols_string);
ptr += strlen (prefix_symbols_string);
}
 
strcpy (ptr, name);
bfd_asymbol_name (sym) = n;
name = n;
}
 
if (strip_symbols == STRIP_ALL)
keep = FALSE;
else if ((flags & BSF_KEEP) != 0 /* Used in relocation. */
|| ((flags & BSF_SECTION_SYM) != 0
&& ((*bfd_get_section (sym)->symbol_ptr_ptr)->flags
& BSF_KEEP) != 0))
{
keep = TRUE;
used_in_reloc = TRUE;
}
else if (relocatable /* Relocatable file. */
&& ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
|| bfd_is_com_section (bfd_get_section (sym))))
keep = TRUE;
else if (bfd_decode_symclass (sym) == 'I')
/* Global symbols in $idata sections need to be retained
even if relocatable is FALSE. External users of the
library containing the $idata section may reference these
symbols. */
keep = TRUE;
else if ((flags & BSF_GLOBAL) != 0 /* Global symbol. */
|| (flags & BSF_WEAK) != 0
|| undefined
|| bfd_is_com_section (bfd_get_section (sym)))
keep = strip_symbols != STRIP_UNNEEDED;
else if ((flags & BSF_DEBUGGING) != 0) /* Debugging symbol. */
keep = (strip_symbols != STRIP_DEBUG
&& strip_symbols != STRIP_UNNEEDED
&& ! convert_debugging);
else if (bfd_coff_get_comdat_section (abfd, bfd_get_section (sym)))
/* COMDAT sections store special information in local
symbols, so we cannot risk stripping any of them. */
keep = TRUE;
else /* Local symbol. */
keep = (strip_symbols != STRIP_UNNEEDED
&& (discard_locals != LOCALS_ALL
&& (discard_locals != LOCALS_START_L
|| ! bfd_is_local_label (abfd, sym))));
 
if (keep && is_specified_symbol (name, strip_specific_htab))
{
/* There are multiple ways to set 'keep' above, but if it
was the relocatable symbol case, then that's an error. */
if (used_in_reloc)
{
non_fatal (_("not stripping symbol `%s' because it is named in a relocation"), name);
status = 1;
}
else
keep = FALSE;
}
 
if (keep
&& !(flags & BSF_KEEP)
&& is_specified_symbol (name, strip_unneeded_htab))
keep = FALSE;
 
if (!keep
&& ((keep_file_symbols && (flags & BSF_FILE))
|| is_specified_symbol (name, keep_specific_htab)))
keep = TRUE;
 
if (keep && is_strip_section (abfd, bfd_get_section (sym)))
keep = FALSE;
 
if (keep)
{
if ((flags & BSF_GLOBAL) != 0
&& (weaken || is_specified_symbol (name, weaken_specific_htab)))
{
sym->flags &= ~ BSF_GLOBAL;
sym->flags |= BSF_WEAK;
}
 
if (!undefined
&& (flags & (BSF_GLOBAL | BSF_WEAK))
&& (is_specified_symbol (name, localize_specific_htab)
|| (htab_elements (keepglobal_specific_htab) != 0
&& ! is_specified_symbol (name, keepglobal_specific_htab))
|| (localize_hidden && is_hidden_symbol (sym))))
{
sym->flags &= ~ (BSF_GLOBAL | BSF_WEAK);
sym->flags |= BSF_LOCAL;
}
 
if (!undefined
&& (flags & BSF_LOCAL)
&& is_specified_symbol (name, globalize_specific_htab))
{
sym->flags &= ~ BSF_LOCAL;
sym->flags |= BSF_GLOBAL;
}
 
to[dst_count++] = sym;
}
}
 
to[dst_count] = NULL;
 
return dst_count;
}
 
/* Find the redefined name of symbol SOURCE. */
 
static const char *
lookup_sym_redefinition (const char *source)
{
struct redefine_node *list;
 
for (list = redefine_sym_list; list != NULL; list = list->next)
if (strcmp (source, list->source) == 0)
return list->target;
 
return source;
}
 
/* Add a node to a symbol redefine list. */
 
static void
redefine_list_append (const char *cause, const char *source, const char *target)
{
struct redefine_node **p;
struct redefine_node *list;
struct redefine_node *new_node;
 
for (p = &redefine_sym_list; (list = *p) != NULL; p = &list->next)
{
if (strcmp (source, list->source) == 0)
fatal (_("%s: Multiple redefinition of symbol \"%s\""),
cause, source);
 
if (strcmp (target, list->target) == 0)
fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"),
cause, target);
}
 
new_node = (struct redefine_node *) xmalloc (sizeof (struct redefine_node));
 
new_node->source = strdup (source);
new_node->target = strdup (target);
new_node->next = NULL;
 
*p = new_node;
}
 
/* Handle the --redefine-syms option. Read lines containing "old new"
from the file, and add them to the symbol redefine list. */
 
static void
add_redefine_syms_file (const char *filename)
{
FILE *file;
char *buf;
size_t bufsize;
size_t len;
size_t outsym_off;
int c, lineno;
 
file = fopen (filename, "r");
if (file == NULL)
fatal (_("couldn't open symbol redefinition file %s (error: %s)"),
filename, strerror (errno));
 
bufsize = 100;
buf = (char *) xmalloc (bufsize + 1 /* For the terminating NUL. */);
 
lineno = 1;
c = getc (file);
len = 0;
outsym_off = 0;
while (c != EOF)
{
/* Collect the input symbol name. */
while (! IS_WHITESPACE (c) && ! IS_LINE_TERMINATOR (c) && c != EOF)
{
if (c == '#')
goto comment;
buf[len++] = c;
if (len >= bufsize)
{
bufsize *= 2;
buf = (char *) xrealloc (buf, bufsize + 1);
}
c = getc (file);
}
buf[len++] = '\0';
if (c == EOF)
break;
 
/* Eat white space between the symbol names. */
while (IS_WHITESPACE (c))
c = getc (file);
if (c == '#' || IS_LINE_TERMINATOR (c))
goto comment;
if (c == EOF)
break;
 
/* Collect the output symbol name. */
outsym_off = len;
while (! IS_WHITESPACE (c) && ! IS_LINE_TERMINATOR (c) && c != EOF)
{
if (c == '#')
goto comment;
buf[len++] = c;
if (len >= bufsize)
{
bufsize *= 2;
buf = (char *) xrealloc (buf, bufsize + 1);
}
c = getc (file);
}
buf[len++] = '\0';
if (c == EOF)
break;
 
/* Eat white space at end of line. */
while (! IS_LINE_TERMINATOR(c) && c != EOF && IS_WHITESPACE (c))
c = getc (file);
if (c == '#')
goto comment;
/* Handle \r\n. */
if ((c == '\r' && (c = getc (file)) == '\n')
|| c == '\n' || c == EOF)
{
end_of_line:
/* Append the redefinition to the list. */
if (buf[0] != '\0')
redefine_list_append (filename, &buf[0], &buf[outsym_off]);
 
lineno++;
len = 0;
outsym_off = 0;
if (c == EOF)
break;
c = getc (file);
continue;
}
else
fatal (_("%s:%d: garbage found at end of line"), filename, lineno);
comment:
if (len != 0 && (outsym_off == 0 || outsym_off == len))
fatal (_("%s:%d: missing new symbol name"), filename, lineno);
buf[len++] = '\0';
 
/* Eat the rest of the line and finish it. */
while (c != '\n' && c != EOF)
c = getc (file);
goto end_of_line;
}
 
if (len != 0)
fatal (_("%s:%d: premature end of file"), filename, lineno);
 
free (buf);
}
 
/* Copy unkown object file IBFD onto OBFD.
Returns TRUE upon success, FALSE otherwise. */
 
static bfd_boolean
copy_unknown_object (bfd *ibfd, bfd *obfd)
{
char *cbuf;
int tocopy;
long ncopied;
long size;
struct stat buf;
 
if (bfd_stat_arch_elt (ibfd, &buf) != 0)
{
bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
return FALSE;
}
 
size = buf.st_size;
if (size < 0)
{
non_fatal (_("stat returns negative size for `%s'"),
bfd_get_archive_filename (ibfd));
return FALSE;
}
 
if (bfd_seek (ibfd, (file_ptr) 0, SEEK_SET) != 0)
{
bfd_nonfatal (bfd_get_archive_filename (ibfd));
return FALSE;
}
 
if (verbose)
printf (_("copy from `%s' [unknown] to `%s' [unknown]\n"),
bfd_get_archive_filename (ibfd), bfd_get_filename (obfd));
 
cbuf = (char *) xmalloc (BUFSIZE);
ncopied = 0;
while (ncopied < size)
{
tocopy = size - ncopied;
if (tocopy > BUFSIZE)
tocopy = BUFSIZE;
 
if (bfd_bread (cbuf, (bfd_size_type) tocopy, ibfd)
!= (bfd_size_type) tocopy)
{
bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
free (cbuf);
return FALSE;
}
 
if (bfd_bwrite (cbuf, (bfd_size_type) tocopy, obfd)
!= (bfd_size_type) tocopy)
{
bfd_nonfatal_message (NULL, obfd, NULL, NULL);
free (cbuf);
return FALSE;
}
 
ncopied += tocopy;
}
 
/* We should at least to be able to read it back when copying an
unknown object in an archive. */
// chmod (bfd_get_filename (obfd), buf.st_mode | S_IRUSR);
free (cbuf);
return TRUE;
}
 
/* Copy object file IBFD onto OBFD.
Returns TRUE upon success, FALSE otherwise. */
 
static bfd_boolean
copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
{
bfd_vma start;
long symcount;
asection **osections = NULL;
asection *gnu_debuglink_section = NULL;
bfd_size_type *gaps = NULL;
bfd_size_type max_gap = 0;
long symsize;
void *dhandle;
enum bfd_architecture iarch;
unsigned int imach;
 
if (ibfd->xvec->byteorder != obfd->xvec->byteorder
&& ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN
&& obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
fatal (_("Unable to change endianness of input file(s)"));
 
if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
{
bfd_nonfatal_message (NULL, obfd, NULL, NULL);
return FALSE;
}
 
if (verbose)
printf (_("copy from `%s' [%s] to `%s' [%s]\n"),
bfd_get_archive_filename (ibfd), bfd_get_target (ibfd),
bfd_get_filename (obfd), bfd_get_target (obfd));
 
if (extract_symbol)
start = 0;
else
{
if (set_start_set)
start = set_start;
else
start = bfd_get_start_address (ibfd);
start += change_start;
}
 
/* Neither the start address nor the flags
need to be set for a core file. */
if (bfd_get_format (obfd) != bfd_core)
{
flagword flags;
 
flags = bfd_get_file_flags (ibfd);
flags |= bfd_flags_to_set;
flags &= ~bfd_flags_to_clear;
flags &= bfd_applicable_file_flags (obfd);
 
if (strip_symbols == STRIP_ALL)
flags &= ~HAS_RELOC;
 
if (!bfd_set_start_address (obfd, start)
|| !bfd_set_file_flags (obfd, flags))
{
bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
return FALSE;
}
}
 
/* Copy architecture of input file to output file. */
iarch = bfd_get_arch (ibfd);
imach = bfd_get_mach (ibfd);
if (input_arch)
{
if (bfd_get_arch_info (ibfd) == NULL
|| bfd_get_arch_info (ibfd)->arch == bfd_arch_unknown)
{
iarch = input_arch->arch;
imach = input_arch->mach;
}
else
non_fatal (_("Input file `%s' ignores binary architecture parameter."),
bfd_get_archive_filename (ibfd));
}
if (!bfd_set_arch_mach (obfd, iarch, imach)
&& (ibfd->target_defaulted
|| bfd_get_arch (ibfd) != bfd_get_arch (obfd)))
{
if (bfd_get_arch (ibfd) == bfd_arch_unknown)
non_fatal (_("Unable to recognise the format of the input file `%s'"),
bfd_get_archive_filename (ibfd));
else
non_fatal (_("Output file cannot represent architecture `%s'"),
bfd_printable_arch_mach (bfd_get_arch (ibfd),
bfd_get_mach (ibfd)));
return FALSE;
}
 
if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
{
bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
return FALSE;
}
 
if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
&& bfd_pei_p (obfd))
{
/* Set up PE parameters. */
pe_data_type *pe = pe_data (obfd);
 
/* Copy PE parameters before changing them. */
if (ibfd->xvec->flavour == bfd_target_coff_flavour
&& bfd_pei_p (ibfd))
pe->pe_opthdr = pe_data (ibfd)->pe_opthdr;
 
if (pe_file_alignment != (bfd_vma) -1)
pe->pe_opthdr.FileAlignment = pe_file_alignment;
else
pe_file_alignment = PE_DEF_FILE_ALIGNMENT;
 
if (pe_heap_commit != (bfd_vma) -1)
pe->pe_opthdr.SizeOfHeapCommit = pe_heap_commit;
 
if (pe_heap_reserve != (bfd_vma) -1)
pe->pe_opthdr.SizeOfHeapCommit = pe_heap_reserve;
 
if (pe_image_base != (bfd_vma) -1)
pe->pe_opthdr.ImageBase = pe_image_base;
 
if (pe_section_alignment != (bfd_vma) -1)
pe->pe_opthdr.SectionAlignment = pe_section_alignment;
else
pe_section_alignment = PE_DEF_SECTION_ALIGNMENT;
 
if (pe_stack_commit != (bfd_vma) -1)
pe->pe_opthdr.SizeOfStackCommit = pe_stack_commit;
 
if (pe_stack_reserve != (bfd_vma) -1)
pe->pe_opthdr.SizeOfStackCommit = pe_stack_reserve;
 
if (pe_subsystem != -1)
pe->pe_opthdr.Subsystem = pe_subsystem;
 
if (pe_major_subsystem_version != -1)
pe->pe_opthdr.MajorSubsystemVersion = pe_major_subsystem_version;
 
if (pe_minor_subsystem_version != -1)
pe->pe_opthdr.MinorSubsystemVersion = pe_minor_subsystem_version;
 
if (pe_file_alignment > pe_section_alignment)
{
char file_alignment[20], section_alignment[20];
 
sprintf_vma (file_alignment, pe_file_alignment);
sprintf_vma (section_alignment, pe_section_alignment);
non_fatal (_("warning: file alignment (0x%s) > section alignment (0x%s)"),
 
file_alignment, section_alignment);
}
}
 
if (isympp)
free (isympp);
 
if (osympp != isympp)
free (osympp);
 
isympp = NULL;
osympp = NULL;
 
symsize = bfd_get_symtab_upper_bound (ibfd);
if (symsize < 0)
{
bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
return FALSE;
}
 
osympp = isympp = (asymbol **) xmalloc (symsize);
symcount = bfd_canonicalize_symtab (ibfd, isympp);
if (symcount < 0)
{
bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
return FALSE;
}
 
/* BFD mandates that all output sections be created and sizes set before
any output is done. Thus, we traverse all sections multiple times. */
bfd_map_over_sections (ibfd, setup_section, obfd);
 
if (!extract_symbol)
setup_bfd_headers (ibfd, obfd);
 
if (add_sections != NULL)
{
struct section_add *padd;
struct section_list *pset;
 
for (padd = add_sections; padd != NULL; padd = padd->next)
{
flagword flags;
 
pset = find_section_list (padd->name, FALSE,
SECTION_CONTEXT_SET_FLAGS);
if (pset != NULL)
flags = pset->flags | SEC_HAS_CONTENTS;
else
flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
 
/* bfd_make_section_with_flags() does not return very helpful
error codes, so check for the most likely user error first. */
if (bfd_get_section_by_name (obfd, padd->name))
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("can't add section '%s'"), padd->name);
return FALSE;
}
else
{
/* We use LINKER_CREATED here so that the backend hooks
will create any special section type information,
instead of presuming we know what we're doing merely
because we set the flags. */
padd->section = bfd_make_section_with_flags
(obfd, padd->name, flags | SEC_LINKER_CREATED);
if (padd->section == NULL)
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("can't create section `%s'"),
padd->name);
return FALSE;
}
}
 
if (! bfd_set_section_size (obfd, padd->section, padd->size))
{
bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
return FALSE;
}
 
pset = find_section_list (padd->name, FALSE,
SECTION_CONTEXT_SET_VMA | SECTION_CONTEXT_ALTER_VMA);
if (pset != NULL
&& ! bfd_set_section_vma (obfd, padd->section, pset->vma_val))
{
bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
return FALSE;
}
 
pset = find_section_list (padd->name, FALSE,
SECTION_CONTEXT_SET_LMA | SECTION_CONTEXT_ALTER_LMA);
if (pset != NULL)
{
padd->section->lma = pset->lma_val;
 
if (! bfd_set_section_alignment
(obfd, padd->section,
bfd_section_alignment (obfd, padd->section)))
{
bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
return FALSE;
}
}
}
}
 
if (gnu_debuglink_filename != NULL)
{
/* PR 15125: Give a helpful warning message if
the debuglink section already exists, and
allow the rest of the copy to complete. */
if (bfd_get_section_by_name (obfd, ".gnu_debuglink"))
{
non_fatal (_("%s: debuglink section already exists"),
bfd_get_filename (obfd));
gnu_debuglink_filename = NULL;
}
else
{
gnu_debuglink_section = bfd_create_gnu_debuglink_section
(obfd, gnu_debuglink_filename);
 
if (gnu_debuglink_section == NULL)
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("cannot create debug link section `%s'"),
gnu_debuglink_filename);
return FALSE;
}
 
/* Special processing for PE format files. We
have no way to distinguish PE from COFF here. */
if (bfd_get_flavour (obfd) == bfd_target_coff_flavour)
{
bfd_vma debuglink_vma;
asection * highest_section;
asection * sec;
 
/* The PE spec requires that all sections be adjacent and sorted
in ascending order of VMA. It also specifies that debug
sections should be last. This is despite the fact that debug
sections are not loaded into memory and so in theory have no
use for a VMA.
 
This means that the debuglink section must be given a non-zero
VMA which makes it contiguous with other debug sections. So
walk the current section list, find the section with the
highest VMA and start the debuglink section after that one. */
for (sec = obfd->sections, highest_section = NULL;
sec != NULL;
sec = sec->next)
if (sec->vma > 0
&& (highest_section == NULL
|| sec->vma > highest_section->vma))
highest_section = sec;
 
if (highest_section)
debuglink_vma = BFD_ALIGN (highest_section->vma
+ highest_section->size,
/* FIXME: We ought to be using
COFF_PAGE_SIZE here or maybe
bfd_get_section_alignment() (if it
was set) but since this is for PE
and we know the required alignment
it is easier just to hard code it. */
0x1000);
else
/* Umm, not sure what to do in this case. */
debuglink_vma = 0x1000;
 
bfd_set_section_vma (obfd, gnu_debuglink_section, debuglink_vma);
}
}
}
 
if (bfd_count_sections (obfd) != 0
&& (gap_fill_set || pad_to_set))
{
asection **set;
unsigned int c, i;
 
/* We must fill in gaps between the sections and/or we must pad
the last section to a specified address. We do this by
grabbing a list of the sections, sorting them by VMA, and
increasing the section sizes as required to fill the gaps.
We write out the gap contents below. */
 
c = bfd_count_sections (obfd);
osections = (asection **) xmalloc (c * sizeof (asection *));
set = osections;
bfd_map_over_sections (obfd, get_sections, &set);
 
qsort (osections, c, sizeof (asection *), compare_section_lma);
 
gaps = (bfd_size_type *) xmalloc (c * sizeof (bfd_size_type));
memset (gaps, 0, c * sizeof (bfd_size_type));
 
if (gap_fill_set)
{
for (i = 0; i < c - 1; i++)
{
flagword flags;
bfd_size_type size;
bfd_vma gap_start, gap_stop;
 
flags = bfd_get_section_flags (obfd, osections[i]);
if ((flags & SEC_HAS_CONTENTS) == 0
|| (flags & SEC_LOAD) == 0)
continue;
 
size = bfd_section_size (obfd, osections[i]);
gap_start = bfd_section_lma (obfd, osections[i]) + size;
gap_stop = bfd_section_lma (obfd, osections[i + 1]);
if (gap_start < gap_stop)
{
if (! bfd_set_section_size (obfd, osections[i],
size + (gap_stop - gap_start)))
{
bfd_nonfatal_message (NULL, obfd, osections[i],
_("Can't fill gap after section"));
status = 1;
break;
}
gaps[i] = gap_stop - gap_start;
if (max_gap < gap_stop - gap_start)
max_gap = gap_stop - gap_start;
}
}
}
 
if (pad_to_set)
{
bfd_vma lma;
bfd_size_type size;
 
lma = bfd_section_lma (obfd, osections[c - 1]);
size = bfd_section_size (obfd, osections[c - 1]);
if (lma + size < pad_to)
{
if (! bfd_set_section_size (obfd, osections[c - 1],
pad_to - lma))
{
bfd_nonfatal_message (NULL, obfd, osections[c - 1],
_("can't add padding"));
status = 1;
}
else
{
gaps[c - 1] = pad_to - (lma + size);
if (max_gap < pad_to - (lma + size))
max_gap = pad_to - (lma + size);
}
}
}
}
 
/* Symbol filtering must happen after the output sections
have been created, but before their contents are set. */
dhandle = NULL;
if (convert_debugging)
dhandle = read_debugging_info (ibfd, isympp, symcount, FALSE);
 
if (strip_symbols == STRIP_DEBUG
|| strip_symbols == STRIP_ALL
|| strip_symbols == STRIP_UNNEEDED
|| strip_symbols == STRIP_NONDEBUG
|| strip_symbols == STRIP_DWO
|| strip_symbols == STRIP_NONDWO
|| discard_locals != LOCALS_UNDEF
|| localize_hidden
|| htab_elements (strip_specific_htab) != 0
|| htab_elements (keep_specific_htab) != 0
|| htab_elements (localize_specific_htab) != 0
|| htab_elements (globalize_specific_htab) != 0
|| htab_elements (keepglobal_specific_htab) != 0
|| htab_elements (weaken_specific_htab) != 0
|| prefix_symbols_string
|| sections_removed
|| sections_copied
|| convert_debugging
|| change_leading_char
|| remove_leading_char
|| redefine_sym_list
|| weaken)
{
/* Mark symbols used in output relocations so that they
are kept, even if they are local labels or static symbols.
 
Note we iterate over the input sections examining their
relocations since the relocations for the output sections
haven't been set yet. mark_symbols_used_in_relocations will
ignore input sections which have no corresponding output
section. */
if (strip_symbols != STRIP_ALL)
bfd_map_over_sections (ibfd,
mark_symbols_used_in_relocations,
isympp);
osympp = (asymbol **) xmalloc ((symcount + 1) * sizeof (asymbol *));
symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount);
}
 
if (convert_debugging && dhandle != NULL)
{
if (! write_debugging_info (obfd, dhandle, &symcount, &osympp))
{
status = 1;
return FALSE;
}
}
 
bfd_set_symtab (obfd, osympp, symcount);
 
/* This has to happen before section positions are set. */
bfd_map_over_sections (ibfd, copy_relocations_in_section, obfd);
 
/* This has to happen after the symbol table has been set. */
bfd_map_over_sections (ibfd, copy_section, obfd);
 
if (add_sections != NULL)
{
struct section_add *padd;
 
for (padd = add_sections; padd != NULL; padd = padd->next)
{
if (! bfd_set_section_contents (obfd, padd->section, padd->contents,
0, padd->size))
{
bfd_nonfatal_message (NULL, obfd, padd->section, NULL);
return FALSE;
}
}
}
 
if (gnu_debuglink_filename != NULL)
{
if (! bfd_fill_in_gnu_debuglink_section
(obfd, gnu_debuglink_section, gnu_debuglink_filename))
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("cannot fill debug link section `%s'"),
gnu_debuglink_filename);
return FALSE;
}
}
 
if (gap_fill_set || pad_to_set)
{
bfd_byte *buf;
int c, i;
 
/* Fill in the gaps. */
if (max_gap > 8192)
max_gap = 8192;
buf = (bfd_byte *) xmalloc (max_gap);
memset (buf, gap_fill, max_gap);
 
c = bfd_count_sections (obfd);
for (i = 0; i < c; i++)
{
if (gaps[i] != 0)
{
bfd_size_type left;
file_ptr off;
 
left = gaps[i];
off = bfd_section_size (obfd, osections[i]) - left;
 
while (left > 0)
{
bfd_size_type now;
 
if (left > 8192)
now = 8192;
else
now = left;
 
if (! bfd_set_section_contents (obfd, osections[i], buf,
off, now))
{
bfd_nonfatal_message (NULL, obfd, osections[i], NULL);
return FALSE;
}
 
left -= now;
off += now;
}
}
}
}
 
/* Do not copy backend data if --extract-symbol is passed; anything
that needs to look at the section contents will fail. */
if (extract_symbol)
return TRUE;
 
/* Allow the BFD backend to copy any private data it understands
from the input BFD to the output BFD. This is done last to
permit the routine to look at the filtered symbol table, which is
important for the ECOFF code at least. */
if (! bfd_copy_private_bfd_data (ibfd, obfd))
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("error copying private BFD data"));
return FALSE;
}
 
/* Switch to the alternate machine code. We have to do this at the
very end, because we only initialize the header when we create
the first section. */
if (use_alt_mach_code != 0)
{
if (! bfd_alt_mach_code (obfd, use_alt_mach_code))
{
non_fatal (_("this target does not support %lu alternative machine codes"),
use_alt_mach_code);
if (bfd_get_flavour (obfd) == bfd_target_elf_flavour)
{
non_fatal (_("treating that number as an absolute e_machine value instead"));
elf_elfheader (obfd)->e_machine = use_alt_mach_code;
}
else
non_fatal (_("ignoring the alternative value"));
}
}
 
return TRUE;
}
 
/* Read each archive element in turn from IBFD, copy the
contents to temp file, and keep the temp file handle.
If 'force_output_target' is TRUE then make sure that
all elements in the new archive are of the type
'output_target'. */
 
static void
copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
bfd_boolean force_output_target,
const bfd_arch_info_type *input_arch)
{
struct name_list
{
struct name_list *next;
const char *name;
bfd *obfd;
} *list, *l;
bfd **ptr = &obfd->archive_head;
bfd *this_element;
char *dir;
const char *filename;
 
/* Make a temp directory to hold the contents. */
dir = make_tempdir (bfd_get_filename (obfd));
if (dir == NULL)
fatal (_("cannot create tempdir for archive copying (error: %s)"),
strerror (errno));
 
if (strip_symbols == STRIP_ALL)
obfd->has_armap = FALSE;
else
obfd->has_armap = ibfd->has_armap;
obfd->is_thin_archive = ibfd->is_thin_archive;
 
if (deterministic)
obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
 
list = NULL;
 
this_element = bfd_openr_next_archived_file (ibfd, NULL);
 
if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
{
status = 1;
bfd_nonfatal_message (NULL, obfd, NULL, NULL);
return;
}
 
while (!status && this_element != NULL)
{
char *output_name;
bfd *output_bfd;
bfd *last_element;
struct stat buf;
int stat_status = 0;
bfd_boolean del = TRUE;
bfd_boolean ok_object;
 
/* Create an output file for this member. */
output_name = concat (dir, "/",
bfd_get_filename (this_element), (char *) 0);
 
/* If the file already exists, make another temp dir. */
if (stat (output_name, &buf) >= 0)
{
output_name = make_tempdir (output_name);
if (output_name == NULL)
fatal (_("cannot create tempdir for archive copying (error: %s)"),
strerror (errno));
 
l = (struct name_list *) xmalloc (sizeof (struct name_list));
l->name = output_name;
l->next = list;
l->obfd = NULL;
list = l;
output_name = concat (output_name, "/",
bfd_get_filename (this_element), (char *) 0);
}
 
if (preserve_dates)
{
stat_status = bfd_stat_arch_elt (this_element, &buf);
 
if (stat_status != 0)
non_fatal (_("internal stat error on %s"),
bfd_get_filename (this_element));
}
 
l = (struct name_list *) xmalloc (sizeof (struct name_list));
l->name = output_name;
l->next = list;
l->obfd = NULL;
list = l;
 
ok_object = bfd_check_format (this_element, bfd_object);
if (!ok_object)
bfd_nonfatal_message (NULL, this_element, NULL,
_("Unable to recognise the format of file"));
 
/* PR binutils/3110: Cope with archives
containing multiple target types. */
if (force_output_target || !ok_object)
output_bfd = bfd_openw (output_name, output_target);
else
output_bfd = bfd_openw (output_name, bfd_get_target (this_element));
 
if (output_bfd == NULL)
{
bfd_nonfatal_message (output_name, NULL, NULL, NULL);
status = 1;
return;
}
 
if (ok_object)
{
del = !copy_object (this_element, output_bfd, input_arch);
 
if (del && bfd_get_arch (this_element) == bfd_arch_unknown)
/* Try again as an unknown object file. */
ok_object = FALSE;
else if (!bfd_close (output_bfd))
{
bfd_nonfatal_message (output_name, NULL, NULL, NULL);
/* Error in new object file. Don't change archive. */
status = 1;
}
}
 
if (!ok_object)
{
del = !copy_unknown_object (this_element, output_bfd);
if (!bfd_close_all_done (output_bfd))
{
bfd_nonfatal_message (output_name, NULL, NULL, NULL);
/* Error in new object file. Don't change archive. */
status = 1;
}
}
 
if (del)
{
unlink (output_name);
status = 1;
}
else
{
if (preserve_dates && stat_status == 0)
set_times (output_name, &buf);
 
/* Open the newly output file and attach to our list. */
output_bfd = bfd_openr (output_name, output_target);
 
l->obfd = output_bfd;
 
*ptr = output_bfd;
ptr = &output_bfd->archive_next;
 
last_element = this_element;
 
this_element = bfd_openr_next_archived_file (ibfd, last_element);
 
bfd_close (last_element);
}
}
*ptr = NULL;
 
filename = bfd_get_filename (obfd);
if (!bfd_close (obfd))
{
status = 1;
bfd_nonfatal_message (filename, NULL, NULL, NULL);
return;
}
 
filename = bfd_get_filename (ibfd);
if (!bfd_close (ibfd))
{
status = 1;
bfd_nonfatal_message (filename, NULL, NULL, NULL);
return;
}
 
/* Delete all the files that we opened. */
#if 0
for (l = list; l != NULL; l = l->next)
{
if (l->obfd == NULL)
rmdir (l->name);
else
{
bfd_close (l->obfd);
unlink (l->name);
}
}
rmdir (dir);
#endif
 
}
 
static void
set_long_section_mode (bfd *output_bfd, bfd *input_bfd, enum long_section_name_handling style)
{
/* This is only relevant to Coff targets. */
if (bfd_get_flavour (output_bfd) == bfd_target_coff_flavour)
{
if (style == KEEP
&& bfd_get_flavour (input_bfd) == bfd_target_coff_flavour)
style = bfd_coff_long_section_names (input_bfd) ? ENABLE : DISABLE;
bfd_coff_set_long_section_names (output_bfd, style != DISABLE);
}
}
 
/* The top-level control. */
 
static void
copy_file (const char *input_filename, const char *output_filename,
const char *input_target, const char *output_target,
const bfd_arch_info_type *input_arch)
{
bfd *ibfd;
char **obj_matching;
char **core_matching;
off_t size = get_file_size (input_filename);
 
if (size < 1)
{
if (size == 0)
non_fatal (_("error: the input file '%s' is empty"),
input_filename);
status = 1;
return;
}
 
/* To allow us to do "strip *" without dying on the first
non-object file, failures are nonfatal. */
ibfd = bfd_openr (input_filename, input_target);
if (ibfd == NULL)
{
bfd_nonfatal_message (input_filename, NULL, NULL, NULL);
status = 1;
return;
}
 
switch (do_debug_sections)
{
case compress:
ibfd->flags |= BFD_COMPRESS;
break;
case decompress:
ibfd->flags |= BFD_DECOMPRESS;
break;
default:
break;
}
 
if (bfd_check_format (ibfd, bfd_archive))
{
bfd_boolean force_output_target;
bfd *obfd;
 
/* bfd_get_target does not return the correct value until
bfd_check_format succeeds. */
if (output_target == NULL)
{
output_target = bfd_get_target (ibfd);
force_output_target = FALSE;
}
else
force_output_target = TRUE;
 
obfd = bfd_openw (output_filename, output_target);
if (obfd == NULL)
{
bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
status = 1;
return;
}
/* This is a no-op on non-Coff targets. */
set_long_section_mode (obfd, ibfd, long_section_names);
 
copy_archive (ibfd, obfd, output_target, force_output_target, input_arch);
}
else if (bfd_check_format_matches (ibfd, bfd_object, &obj_matching))
{
bfd *obfd;
do_copy:
 
/* bfd_get_target does not return the correct value until
bfd_check_format succeeds. */
if (output_target == NULL)
output_target = bfd_get_target (ibfd);
 
obfd = bfd_openw (output_filename, output_target);
if (obfd == NULL)
{
bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
status = 1;
return;
}
/* This is a no-op on non-Coff targets. */
set_long_section_mode (obfd, ibfd, long_section_names);
 
if (! copy_object (ibfd, obfd, input_arch))
status = 1;
 
if (!bfd_close (obfd))
{
status = 1;
bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
return;
}
 
if (!bfd_close (ibfd))
{
status = 1;
bfd_nonfatal_message (input_filename, NULL, NULL, NULL);
return;
}
}
else
{
bfd_error_type obj_error = bfd_get_error ();
bfd_error_type core_error;
 
if (bfd_check_format_matches (ibfd, bfd_core, &core_matching))
{
/* This probably can't happen.. */
if (obj_error == bfd_error_file_ambiguously_recognized)
free (obj_matching);
goto do_copy;
}
 
core_error = bfd_get_error ();
/* Report the object error in preference to the core error. */
if (obj_error != core_error)
bfd_set_error (obj_error);
 
bfd_nonfatal_message (input_filename, NULL, NULL, NULL);
 
if (obj_error == bfd_error_file_ambiguously_recognized)
{
list_matching_formats (obj_matching);
free (obj_matching);
}
if (core_error == bfd_error_file_ambiguously_recognized)
{
list_matching_formats (core_matching);
free (core_matching);
}
 
status = 1;
}
}
 
/* Add a name to the section renaming list. */
 
static void
add_section_rename (const char * old_name, const char * new_name,
flagword flags)
{
section_rename * srename;
 
/* Check for conflicts first. */
for (srename = section_rename_list; srename != NULL; srename = srename->next)
if (strcmp (srename->old_name, old_name) == 0)
{
/* Silently ignore duplicate definitions. */
if (strcmp (srename->new_name, new_name) == 0
&& srename->flags == flags)
return;
 
fatal (_("Multiple renames of section %s"), old_name);
}
 
srename = (section_rename *) xmalloc (sizeof (* srename));
 
srename->old_name = old_name;
srename->new_name = new_name;
srename->flags = flags;
srename->next = section_rename_list;
 
section_rename_list = srename;
}
 
/* Check the section rename list for a new name of the input section
ISECTION. Return the new name if one is found.
Also set RETURNED_FLAGS to the flags to be used for this section. */
 
static const char *
find_section_rename (bfd * ibfd ATTRIBUTE_UNUSED, sec_ptr isection,
flagword * returned_flags)
{
const char * old_name = bfd_section_name (ibfd, isection);
section_rename * srename;
 
/* Default to using the flags of the input section. */
* returned_flags = bfd_get_section_flags (ibfd, isection);
 
for (srename = section_rename_list; srename != NULL; srename = srename->next)
if (strcmp (srename->old_name, old_name) == 0)
{
if (srename->flags != (flagword) -1)
* returned_flags = srename->flags;
 
return srename->new_name;
}
 
return old_name;
}
 
/* Once each of the sections is copied, we may still need to do some
finalization work for private section headers. Do that here. */
 
static void
setup_bfd_headers (bfd *ibfd, bfd *obfd)
{
/* Allow the BFD backend to copy any private data it understands
from the input section to the output section. */
if (! bfd_copy_private_header_data (ibfd, obfd))
{
status = 1;
bfd_nonfatal_message (NULL, ibfd, NULL,
_("error in private header data"));
return;
}
 
/* All went well. */
return;
}
 
/* Create a section in OBFD with the same
name and attributes as ISECTION in IBFD. */
 
static void
setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
{
bfd *obfd = (bfd *) obfdarg;
struct section_list *p;
sec_ptr osection;
bfd_size_type size;
bfd_vma vma;
bfd_vma lma;
flagword flags;
const char *err;
const char * name;
char *prefix = NULL;
bfd_boolean make_nobits;
 
if (is_strip_section (ibfd, isection))
return;
 
/* Get the, possibly new, name of the output section. */
name = find_section_rename (ibfd, isection, & flags);
 
/* Prefix sections. */
if ((prefix_alloc_sections_string)
&& (bfd_get_section_flags (ibfd, isection) & SEC_ALLOC))
prefix = prefix_alloc_sections_string;
else if (prefix_sections_string)
prefix = prefix_sections_string;
 
if (prefix)
{
char *n;
 
n = (char *) xmalloc (strlen (prefix) + strlen (name) + 1);
strcpy (n, prefix);
strcat (n, name);
name = n;
}
 
make_nobits = FALSE;
 
p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
SECTION_CONTEXT_SET_FLAGS);
if (p != NULL)
flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
else if (strip_symbols == STRIP_NONDEBUG
&& (flags & (SEC_ALLOC | SEC_GROUP)) != 0
&& !(ibfd->xvec->flavour == bfd_target_elf_flavour
&& elf_section_type (isection) == SHT_NOTE))
{
flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD | SEC_GROUP);
if (obfd->xvec->flavour == bfd_target_elf_flavour)
{
make_nobits = TRUE;
 
/* Twiddle the input section flags so that it seems to
elf.c:copy_private_bfd_data that section flags have not
changed between input and output sections. This hack
prevents wholesale rewriting of the program headers. */
isection->flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD | SEC_GROUP);
}
}
 
osection = bfd_make_section_anyway_with_flags (obfd, name, flags);
 
if (osection == NULL)
{
err = _("failed to create output section");
goto loser;
}
 
if (make_nobits)
elf_section_type (osection) = SHT_NOBITS;
 
size = bfd_section_size (ibfd, isection);
if (copy_byte >= 0)
size = (size + interleave - 1) / interleave * copy_width;
else if (extract_symbol)
size = 0;
if (! bfd_set_section_size (obfd, osection, size))
{
err = _("failed to set size");
goto loser;
}
 
vma = bfd_section_vma (ibfd, isection);
p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
SECTION_CONTEXT_ALTER_VMA | SECTION_CONTEXT_SET_VMA);
if (p != NULL)
{
if (p->context & SECTION_CONTEXT_SET_VMA)
vma = p->vma_val;
else
vma += p->vma_val;
}
else
vma += change_section_address;
 
if (! bfd_set_section_vma (obfd, osection, vma))
{
err = _("failed to set vma");
goto loser;
}
 
lma = isection->lma;
p = find_section_list (bfd_section_name (ibfd, isection), FALSE,
SECTION_CONTEXT_ALTER_LMA | SECTION_CONTEXT_SET_LMA);
if (p != NULL)
{
if (p->context & SECTION_CONTEXT_ALTER_LMA)
lma += p->lma_val;
else
lma = p->lma_val;
}
else
lma += change_section_address;
 
osection->lma = lma;
 
/* FIXME: This is probably not enough. If we change the LMA we
may have to recompute the header for the file as well. */
if (!bfd_set_section_alignment (obfd,
osection,
bfd_section_alignment (ibfd, isection)))
{
err = _("failed to set alignment");
goto loser;
}
 
/* Copy merge entity size. */
osection->entsize = isection->entsize;
 
/* This used to be mangle_section; we do here to avoid using
bfd_get_section_by_name since some formats allow multiple
sections with the same name. */
isection->output_section = osection;
isection->output_offset = 0;
 
/* Do not copy backend data if --extract-symbol is passed; anything
that needs to look at the section contents will fail. */
if (extract_symbol)
return;
 
if ((isection->flags & SEC_GROUP) != 0)
{
asymbol *gsym = group_signature (isection);
 
if (gsym != NULL)
{
gsym->flags |= BSF_KEEP;
if (ibfd->xvec->flavour == bfd_target_elf_flavour)
elf_group_id (isection) = gsym;
}
}
 
/* Allow the BFD backend to copy any private data it understands
from the input section to the output section. */
if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection))
{
err = _("failed to copy private data");
goto loser;
}
 
/* All went well. */
return;
 
loser:
status = 1;
bfd_nonfatal_message (NULL, obfd, osection, err);
}
 
/* Return TRUE if input section ISECTION should be skipped. */
 
static bfd_boolean
skip_section (bfd *ibfd, sec_ptr isection)
{
sec_ptr osection;
bfd_size_type size;
flagword flags;
 
/* If we have already failed earlier on,
do not keep on generating complaints now. */
if (status != 0)
return TRUE;
 
if (extract_symbol)
return TRUE;
 
if (is_strip_section (ibfd, isection))
return TRUE;
 
flags = bfd_get_section_flags (ibfd, isection);
if ((flags & SEC_GROUP) != 0)
return TRUE;
 
osection = isection->output_section;
size = bfd_get_section_size (isection);
 
if (size == 0 || osection == 0)
return TRUE;
 
return FALSE;
}
 
/* Copy relocations in input section ISECTION of IBFD to an output
section with the same name in OBFDARG. If stripping then don't
copy any relocation info. */
 
static void
copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
{
bfd *obfd = (bfd *) obfdarg;
long relsize;
arelent **relpp;
long relcount;
sec_ptr osection;
 
if (skip_section (ibfd, isection))
return;
 
osection = isection->output_section;
 
/* Core files and DWO files do not need to be relocated. */
if (bfd_get_format (obfd) == bfd_core || strip_symbols == STRIP_NONDWO)
relsize = 0;
else
{
relsize = bfd_get_reloc_upper_bound (ibfd, isection);
 
if (relsize < 0)
{
/* Do not complain if the target does not support relocations. */
if (relsize == -1 && bfd_get_error () == bfd_error_invalid_operation)
relsize = 0;
else
{
status = 1;
bfd_nonfatal_message (NULL, ibfd, isection, NULL);
return;
}
}
}
 
if (relsize == 0)
{
bfd_set_reloc (obfd, osection, NULL, 0);
osection->flags &= ~SEC_RELOC;
}
else
{
relpp = (arelent **) xmalloc (relsize);
relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
if (relcount < 0)
{
status = 1;
bfd_nonfatal_message (NULL, ibfd, isection,
_("relocation count is negative"));
return;
}
 
if (strip_symbols == STRIP_ALL)
{
/* Remove relocations which are not in
keep_strip_specific_list. */
arelent **temp_relpp;
long temp_relcount = 0;
long i;
 
temp_relpp = (arelent **) xmalloc (relsize);
for (i = 0; i < relcount; i++)
if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr),
keep_specific_htab))
temp_relpp [temp_relcount++] = relpp [i];
relcount = temp_relcount;
free (relpp);
relpp = temp_relpp;
}
 
bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount);
if (relcount == 0)
{
osection->flags &= ~SEC_RELOC;
free (relpp);
}
}
}
 
/* Copy the data of input section ISECTION of IBFD
to an output section with the same name in OBFD. */
 
static void
copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
{
bfd *obfd = (bfd *) obfdarg;
struct section_list *p;
sec_ptr osection;
bfd_size_type size;
 
if (skip_section (ibfd, isection))
return;
 
osection = isection->output_section;
size = bfd_get_section_size (isection);
 
if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
&& bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
{
bfd_byte *memhunk = NULL;
 
if (!bfd_get_full_section_contents (ibfd, isection, &memhunk))
{
status = 1;
bfd_nonfatal_message (NULL, ibfd, isection, NULL);
return;
}
 
if (reverse_bytes)
{
/* We don't handle leftover bytes (too many possible behaviors,
and we don't know what the user wants). The section length
must be a multiple of the number of bytes to swap. */
if ((size % reverse_bytes) == 0)
{
unsigned long i, j;
bfd_byte b;
 
for (i = 0; i < size; i += reverse_bytes)
for (j = 0; j < (unsigned long)(reverse_bytes / 2); j++)
{
bfd_byte *m = (bfd_byte *) memhunk;
 
b = m[i + j];
m[i + j] = m[(i + reverse_bytes) - (j + 1)];
m[(i + reverse_bytes) - (j + 1)] = b;
}
}
else
/* User must pad the section up in order to do this. */
fatal (_("cannot reverse bytes: length of section %s must be evenly divisible by %d"),
bfd_section_name (ibfd, isection), reverse_bytes);
}
 
if (copy_byte >= 0)
{
/* Keep only every `copy_byte'th byte in MEMHUNK. */
char *from = (char *) memhunk + copy_byte;
char *to = (char *) memhunk;
char *end = (char *) memhunk + size;
int i;
 
for (; from < end; from += interleave)
for (i = 0; i < copy_width; i++)
{
if (&from[i] >= end)
break;
*to++ = from[i];
}
 
size = (size + interleave - 1 - copy_byte) / interleave * copy_width;
osection->lma /= interleave;
}
 
if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
{
status = 1;
bfd_nonfatal_message (NULL, obfd, osection, NULL);
return;
}
free (memhunk);
}
else if ((p = find_section_list (bfd_get_section_name (ibfd, isection),
FALSE, SECTION_CONTEXT_SET_FLAGS)) != NULL
&& (p->flags & SEC_HAS_CONTENTS) != 0)
{
void *memhunk = xmalloc (size);
 
/* We don't permit the user to turn off the SEC_HAS_CONTENTS
flag--they can just remove the section entirely and add it
back again. However, we do permit them to turn on the
SEC_HAS_CONTENTS flag, and take it to mean that the section
contents should be zeroed out. */
 
memset (memhunk, 0, size);
if (! bfd_set_section_contents (obfd, osection, memhunk, 0, size))
{
status = 1;
bfd_nonfatal_message (NULL, obfd, osection, NULL);
return;
}
free (memhunk);
}
}
 
/* Get all the sections. This is used when --gap-fill or --pad-to is
used. */
 
static void
get_sections (bfd *obfd ATTRIBUTE_UNUSED, asection *osection, void *secppparg)
{
asection ***secppp = (asection ***) secppparg;
 
**secppp = osection;
++(*secppp);
}
 
/* Sort sections by VMA. This is called via qsort, and is used when
--gap-fill or --pad-to is used. We force non loadable or empty
sections to the front, where they are easier to ignore. */
 
static int
compare_section_lma (const void *arg1, const void *arg2)
{
const asection *const *sec1 = (const asection * const *) arg1;
const asection *const *sec2 = (const asection * const *) arg2;
flagword flags1, flags2;
 
/* Sort non loadable sections to the front. */
flags1 = (*sec1)->flags;
flags2 = (*sec2)->flags;
if ((flags1 & SEC_HAS_CONTENTS) == 0
|| (flags1 & SEC_LOAD) == 0)
{
if ((flags2 & SEC_HAS_CONTENTS) != 0
&& (flags2 & SEC_LOAD) != 0)
return -1;
}
else
{
if ((flags2 & SEC_HAS_CONTENTS) == 0
|| (flags2 & SEC_LOAD) == 0)
return 1;
}
 
/* Sort sections by LMA. */
if ((*sec1)->lma > (*sec2)->lma)
return 1;
else if ((*sec1)->lma < (*sec2)->lma)
return -1;
 
/* Sort sections with the same LMA by size. */
if (bfd_get_section_size (*sec1) > bfd_get_section_size (*sec2))
return 1;
else if (bfd_get_section_size (*sec1) < bfd_get_section_size (*sec2))
return -1;
 
return 0;
}
 
/* Mark all the symbols which will be used in output relocations with
the BSF_KEEP flag so that those symbols will not be stripped.
 
Ignore relocations which will not appear in the output file. */
 
static void
mark_symbols_used_in_relocations (bfd *ibfd, sec_ptr isection, void *symbolsarg)
{
asymbol **symbols = (asymbol **) symbolsarg;
long relsize;
arelent **relpp;
long relcount, i;
 
/* Ignore an input section with no corresponding output section. */
if (isection->output_section == NULL)
return;
 
relsize = bfd_get_reloc_upper_bound (ibfd, isection);
if (relsize < 0)
{
/* Do not complain if the target does not support relocations. */
if (relsize == -1 && bfd_get_error () == bfd_error_invalid_operation)
return;
bfd_fatal (bfd_get_filename (ibfd));
}
 
if (relsize == 0)
return;
 
relpp = (arelent **) xmalloc (relsize);
relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, symbols);
if (relcount < 0)
bfd_fatal (bfd_get_filename (ibfd));
 
/* Examine each symbol used in a relocation. If it's not one of the
special bfd section symbols, then mark it with BSF_KEEP. */
for (i = 0; i < relcount; i++)
{
if (*relpp[i]->sym_ptr_ptr != bfd_com_section_ptr->symbol
&& *relpp[i]->sym_ptr_ptr != bfd_abs_section_ptr->symbol
&& *relpp[i]->sym_ptr_ptr != bfd_und_section_ptr->symbol)
(*relpp[i]->sym_ptr_ptr)->flags |= BSF_KEEP;
}
 
if (relpp != NULL)
free (relpp);
}
 
/* Write out debugging information. */
 
static bfd_boolean
write_debugging_info (bfd *obfd, void *dhandle,
long *symcountp ATTRIBUTE_UNUSED,
asymbol ***symppp ATTRIBUTE_UNUSED)
{
if (bfd_get_flavour (obfd) == bfd_target_ieee_flavour)
return write_ieee_debugging_info (obfd, dhandle);
 
if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
|| bfd_get_flavour (obfd) == bfd_target_elf_flavour)
{
bfd_byte *syms, *strings;
bfd_size_type symsize, stringsize;
asection *stabsec, *stabstrsec;
flagword flags;
 
if (! write_stabs_in_sections_debugging_info (obfd, dhandle, &syms,
&symsize, &strings,
&stringsize))
return FALSE;
 
flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING;
stabsec = bfd_make_section_with_flags (obfd, ".stab", flags);
stabstrsec = bfd_make_section_with_flags (obfd, ".stabstr", flags);
if (stabsec == NULL
|| stabstrsec == NULL
|| ! bfd_set_section_size (obfd, stabsec, symsize)
|| ! bfd_set_section_size (obfd, stabstrsec, stringsize)
|| ! bfd_set_section_alignment (obfd, stabsec, 2)
|| ! bfd_set_section_alignment (obfd, stabstrsec, 0))
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("can't create debugging section"));
return FALSE;
}
 
/* We can get away with setting the section contents now because
the next thing the caller is going to do is copy over the
real sections. We may someday have to split the contents
setting out of this function. */
if (! bfd_set_section_contents (obfd, stabsec, syms, 0, symsize)
|| ! bfd_set_section_contents (obfd, stabstrsec, strings, 0,
stringsize))
{
bfd_nonfatal_message (NULL, obfd, NULL,
_("can't set debugging section contents"));
return FALSE;
}
 
return TRUE;
}
 
bfd_nonfatal_message (NULL, obfd, NULL,
_("don't know how to write debugging information for %s"),
bfd_get_target (obfd));
return FALSE;
}
 
/* If neither -D nor -U was specified explicitly,
then use the configured default. */
static void
default_deterministic (void)
{
if (deterministic < 0)
deterministic = DEFAULT_AR_DETERMINISTIC;
}
 
static int
strip_main (int argc, char *argv[])
{
char *input_target = NULL;
char *output_target = NULL;
bfd_boolean show_version = FALSE;
bfd_boolean formats_info = FALSE;
int c;
int i;
char *output_file = NULL;
 
while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVvw",
strip_options, (int *) 0)) != EOF)
{
switch (c)
{
case 'I':
input_target = optarg;
break;
case 'O':
output_target = optarg;
break;
case 'F':
input_target = output_target = optarg;
break;
case 'R':
find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE);
sections_removed = TRUE;
break;
case 's':
strip_symbols = STRIP_ALL;
break;
case 'S':
case 'g':
case 'd': /* Historic BSD alias for -g. Used by early NetBSD. */
strip_symbols = STRIP_DEBUG;
break;
case OPTION_STRIP_DWO:
strip_symbols = STRIP_DWO;
break;
case OPTION_STRIP_UNNEEDED:
strip_symbols = STRIP_UNNEEDED;
break;
case 'K':
add_specific_symbol (optarg, keep_specific_htab);
break;
case 'N':
add_specific_symbol (optarg, strip_specific_htab);
break;
case 'o':
output_file = optarg;
break;
case 'p':
preserve_dates = TRUE;
break;
case 'D':
deterministic = TRUE;
break;
case 'U':
deterministic = FALSE;
break;
case 'x':
discard_locals = LOCALS_ALL;
break;
case 'X':
discard_locals = LOCALS_START_L;
break;
case 'v':
verbose = TRUE;
break;
case 'V':
show_version = TRUE;
break;
case OPTION_FORMATS_INFO:
formats_info = TRUE;
break;
case OPTION_ONLY_KEEP_DEBUG:
strip_symbols = STRIP_NONDEBUG;
break;
case OPTION_KEEP_FILE_SYMBOLS:
keep_file_symbols = 1;
break;
case 0:
/* We've been given a long option. */
break;
case 'w':
wildcard = TRUE;
break;
case 'H':
case 'h':
strip_usage (stdout, 0);
default:
strip_usage (stderr, 1);
}
}
 
if (formats_info)
{
display_info ();
return 0;
}
 
if (show_version)
print_version ("strip");
 
default_deterministic ();
 
/* Default is to strip all symbols. */
if (strip_symbols == STRIP_UNDEF
&& discard_locals == LOCALS_UNDEF
&& htab_elements (strip_specific_htab) == 0)
strip_symbols = STRIP_ALL;
 
if (output_target == NULL)
output_target = input_target;
 
i = optind;
if (i == argc
|| (output_file != NULL && (i + 1) < argc))
strip_usage (stderr, 1);
 
for (; i < argc; i++)
{
int hold_status = status;
struct stat statbuf;
char *tmpname;
 
if (get_file_size (argv[i]) < 1)
{
status = 1;
continue;
}
 
if (preserve_dates)
/* No need to check the return value of stat().
It has already been checked in get_file_size(). */
stat (argv[i], &statbuf);
 
if (output_file == NULL
|| filename_cmp (argv[i], output_file) == 0)
tmpname = make_tempname (argv[i]);
else
tmpname = output_file;
 
if (tmpname == NULL)
{
bfd_nonfatal_message (argv[i], NULL, NULL,
_("could not create temporary file to hold stripped copy"));
status = 1;
continue;
}
 
status = 0;
copy_file (argv[i], tmpname, input_target, output_target, NULL);
if (status == 0)
{
if (preserve_dates)
set_times (tmpname, &statbuf);
if (output_file != tmpname)
status = (smart_rename (tmpname,
output_file ? output_file : argv[i],
preserve_dates) != 0);
if (status == 0)
status = hold_status;
}
else
unlink_if_ordinary (tmpname);
if (output_file != tmpname)
free (tmpname);
}
 
return status;
}
 
/* Set up PE subsystem. */
 
static void
set_pe_subsystem (const char *s)
{
const char *version, *subsystem;
size_t i;
static const struct
{
const char *name;
const char set_def;
const short value;
}
v[] =
{
{ "native", 0, IMAGE_SUBSYSTEM_NATIVE },
{ "windows", 0, IMAGE_SUBSYSTEM_WINDOWS_GUI },
{ "console", 0, IMAGE_SUBSYSTEM_WINDOWS_CUI },
{ "posix", 0, IMAGE_SUBSYSTEM_POSIX_CUI },
{ "wince", 0, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI },
{ "efi-app", 1, IMAGE_SUBSYSTEM_EFI_APPLICATION },
{ "efi-bsd", 1, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER },
{ "efi-rtd", 1, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER },
{ "sal-rtd", 1, IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER },
{ "xbox", 0, IMAGE_SUBSYSTEM_XBOX }
};
short value;
char *copy;
int set_def = -1;
 
/* Check for the presence of a version number. */
version = strchr (s, ':');
if (version == NULL)
subsystem = s;
else
{
int len = version - s;
copy = xstrdup (s);
subsystem = copy;
copy[len] = '\0';
version = copy + 1 + len;
pe_major_subsystem_version = strtoul (version, &copy, 0);
if (*copy == '.')
pe_minor_subsystem_version = strtoul (copy + 1, &copy, 0);
if (*copy != '\0')
non_fatal (_("%s: bad version in PE subsystem"), s);
}
 
/* Check for numeric subsystem. */
value = (short) strtol (subsystem, &copy, 0);
if (*copy == '\0')
{
for (i = 0; i < ARRAY_SIZE (v); i++)
if (v[i].value == value)
{
pe_subsystem = value;
set_def = v[i].set_def;
break;
}
}
else
{
/* Search for subsystem by name. */
for (i = 0; i < ARRAY_SIZE (v); i++)
if (strcmp (subsystem, v[i].name) == 0)
{
pe_subsystem = v[i].value;
set_def = v[i].set_def;
break;
}
}
 
switch (set_def)
{
case -1:
fatal (_("unknown PE subsystem: %s"), s);
break;
case 0:
break;
default:
if (pe_file_alignment == (bfd_vma) -1)
pe_file_alignment = PE_DEF_FILE_ALIGNMENT;
if (pe_section_alignment == (bfd_vma) -1)
pe_section_alignment = PE_DEF_SECTION_ALIGNMENT;
break;
}
if (s != subsystem)
free ((char *) subsystem);
}
 
/* Convert EFI target to PEI target. */
 
static void
convert_efi_target (char *efi)
{
efi[0] = 'p';
efi[1] = 'e';
efi[2] = 'i';
 
if (strcmp (efi + 4, "ia32") == 0)
{
/* Change ia32 to i386. */
efi[5]= '3';
efi[6]= '8';
efi[7]= '6';
}
else if (strcmp (efi + 4, "x86_64") == 0)
{
/* Change x86_64 to x86-64. */
efi[7] = '-';
}
}
 
static int
copy_main (int argc, char *argv[])
{
char *input_filename = NULL;
char *output_filename = NULL;
char *tmpname;
char *input_target = NULL;
char *output_target = NULL;
bfd_boolean show_version = FALSE;
bfd_boolean change_warn = TRUE;
bfd_boolean formats_info = FALSE;
int c;
struct stat statbuf;
const bfd_arch_info_type *input_arch = NULL;
 
while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:w",
copy_options, (int *) 0)) != EOF)
{
switch (c)
{
case 'b':
copy_byte = atoi (optarg);
if (copy_byte < 0)
fatal (_("byte number must be non-negative"));
break;
 
case 'B':
input_arch = bfd_scan_arch (optarg);
if (input_arch == NULL)
fatal (_("architecture %s unknown"), optarg);
break;
 
case 'i':
if (optarg)
{
interleave = atoi (optarg);
if (interleave < 1)
fatal (_("interleave must be positive"));
}
else
interleave = 4;
break;
 
case OPTION_INTERLEAVE_WIDTH:
copy_width = atoi (optarg);
if (copy_width < 1)
fatal(_("interleave width must be positive"));
break;
 
case 'I':
case 's': /* "source" - 'I' is preferred */
input_target = optarg;
break;
 
case 'O':
case 'd': /* "destination" - 'O' is preferred */
output_target = optarg;
break;
 
case 'F':
input_target = output_target = optarg;
break;
 
case 'j':
find_section_list (optarg, TRUE, SECTION_CONTEXT_COPY);
sections_copied = TRUE;
break;
 
case 'R':
find_section_list (optarg, TRUE, SECTION_CONTEXT_REMOVE);
sections_removed = TRUE;
break;
 
case 'S':
strip_symbols = STRIP_ALL;
break;
 
case 'g':
strip_symbols = STRIP_DEBUG;
break;
 
case OPTION_STRIP_DWO:
strip_symbols = STRIP_DWO;
break;
 
case OPTION_STRIP_UNNEEDED:
strip_symbols = STRIP_UNNEEDED;
break;
 
case OPTION_ONLY_KEEP_DEBUG:
strip_symbols = STRIP_NONDEBUG;
break;
 
case OPTION_KEEP_FILE_SYMBOLS:
keep_file_symbols = 1;
break;
 
case OPTION_ADD_GNU_DEBUGLINK:
long_section_names = ENABLE ;
gnu_debuglink_filename = optarg;
break;
 
case 'K':
add_specific_symbol (optarg, keep_specific_htab);
break;
 
case 'N':
add_specific_symbol (optarg, strip_specific_htab);
break;
 
case OPTION_STRIP_UNNEEDED_SYMBOL:
add_specific_symbol (optarg, strip_unneeded_htab);
break;
 
case 'L':
add_specific_symbol (optarg, localize_specific_htab);
break;
 
case OPTION_GLOBALIZE_SYMBOL:
add_specific_symbol (optarg, globalize_specific_htab);
break;
 
case 'G':
add_specific_symbol (optarg, keepglobal_specific_htab);
break;
 
case 'W':
add_specific_symbol (optarg, weaken_specific_htab);
break;
 
case 'p':
preserve_dates = TRUE;
break;
 
case 'D':
deterministic = TRUE;
break;
 
case 'U':
deterministic = FALSE;
break;
 
case 'w':
wildcard = TRUE;
break;
 
case 'x':
discard_locals = LOCALS_ALL;
break;
 
case 'X':
discard_locals = LOCALS_START_L;
break;
 
case 'v':
verbose = TRUE;
break;
 
case 'V':
show_version = TRUE;
break;
 
case OPTION_FORMATS_INFO:
formats_info = TRUE;
break;
 
case OPTION_WEAKEN:
weaken = TRUE;
break;
 
case OPTION_ADD_SECTION:
{
const char *s;
size_t off, alloc;
struct section_add *pa;
FILE *f;
 
s = strchr (optarg, '=');
 
if (s == NULL)
fatal (_("bad format for %s"), "--add-section");
 
pa = (struct section_add *) xmalloc (sizeof (struct section_add));
pa->name = xstrndup (optarg, s - optarg);
pa->filename = s + 1;
 
/* We don't use get_file_size so that we can do
--add-section .note.GNU_stack=/dev/null
get_file_size doesn't work on /dev/null. */
 
f = fopen (pa->filename, FOPEN_RB);
if (f == NULL)
fatal (_("cannot open: %s: %s"),
pa->filename, strerror (errno));
 
off = 0;
alloc = 4096;
pa->contents = (bfd_byte *) xmalloc (alloc);
while (!feof (f))
{
off_t got;
 
if (off == alloc)
{
alloc <<= 1;
pa->contents = (bfd_byte *) xrealloc (pa->contents, alloc);
}
 
got = fread (pa->contents + off, 1, alloc - off, f);
if (ferror (f))
fatal (_("%s: fread failed"), pa->filename);
 
off += got;
}
 
pa->size = off;
 
fclose (f);
 
pa->next = add_sections;
add_sections = pa;
}
break;
 
case OPTION_CHANGE_START:
change_start = parse_vma (optarg, "--change-start");
break;
 
case OPTION_CHANGE_SECTION_ADDRESS:
case OPTION_CHANGE_SECTION_LMA:
case OPTION_CHANGE_SECTION_VMA:
{
struct section_list * p;
unsigned int context = 0;
const char *s;
int len;
char *name;
char *option = NULL;
bfd_vma val;
 
switch (c)
{
case OPTION_CHANGE_SECTION_ADDRESS:
option = "--change-section-address";
context = SECTION_CONTEXT_ALTER_LMA | SECTION_CONTEXT_ALTER_VMA;
break;
case OPTION_CHANGE_SECTION_LMA:
option = "--change-section-lma";
context = SECTION_CONTEXT_ALTER_LMA;
break;
case OPTION_CHANGE_SECTION_VMA:
option = "--change-section-vma";
context = SECTION_CONTEXT_ALTER_VMA;
break;
}
 
s = strchr (optarg, '=');
if (s == NULL)
{
s = strchr (optarg, '+');
if (s == NULL)
{
s = strchr (optarg, '-');
if (s == NULL)
fatal (_("bad format for %s"), option);
}
}
else
{
/* Correct the context. */
switch (c)
{
case OPTION_CHANGE_SECTION_ADDRESS:
context = SECTION_CONTEXT_SET_LMA | SECTION_CONTEXT_SET_VMA;
break;
case OPTION_CHANGE_SECTION_LMA:
context = SECTION_CONTEXT_SET_LMA;
break;
case OPTION_CHANGE_SECTION_VMA:
context = SECTION_CONTEXT_SET_VMA;
break;
}
}
 
len = s - optarg;
name = (char *) xmalloc (len + 1);
strncpy (name, optarg, len);
name[len] = '\0';
 
p = find_section_list (name, TRUE, context);
 
val = parse_vma (s + 1, option);
if (*s == '-')
val = - val;
 
switch (c)
{
case OPTION_CHANGE_SECTION_ADDRESS:
p->vma_val = val;
/* Drop through. */
 
case OPTION_CHANGE_SECTION_LMA:
p->lma_val = val;
break;
 
case OPTION_CHANGE_SECTION_VMA:
p->vma_val = val;
break;
}
}
break;
 
case OPTION_CHANGE_ADDRESSES:
change_section_address = parse_vma (optarg, "--change-addresses");
change_start = change_section_address;
break;
 
case OPTION_CHANGE_WARNINGS:
change_warn = TRUE;
break;
 
case OPTION_CHANGE_LEADING_CHAR:
change_leading_char = TRUE;
break;
 
case OPTION_COMPRESS_DEBUG_SECTIONS:
do_debug_sections = compress;
break;
 
case OPTION_DEBUGGING:
convert_debugging = TRUE;
break;
 
case OPTION_DECOMPRESS_DEBUG_SECTIONS:
do_debug_sections = decompress;
break;
 
case OPTION_GAP_FILL:
{
bfd_vma gap_fill_vma;
 
gap_fill_vma = parse_vma (optarg, "--gap-fill");
gap_fill = (bfd_byte) gap_fill_vma;
if ((bfd_vma) gap_fill != gap_fill_vma)
{
char buff[20];
 
sprintf_vma (buff, gap_fill_vma);
 
non_fatal (_("Warning: truncating gap-fill from 0x%s to 0x%x"),
buff, gap_fill);
}
gap_fill_set = TRUE;
}
break;
 
case OPTION_NO_CHANGE_WARNINGS:
change_warn = FALSE;
break;
 
case OPTION_PAD_TO:
pad_to = parse_vma (optarg, "--pad-to");
pad_to_set = TRUE;
break;
 
case OPTION_REMOVE_LEADING_CHAR:
remove_leading_char = TRUE;
break;
 
case OPTION_REDEFINE_SYM:
{
/* Push this redefinition onto redefine_symbol_list. */
 
int len;
const char *s;
const char *nextarg;
char *source, *target;
 
s = strchr (optarg, '=');
if (s == NULL)
fatal (_("bad format for %s"), "--redefine-sym");
 
len = s - optarg;
source = (char *) xmalloc (len + 1);
strncpy (source, optarg, len);
source[len] = '\0';
 
nextarg = s + 1;
len = strlen (nextarg);
target = (char *) xmalloc (len + 1);
strcpy (target, nextarg);
 
redefine_list_append ("--redefine-sym", source, target);
 
free (source);
free (target);
}
break;
 
case OPTION_REDEFINE_SYMS:
add_redefine_syms_file (optarg);
break;
 
case OPTION_SET_SECTION_FLAGS:
{
struct section_list *p;
const char *s;
int len;
char *name;
 
s = strchr (optarg, '=');
if (s == NULL)
fatal (_("bad format for %s"), "--set-section-flags");
 
len = s - optarg;
name = (char *) xmalloc (len + 1);
strncpy (name, optarg, len);
name[len] = '\0';
 
p = find_section_list (name, TRUE, SECTION_CONTEXT_SET_FLAGS);
 
p->flags = parse_flags (s + 1);
}
break;
 
case OPTION_RENAME_SECTION:
{
flagword flags;
const char *eq, *fl;
char *old_name;
char *new_name;
unsigned int len;
 
eq = strchr (optarg, '=');
if (eq == NULL)
fatal (_("bad format for %s"), "--rename-section");
 
len = eq - optarg;
if (len == 0)
fatal (_("bad format for %s"), "--rename-section");
 
old_name = (char *) xmalloc (len + 1);
strncpy (old_name, optarg, len);
old_name[len] = 0;
 
eq++;
fl = strchr (eq, ',');
if (fl)
{
flags = parse_flags (fl + 1);
len = fl - eq;
}
else
{
flags = -1;
len = strlen (eq);
}
 
if (len == 0)
fatal (_("bad format for %s"), "--rename-section");
 
new_name = (char *) xmalloc (len + 1);
strncpy (new_name, eq, len);
new_name[len] = 0;
 
add_section_rename (old_name, new_name, flags);
}
break;
 
case OPTION_SET_START:
set_start = parse_vma (optarg, "--set-start");
set_start_set = TRUE;
break;
 
case OPTION_SREC_LEN:
Chunk = parse_vma (optarg, "--srec-len");
break;
 
case OPTION_SREC_FORCES3:
S3Forced = TRUE;
break;
 
case OPTION_STRIP_SYMBOLS:
add_specific_symbols (optarg, strip_specific_htab);
break;
 
case OPTION_STRIP_UNNEEDED_SYMBOLS:
add_specific_symbols (optarg, strip_unneeded_htab);
break;
 
case OPTION_KEEP_SYMBOLS:
add_specific_symbols (optarg, keep_specific_htab);
break;
 
case OPTION_LOCALIZE_HIDDEN:
localize_hidden = TRUE;
break;
 
case OPTION_LOCALIZE_SYMBOLS:
add_specific_symbols (optarg, localize_specific_htab);
break;
 
case OPTION_LONG_SECTION_NAMES:
if (!strcmp ("enable", optarg))
long_section_names = ENABLE;
else if (!strcmp ("disable", optarg))
long_section_names = DISABLE;
else if (!strcmp ("keep", optarg))
long_section_names = KEEP;
else
fatal (_("unknown long section names option '%s'"), optarg);
break;
 
case OPTION_GLOBALIZE_SYMBOLS:
add_specific_symbols (optarg, globalize_specific_htab);
break;
 
case OPTION_KEEPGLOBAL_SYMBOLS:
add_specific_symbols (optarg, keepglobal_specific_htab);
break;
 
case OPTION_WEAKEN_SYMBOLS:
add_specific_symbols (optarg, weaken_specific_htab);
break;
 
case OPTION_ALT_MACH_CODE:
use_alt_mach_code = strtoul (optarg, NULL, 0);
if (use_alt_mach_code == 0)
fatal (_("unable to parse alternative machine code"));
break;
 
case OPTION_PREFIX_SYMBOLS:
prefix_symbols_string = optarg;
break;
 
case OPTION_PREFIX_SECTIONS:
prefix_sections_string = optarg;
break;
 
case OPTION_PREFIX_ALLOC_SECTIONS:
prefix_alloc_sections_string = optarg;
break;
 
case OPTION_READONLY_TEXT:
bfd_flags_to_set |= WP_TEXT;
bfd_flags_to_clear &= ~WP_TEXT;
break;
 
case OPTION_WRITABLE_TEXT:
bfd_flags_to_clear |= WP_TEXT;
bfd_flags_to_set &= ~WP_TEXT;
break;
 
case OPTION_PURE:
bfd_flags_to_set |= D_PAGED;
bfd_flags_to_clear &= ~D_PAGED;
break;
 
case OPTION_IMPURE:
bfd_flags_to_clear |= D_PAGED;
bfd_flags_to_set &= ~D_PAGED;
break;
 
case OPTION_EXTRACT_DWO:
strip_symbols = STRIP_NONDWO;
break;
 
case OPTION_EXTRACT_SYMBOL:
extract_symbol = TRUE;
break;
 
case OPTION_REVERSE_BYTES:
{
int prev = reverse_bytes;
 
reverse_bytes = atoi (optarg);
if ((reverse_bytes <= 0) || ((reverse_bytes % 2) != 0))
fatal (_("number of bytes to reverse must be positive and even"));
 
if (prev && prev != reverse_bytes)
non_fatal (_("Warning: ignoring previous --reverse-bytes value of %d"),
prev);
break;
}
 
case OPTION_FILE_ALIGNMENT:
pe_file_alignment = parse_vma (optarg, "--file-alignment");
break;
 
case OPTION_HEAP:
{
char *end;
pe_heap_reserve = strtoul (optarg, &end, 0);
if (end == optarg
|| (*end != '.' && *end != '\0'))
non_fatal (_("%s: invalid reserve value for --heap"),
optarg);
else if (*end != '\0')
{
pe_heap_commit = strtoul (end + 1, &end, 0);
if (*end != '\0')
non_fatal (_("%s: invalid commit value for --heap"),
optarg);
}
}
break;
 
case OPTION_IMAGE_BASE:
pe_image_base = parse_vma (optarg, "--image-base");
break;
 
case OPTION_SECTION_ALIGNMENT:
pe_section_alignment = parse_vma (optarg,
"--section-alignment");
break;
 
case OPTION_SUBSYSTEM:
set_pe_subsystem (optarg);
break;
 
case OPTION_STACK:
{
char *end;
pe_stack_reserve = strtoul (optarg, &end, 0);
if (end == optarg
|| (*end != '.' && *end != '\0'))
non_fatal (_("%s: invalid reserve value for --stack"),
optarg);
else if (*end != '\0')
{
pe_stack_commit = strtoul (end + 1, &end, 0);
if (*end != '\0')
non_fatal (_("%s: invalid commit value for --stack"),
optarg);
}
}
break;
 
case 0:
/* We've been given a long option. */
break;
 
case 'H':
case 'h':
copy_usage (stdout, 0);
 
default:
copy_usage (stderr, 1);
}
}
 
if (formats_info)
{
display_info ();
return 0;
}
 
if (show_version)
print_version ("objcopy");
 
if (interleave && copy_byte == -1)
fatal (_("interleave start byte must be set with --byte"));
 
if (copy_byte >= interleave)
fatal (_("byte number must be less than interleave"));
 
if (copy_width > interleave - copy_byte)
fatal (_("interleave width must be less than or equal to interleave - byte`"));
 
if (optind == argc || optind + 2 < argc)
copy_usage (stderr, 1);
 
input_filename = argv[optind];
if (optind + 1 < argc)
output_filename = argv[optind + 1];
 
default_deterministic ();
 
/* Default is to strip no symbols. */
if (strip_symbols == STRIP_UNDEF && discard_locals == LOCALS_UNDEF)
strip_symbols = STRIP_NONE;
 
if (output_target == NULL)
output_target = input_target;
 
/* Convert input EFI target to PEI target. */
if (input_target != NULL
&& strncmp (input_target, "efi-", 4) == 0)
{
char *efi;
 
efi = xstrdup (output_target + 4);
if (strncmp (efi, "bsdrv-", 6) == 0
|| strncmp (efi, "rtdrv-", 6) == 0)
efi += 2;
else if (strncmp (efi, "app-", 4) != 0)
fatal (_("unknown input EFI target: %s"), input_target);
 
input_target = efi;
convert_efi_target (efi);
}
 
/* Convert output EFI target to PEI target. */
if (output_target != NULL
&& strncmp (output_target, "efi-", 4) == 0)
{
char *efi;
 
efi = xstrdup (output_target + 4);
if (strncmp (efi, "app-", 4) == 0)
{
if (pe_subsystem == -1)
pe_subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
}
else if (strncmp (efi, "bsdrv-", 6) == 0)
{
if (pe_subsystem == -1)
pe_subsystem = IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
efi += 2;
}
else if (strncmp (efi, "rtdrv-", 6) == 0)
{
if (pe_subsystem == -1)
pe_subsystem = IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
efi += 2;
}
else
fatal (_("unknown output EFI target: %s"), output_target);
 
if (pe_file_alignment == (bfd_vma) -1)
pe_file_alignment = PE_DEF_FILE_ALIGNMENT;
if (pe_section_alignment == (bfd_vma) -1)
pe_section_alignment = PE_DEF_SECTION_ALIGNMENT;
 
output_target = efi;
convert_efi_target (efi);
}
 
if (preserve_dates)
if (stat (input_filename, & statbuf) < 0)
fatal (_("warning: could not locate '%s'. System error message: %s"),
input_filename, strerror (errno));
 
/* If there is no destination file, or the source and destination files
are the same, then create a temp and rename the result into the input. */
if (output_filename == NULL
|| filename_cmp (input_filename, output_filename) == 0)
tmpname = make_tempname (input_filename);
else
tmpname = output_filename;
 
if (tmpname == NULL)
fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"),
input_filename, strerror (errno));
 
copy_file (input_filename, tmpname, input_target, output_target, input_arch);
if (status == 0)
{
if (preserve_dates)
set_times (tmpname, &statbuf);
if (tmpname != output_filename)
status = (smart_rename (tmpname, input_filename,
preserve_dates) != 0);
}
else
unlink_if_ordinary (tmpname);
 
if (change_warn)
{
struct section_list *p;
 
for (p = change_sections; p != NULL; p = p->next)
{
if (! p->used)
{
if (p->context & (SECTION_CONTEXT_SET_VMA | SECTION_CONTEXT_ALTER_VMA))
{
char buff [20];
 
sprintf_vma (buff, p->vma_val);
 
/* xgettext:c-format */
non_fatal (_("%s %s%c0x%s never used"),
"--change-section-vma",
p->pattern,
p->context & SECTION_CONTEXT_SET_VMA ? '=' : '+',
buff);
}
 
if (p->context & (SECTION_CONTEXT_SET_LMA | SECTION_CONTEXT_ALTER_LMA))
{
char buff [20];
 
sprintf_vma (buff, p->lma_val);
 
/* xgettext:c-format */
non_fatal (_("%s %s%c0x%s never used"),
"--change-section-lma",
p->pattern,
p->context & SECTION_CONTEXT_SET_LMA ? '=' : '+',
buff);
}
}
}
}
 
return 0;
}
 
int
main (int argc, char *argv[])
{
#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
setlocale (LC_MESSAGES, "");
#endif
#if defined (HAVE_SETLOCALE)
setlocale (LC_CTYPE, "");
#endif
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
 
program_name = argv[0];
xmalloc_set_program_name (program_name);
 
START_PROGRESS (program_name, 0);
 
expandargv (&argc, &argv);
 
strip_symbols = STRIP_UNDEF;
discard_locals = LOCALS_UNDEF;
 
bfd_init ();
set_default_bfd_target ();
 
if (is_strip < 0)
{
int i = strlen (program_name);
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
/* Drop the .exe suffix, if any. */
if (i > 4 && FILENAME_CMP (program_name + i - 4, ".exe") == 0)
{
i -= 4;
program_name[i] = '\0';
}
#endif
is_strip = (i >= 5 && FILENAME_CMP (program_name + i - 5, "strip") == 0);
}
 
create_symbol_htabs ();
 
if (is_strip)
strip_main (argc, argv);
else
copy_main (argc, argv);
 
END_PROGRESS (program_name);
 
return status;
}
/contrib/toolchain/binutils/binutils/rdcoff.c
0,0 → 1,876
/* stabs.c -- Parse COFF debugging information
Copyright 1996, 1999, 2000, 2002, 2003, 2005, 2007
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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
/* This file contains code which parses COFF debugging information. */
 
#include "sysdep.h"
#include "bfd.h"
#include "coff/internal.h"
#include "libiberty.h"
#include "bucomm.h"
#include "debug.h"
#include "budbg.h"
 
/* FIXME: We should not need this BFD internal file. We need it for
the N_BTMASK, etc., values. */
#include "libcoff.h"
 
/* These macros extract the right mask and shifts for this BFD. They
assume that there is a local variable named ABFD. This is so that
macros like ISFCN and DECREF, from coff/internal.h, will work
without modification. */
#define N_BTMASK (coff_data (abfd)->local_n_btmask)
#define N_BTSHFT (coff_data (abfd)->local_n_btshft)
#define N_TMASK (coff_data (abfd)->local_n_tmask)
#define N_TSHIFT (coff_data (abfd)->local_n_tshift)
 
/* This structure is used to hold the symbols, as well as the current
location within the symbols. */
 
struct coff_symbols
{
/* The symbols. */
asymbol **syms;
/* The number of symbols. */
long symcount;
/* The index of the current symbol. */
long symno;
/* The index of the current symbol in the COFF symbol table (where
each auxent counts as a symbol). */
long coff_symno;
};
 
/* The largest basic type we are prepared to handle. */
 
#define T_MAX (T_LNGDBL)
 
/* This structure is used to hold slots. */
 
struct coff_slots
{
/* Next set of slots. */
struct coff_slots *next;
/* Slots. */
#define COFF_SLOTS (16)
debug_type slots[COFF_SLOTS];
};
 
/* This structure is used to map symbol indices to types. */
 
struct coff_types
{
/* Slots. */
struct coff_slots *slots;
/* Basic types. */
debug_type basic[T_MAX + 1];
};
 
static debug_type *coff_get_slot (struct coff_types *, int);
static debug_type parse_coff_type
(bfd *, struct coff_symbols *, struct coff_types *, long, int,
union internal_auxent *, bfd_boolean, void *);
static debug_type parse_coff_base_type
(bfd *, struct coff_symbols *, struct coff_types *, long, int,
union internal_auxent *, void *);
static debug_type parse_coff_struct_type
(bfd *, struct coff_symbols *, struct coff_types *, int,
union internal_auxent *, void *);
static debug_type parse_coff_enum_type
(bfd *, struct coff_symbols *, struct coff_types *,
union internal_auxent *, void *);
static bfd_boolean parse_coff_symbol
(bfd *, struct coff_types *, asymbol *, long, struct internal_syment *,
void *, debug_type, bfd_boolean);
static bfd_boolean external_coff_symbol_p (int sym_class);
/* Return the slot for a type. */
 
static debug_type *
coff_get_slot (struct coff_types *types, int indx)
{
struct coff_slots **pps;
 
pps = &types->slots;
 
while (indx >= COFF_SLOTS)
{
if (*pps == NULL)
{
*pps = (struct coff_slots *) xmalloc (sizeof **pps);
memset (*pps, 0, sizeof **pps);
}
pps = &(*pps)->next;
indx -= COFF_SLOTS;
}
 
if (*pps == NULL)
{
*pps = (struct coff_slots *) xmalloc (sizeof **pps);
memset (*pps, 0, sizeof **pps);
}
 
return (*pps)->slots + indx;
}
 
/* Parse a COFF type code in NTYPE. */
 
static debug_type
parse_coff_type (bfd *abfd, struct coff_symbols *symbols,
struct coff_types *types, long coff_symno, int ntype,
union internal_auxent *pauxent, bfd_boolean useaux,
void *dhandle)
{
debug_type type;
 
if ((ntype & ~N_BTMASK) != 0)
{
int newtype;
 
newtype = DECREF (ntype);
 
if (ISPTR (ntype))
{
type = parse_coff_type (abfd, symbols, types, coff_symno, newtype,
pauxent, useaux, dhandle);
type = debug_make_pointer_type (dhandle, type);
}
else if (ISFCN (ntype))
{
type = parse_coff_type (abfd, symbols, types, coff_symno, newtype,
pauxent, useaux, dhandle);
type = debug_make_function_type (dhandle, type, (debug_type *) NULL,
FALSE);
}
else if (ISARY (ntype))
{
int n;
 
if (pauxent == NULL)
n = 0;
else
{
unsigned short *dim;
int i;
 
/* FIXME: If pauxent->x_sym.x_tagndx.l == 0, gdb sets
the c_naux field of the syment to 0. */
 
/* Move the dimensions down, so that the next array
picks up the next one. */
dim = pauxent->x_sym.x_fcnary.x_ary.x_dimen;
n = dim[0];
for (i = 0; *dim != 0 && i < DIMNUM - 1; i++, dim++)
*dim = *(dim + 1);
*dim = 0;
}
 
type = parse_coff_type (abfd, symbols, types, coff_symno, newtype,
pauxent, FALSE, dhandle);
type = debug_make_array_type (dhandle, type,
parse_coff_base_type (abfd, symbols,
types,
coff_symno,
T_INT,
NULL, dhandle),
0, n - 1, FALSE);
}
else
{
non_fatal (_("parse_coff_type: Bad type code 0x%x"), ntype);
return DEBUG_TYPE_NULL;
}
 
return type;
}
 
if (pauxent != NULL && pauxent->x_sym.x_tagndx.l > 0)
{
debug_type *slot;
 
/* This is a reference to an existing type. FIXME: gdb checks
that the class is not C_STRTAG, nor C_UNTAG, nor C_ENTAG. */
slot = coff_get_slot (types, pauxent->x_sym.x_tagndx.l);
if (*slot != DEBUG_TYPE_NULL)
return *slot;
else
return debug_make_indirect_type (dhandle, slot, (const char *) NULL);
}
 
/* If the aux entry has already been used for something, useaux will
have been set to false, indicating that parse_coff_base_type
should not use it. We need to do it this way, rather than simply
passing pauxent as NULL, because we need to be able handle
multiple array dimensions while still discarding pauxent after
having handled all of them. */
if (! useaux)
pauxent = NULL;
 
return parse_coff_base_type (abfd, symbols, types, coff_symno, ntype,
pauxent, dhandle);
}
 
/* Parse a basic COFF type in NTYPE. */
 
static debug_type
parse_coff_base_type (bfd *abfd, struct coff_symbols *symbols,
struct coff_types *types, long coff_symno, int ntype,
union internal_auxent *pauxent, void *dhandle)
{
debug_type ret;
bfd_boolean set_basic;
const char *name;
debug_type *slot;
 
if (ntype >= 0
&& ntype <= T_MAX
&& types->basic[ntype] != DEBUG_TYPE_NULL)
return types->basic[ntype];
 
set_basic = TRUE;
name = NULL;
 
switch (ntype)
{
default:
ret = debug_make_void_type (dhandle);
break;
 
case T_NULL:
case T_VOID:
ret = debug_make_void_type (dhandle);
name = "void";
break;
 
case T_CHAR:
ret = debug_make_int_type (dhandle, 1, FALSE);
name = "char";
break;
 
case T_SHORT:
ret = debug_make_int_type (dhandle, 2, FALSE);
name = "short";
break;
 
case T_INT:
/* FIXME: Perhaps the size should depend upon the architecture. */
ret = debug_make_int_type (dhandle, 4, FALSE);
name = "int";
break;
 
case T_LONG:
ret = debug_make_int_type (dhandle, 4, FALSE);
name = "long";
break;
 
case T_FLOAT:
ret = debug_make_float_type (dhandle, 4);
name = "float";
break;
 
case T_DOUBLE:
ret = debug_make_float_type (dhandle, 8);
name = "double";
break;
 
case T_LNGDBL:
ret = debug_make_float_type (dhandle, 12);
name = "long double";
break;
 
case T_UCHAR:
ret = debug_make_int_type (dhandle, 1, TRUE);
name = "unsigned char";
break;
 
case T_USHORT:
ret = debug_make_int_type (dhandle, 2, TRUE);
name = "unsigned short";
break;
 
case T_UINT:
ret = debug_make_int_type (dhandle, 4, TRUE);
name = "unsigned int";
break;
 
case T_ULONG:
ret = debug_make_int_type (dhandle, 4, TRUE);
name = "unsigned long";
break;
 
case T_STRUCT:
if (pauxent == NULL)
ret = debug_make_struct_type (dhandle, TRUE, 0,
(debug_field *) NULL);
else
ret = parse_coff_struct_type (abfd, symbols, types, ntype, pauxent,
dhandle);
 
slot = coff_get_slot (types, coff_symno);
*slot = ret;
 
set_basic = FALSE;
break;
 
case T_UNION:
if (pauxent == NULL)
ret = debug_make_struct_type (dhandle, FALSE, 0, (debug_field *) NULL);
else
ret = parse_coff_struct_type (abfd, symbols, types, ntype, pauxent,
dhandle);
 
slot = coff_get_slot (types, coff_symno);
*slot = ret;
 
set_basic = FALSE;
break;
 
case T_ENUM:
if (pauxent == NULL)
ret = debug_make_enum_type (dhandle, (const char **) NULL,
(bfd_signed_vma *) NULL);
else
ret = parse_coff_enum_type (abfd, symbols, types, pauxent, dhandle);
 
slot = coff_get_slot (types, coff_symno);
*slot = ret;
 
set_basic = FALSE;
break;
}
 
if (name != NULL)
ret = debug_name_type (dhandle, name, ret);
 
if (set_basic
&& ntype >= 0
&& ntype <= T_MAX)
types->basic[ntype] = ret;
 
return ret;
}
 
/* Parse a struct type. */
 
static debug_type
parse_coff_struct_type (bfd *abfd, struct coff_symbols *symbols,
struct coff_types *types, int ntype,
union internal_auxent *pauxent, void *dhandle)
{
long symend;
int alloc;
debug_field *fields;
int count;
bfd_boolean done;
 
symend = pauxent->x_sym.x_fcnary.x_fcn.x_endndx.l;
 
alloc = 10;
fields = (debug_field *) xmalloc (alloc * sizeof *fields);
count = 0;
 
done = FALSE;
while (! done
&& symbols->coff_symno < symend
&& symbols->symno < symbols->symcount)
{
asymbol *sym;
long this_coff_symno;
struct internal_syment syment;
union internal_auxent auxent;
union internal_auxent *psubaux;
bfd_vma bitpos = 0, bitsize = 0;
 
sym = symbols->syms[symbols->symno];
 
if (! bfd_coff_get_syment (abfd, sym, &syment))
{
non_fatal (_("bfd_coff_get_syment failed: %s"),
bfd_errmsg (bfd_get_error ()));
return DEBUG_TYPE_NULL;
}
 
this_coff_symno = symbols->coff_symno;
 
++symbols->symno;
symbols->coff_symno += 1 + syment.n_numaux;
 
if (syment.n_numaux == 0)
psubaux = NULL;
else
{
if (! bfd_coff_get_auxent (abfd, sym, 0, &auxent))
{
non_fatal (_("bfd_coff_get_auxent failed: %s"),
bfd_errmsg (bfd_get_error ()));
return DEBUG_TYPE_NULL;
}
psubaux = &auxent;
}
 
switch (syment.n_sclass)
{
case C_MOS:
case C_MOU:
bitpos = 8 * bfd_asymbol_value (sym);
bitsize = 0;
break;
 
case C_FIELD:
bitpos = bfd_asymbol_value (sym);
bitsize = auxent.x_sym.x_misc.x_lnsz.x_size;
break;
 
case C_EOS:
done = TRUE;
break;
}
 
if (! done)
{
debug_type ftype;
debug_field f;
 
ftype = parse_coff_type (abfd, symbols, types, this_coff_symno,
syment.n_type, psubaux, TRUE, dhandle);
f = debug_make_field (dhandle, bfd_asymbol_name (sym), ftype,
bitpos, bitsize, DEBUG_VISIBILITY_PUBLIC);
if (f == DEBUG_FIELD_NULL)
return DEBUG_TYPE_NULL;
 
if (count + 1 >= alloc)
{
alloc += 10;
fields = ((debug_field *)
xrealloc (fields, alloc * sizeof *fields));
}
 
fields[count] = f;
++count;
}
}
 
fields[count] = DEBUG_FIELD_NULL;
 
return debug_make_struct_type (dhandle, ntype == T_STRUCT,
pauxent->x_sym.x_misc.x_lnsz.x_size,
fields);
}
 
/* Parse an enum type. */
 
static debug_type
parse_coff_enum_type (bfd *abfd, struct coff_symbols *symbols,
struct coff_types *types ATTRIBUTE_UNUSED,
union internal_auxent *pauxent, void *dhandle)
{
long symend;
int alloc;
const char **names;
bfd_signed_vma *vals;
int count;
bfd_boolean done;
 
symend = pauxent->x_sym.x_fcnary.x_fcn.x_endndx.l;
 
alloc = 10;
names = (const char **) xmalloc (alloc * sizeof *names);
vals = (bfd_signed_vma *) xmalloc (alloc * sizeof *vals);
count = 0;
 
done = FALSE;
while (! done
&& symbols->coff_symno < symend
&& symbols->symno < symbols->symcount)
{
asymbol *sym;
struct internal_syment syment;
 
sym = symbols->syms[symbols->symno];
 
if (! bfd_coff_get_syment (abfd, sym, &syment))
{
non_fatal (_("bfd_coff_get_syment failed: %s"),
bfd_errmsg (bfd_get_error ()));
return DEBUG_TYPE_NULL;
}
 
++symbols->symno;
symbols->coff_symno += 1 + syment.n_numaux;
 
switch (syment.n_sclass)
{
case C_MOE:
if (count + 1 >= alloc)
{
alloc += 10;
names = ((const char **)
xrealloc (names, alloc * sizeof *names));
vals = ((bfd_signed_vma *)
xrealloc (vals, alloc * sizeof *vals));
}
 
names[count] = bfd_asymbol_name (sym);
vals[count] = bfd_asymbol_value (sym);
++count;
break;
 
case C_EOS:
done = TRUE;
break;
}
}
 
names[count] = NULL;
 
return debug_make_enum_type (dhandle, names, vals);
}
 
/* Handle a single COFF symbol. */
 
static bfd_boolean
parse_coff_symbol (bfd *abfd ATTRIBUTE_UNUSED, struct coff_types *types,
asymbol *sym, long coff_symno,
struct internal_syment *psyment, void *dhandle,
debug_type type, bfd_boolean within_function)
{
switch (psyment->n_sclass)
{
case C_NULL:
break;
 
case C_AUTO:
if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type,
DEBUG_LOCAL, bfd_asymbol_value (sym)))
return FALSE;
break;
 
case C_WEAKEXT:
case C_EXT:
if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type,
DEBUG_GLOBAL, bfd_asymbol_value (sym)))
return FALSE;
break;
 
case C_STAT:
if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type,
(within_function
? DEBUG_LOCAL_STATIC
: DEBUG_STATIC),
bfd_asymbol_value (sym)))
return FALSE;
break;
 
case C_REG:
/* FIXME: We may need to convert the register number. */
if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type,
DEBUG_REGISTER, bfd_asymbol_value (sym)))
return FALSE;
break;
 
case C_LABEL:
break;
 
case C_ARG:
if (! debug_record_parameter (dhandle, bfd_asymbol_name (sym), type,
DEBUG_PARM_STACK, bfd_asymbol_value (sym)))
return FALSE;
break;
 
case C_REGPARM:
/* FIXME: We may need to convert the register number. */
if (! debug_record_parameter (dhandle, bfd_asymbol_name (sym), type,
DEBUG_PARM_REG, bfd_asymbol_value (sym)))
return FALSE;
break;
 
case C_TPDEF:
type = debug_name_type (dhandle, bfd_asymbol_name (sym), type);
if (type == DEBUG_TYPE_NULL)
return FALSE;
break;
 
case C_STRTAG:
case C_UNTAG:
case C_ENTAG:
{
debug_type *slot;
 
type = debug_tag_type (dhandle, bfd_asymbol_name (sym), type);
if (type == DEBUG_TYPE_NULL)
return FALSE;
 
/* Store the named type into the slot, so that references get
the name. */
slot = coff_get_slot (types, coff_symno);
*slot = type;
}
break;
 
default:
break;
}
 
return TRUE;
}
 
/* Determine if a symbol has external visibility. */
 
static bfd_boolean
external_coff_symbol_p (int sym_class)
{
switch (sym_class)
{
case C_EXT:
case C_WEAKEXT:
return TRUE;
default:
break;
}
return FALSE;
}
 
/* This is the main routine. It looks through all the symbols and
handles them. */
 
bfd_boolean
parse_coff (bfd *abfd, asymbol **syms, long symcount, void *dhandle)
{
struct coff_symbols symbols;
struct coff_types types;
int i;
long next_c_file;
const char *fnname;
int fnclass;
int fntype;
bfd_vma fnend;
alent *linenos;
bfd_boolean within_function;
long this_coff_symno;
 
symbols.syms = syms;
symbols.symcount = symcount;
symbols.symno = 0;
symbols.coff_symno = 0;
 
types.slots = NULL;
for (i = 0; i <= T_MAX; i++)
types.basic[i] = DEBUG_TYPE_NULL;
 
next_c_file = -1;
fnname = NULL;
fnclass = 0;
fntype = 0;
fnend = 0;
linenos = NULL;
within_function = FALSE;
 
while (symbols.symno < symcount)
{
asymbol *sym;
const char *name;
struct internal_syment syment;
union internal_auxent auxent;
union internal_auxent *paux;
debug_type type;
 
sym = syms[symbols.symno];
 
if (! bfd_coff_get_syment (abfd, sym, &syment))
{
non_fatal (_("bfd_coff_get_syment failed: %s"),
bfd_errmsg (bfd_get_error ()));
return FALSE;
}
 
name = bfd_asymbol_name (sym);
 
this_coff_symno = symbols.coff_symno;
 
++symbols.symno;
symbols.coff_symno += 1 + syment.n_numaux;
 
/* We only worry about the first auxent, because that is the
only one which is relevant for debugging information. */
if (syment.n_numaux == 0)
paux = NULL;
else
{
if (! bfd_coff_get_auxent (abfd, sym, 0, &auxent))
{
non_fatal (_("bfd_coff_get_auxent failed: %s"),
bfd_errmsg (bfd_get_error ()));
return FALSE;
}
paux = &auxent;
}
 
if (this_coff_symno == next_c_file && syment.n_sclass != C_FILE)
{
/* The last C_FILE symbol points to the first external
symbol. */
if (! debug_set_filename (dhandle, "*globals*"))
return FALSE;
}
 
switch (syment.n_sclass)
{
case C_EFCN:
case C_EXTDEF:
case C_ULABEL:
case C_USTATIC:
case C_LINE:
case C_ALIAS:
case C_HIDDEN:
/* Just ignore these classes. */
break;
 
case C_FILE:
next_c_file = syment.n_value;
if (! debug_set_filename (dhandle, name))
return FALSE;
break;
 
case C_STAT:
/* Ignore static symbols with a type of T_NULL. These
represent section entries. */
if (syment.n_type == T_NULL)
break;
/* Fall through. */
case C_WEAKEXT:
case C_EXT:
if (ISFCN (syment.n_type))
{
fnname = name;
fnclass = syment.n_sclass;
fntype = syment.n_type;
if (syment.n_numaux > 0)
fnend = bfd_asymbol_value (sym) + auxent.x_sym.x_misc.x_fsize;
else
fnend = 0;
linenos = BFD_SEND (abfd, _get_lineno, (abfd, sym));
break;
}
type = parse_coff_type (abfd, &symbols, &types, this_coff_symno,
syment.n_type, paux, TRUE, dhandle);
if (type == DEBUG_TYPE_NULL)
return FALSE;
if (! parse_coff_symbol (abfd, &types, sym, this_coff_symno, &syment,
dhandle, type, within_function))
return FALSE;
break;
 
case C_FCN:
if (strcmp (name, ".bf") == 0)
{
if (fnname == NULL)
{
non_fatal (_("%ld: .bf without preceding function"),
this_coff_symno);
return FALSE;
}
 
type = parse_coff_type (abfd, &symbols, &types, this_coff_symno,
DECREF (fntype), paux, FALSE, dhandle);
if (type == DEBUG_TYPE_NULL)
return FALSE;
 
if (! debug_record_function (dhandle, fnname, type,
external_coff_symbol_p (fnclass),
bfd_asymbol_value (sym)))
return FALSE;
 
if (linenos != NULL)
{
int base;
bfd_vma addr;
 
if (syment.n_numaux == 0)
base = 0;
else
base = auxent.x_sym.x_misc.x_lnsz.x_lnno - 1;
 
addr = bfd_get_section_vma (abfd, bfd_get_section (sym));
 
++linenos;
 
while (linenos->line_number != 0)
{
if (! debug_record_line (dhandle,
linenos->line_number + base,
linenos->u.offset + addr))
return FALSE;
++linenos;
}
}
 
fnname = NULL;
linenos = NULL;
fnclass = 0;
fntype = 0;
 
within_function = TRUE;
}
else if (strcmp (name, ".ef") == 0)
{
if (! within_function)
{
non_fatal (_("%ld: unexpected .ef\n"), this_coff_symno);
return FALSE;
}
 
if (bfd_asymbol_value (sym) > fnend)
fnend = bfd_asymbol_value (sym);
if (! debug_end_function (dhandle, fnend))
return FALSE;
 
fnend = 0;
within_function = FALSE;
}
break;
 
case C_BLOCK:
if (strcmp (name, ".bb") == 0)
{
if (! debug_start_block (dhandle, bfd_asymbol_value (sym)))
return FALSE;
}
else if (strcmp (name, ".eb") == 0)
{
if (! debug_end_block (dhandle, bfd_asymbol_value (sym)))
return FALSE;
}
break;
 
default:
type = parse_coff_type (abfd, &symbols, &types, this_coff_symno,
syment.n_type, paux, TRUE, dhandle);
if (type == DEBUG_TYPE_NULL)
return FALSE;
if (! parse_coff_symbol (abfd, &types, sym, this_coff_symno, &syment,
dhandle, type, within_function))
return FALSE;
break;
}
}
 
return TRUE;
}
/contrib/toolchain/binutils/binutils/rddbg.c
0,0 → 1,450
/* rddbg.c -- Read debugging information into a generic form.
Copyright 1995, 1996, 1997, 2000, 2002, 2003, 2005, 2007, 2008,
2010 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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
 
/* This file reads debugging information into a generic form. This
file knows how to dig the debugging information out of an object
file. */
 
#include "sysdep.h"
#include "bfd.h"
#include "libiberty.h"
#include "bucomm.h"
#include "debug.h"
#include "budbg.h"
 
static bfd_boolean read_section_stabs_debugging_info
(bfd *, asymbol **, long, void *, bfd_boolean *);
static bfd_boolean read_symbol_stabs_debugging_info
(bfd *, asymbol **, long, void *, bfd_boolean *);
static bfd_boolean read_ieee_debugging_info (bfd *, void *, bfd_boolean *);
static void save_stab (int, int, bfd_vma, const char *);
static void stab_context (void);
static void free_saved_stabs (void);
 
/* Read debugging information from a BFD. Returns a generic debugging
pointer. */
 
void *
read_debugging_info (bfd *abfd, asymbol **syms, long symcount, bfd_boolean no_messages)
{
void *dhandle;
bfd_boolean found;
 
dhandle = debug_init ();
if (dhandle == NULL)
return NULL;
 
if (! read_section_stabs_debugging_info (abfd, syms, symcount, dhandle,
&found))
return NULL;
 
if (bfd_get_flavour (abfd) == bfd_target_aout_flavour)
{
if (! read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle,
&found))
return NULL;
}
 
if (bfd_get_flavour (abfd) == bfd_target_ieee_flavour)
{
if (! read_ieee_debugging_info (abfd, dhandle, &found))
return NULL;
}
 
/* Try reading the COFF symbols if we didn't find any stabs in COFF
sections. */
if (! found
&& bfd_get_flavour (abfd) == bfd_target_coff_flavour
&& symcount > 0)
{
if (! parse_coff (abfd, syms, symcount, dhandle))
return NULL;
found = TRUE;
}
 
if (! found)
{
if (! no_messages)
non_fatal (_("%s: no recognized debugging information"),
bfd_get_filename (abfd));
return NULL;
}
 
return dhandle;
}
 
/* Read stabs in sections debugging information from a BFD. */
 
static bfd_boolean
read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
void *dhandle, bfd_boolean *pfound)
{
static struct
{
const char *secname;
const char *strsecname;
}
names[] =
{
{ ".stab", ".stabstr" },
{ "LC_SYMTAB.stabs", "LC_SYMTAB.stabstr" },
{ "$GDB_SYMBOLS$", "$GDB_STRINGS$" }
};
unsigned int i;
void *shandle;
 
*pfound = FALSE;
shandle = NULL;
 
for (i = 0; i < sizeof names / sizeof names[0]; i++)
{
asection *sec, *strsec;
 
sec = bfd_get_section_by_name (abfd, names[i].secname);
strsec = bfd_get_section_by_name (abfd, names[i].strsecname);
if (sec != NULL && strsec != NULL)
{
bfd_size_type stabsize, strsize;
bfd_byte *stabs, *strings;
bfd_byte *stab;
bfd_size_type stroff, next_stroff;
 
stabsize = bfd_section_size (abfd, sec);
stabs = (bfd_byte *) xmalloc (stabsize);
if (! bfd_get_section_contents (abfd, sec, stabs, 0, stabsize))
{
fprintf (stderr, "%s: %s: %s\n",
bfd_get_filename (abfd), names[i].secname,
bfd_errmsg (bfd_get_error ()));
return FALSE;
}
 
strsize = bfd_section_size (abfd, strsec);
strings = (bfd_byte *) xmalloc (strsize);
if (! bfd_get_section_contents (abfd, strsec, strings, 0, strsize))
{
fprintf (stderr, "%s: %s: %s\n",
bfd_get_filename (abfd), names[i].strsecname,
bfd_errmsg (bfd_get_error ()));
return FALSE;
}
 
if (shandle == NULL)
{
shandle = start_stab (dhandle, abfd, TRUE, syms, symcount);
if (shandle == NULL)
return FALSE;
}
 
*pfound = TRUE;
 
stroff = 0;
next_stroff = 0;
for (stab = stabs; stab < stabs + stabsize; stab += 12)
{
unsigned int strx;
int type;
int other ATTRIBUTE_UNUSED;
int desc;
bfd_vma value;
 
/* This code presumes 32 bit values. */
 
strx = bfd_get_32 (abfd, stab);
type = bfd_get_8 (abfd, stab + 4);
other = bfd_get_8 (abfd, stab + 5);
desc = bfd_get_16 (abfd, stab + 6);
value = bfd_get_32 (abfd, stab + 8);
 
if (type == 0)
{
/* Special type 0 stabs indicate the offset to the
next string table. */
stroff = next_stroff;
next_stroff += value;
}
else
{
char *f, *s;
 
f = NULL;
 
if (stroff + strx > strsize)
{
fprintf (stderr, "%s: %s: stab entry %ld is corrupt, strx = 0x%x, type = %d\n",
bfd_get_filename (abfd), names[i].secname,
(long) (stab - stabs) / 12, strx, type);
continue;
}
 
s = (char *) strings + stroff + strx;
 
while (s[strlen (s) - 1] == '\\'
&& stab + 12 < stabs + stabsize)
{
char *p;
 
stab += 12;
p = s + strlen (s) - 1;
*p = '\0';
s = concat (s,
((char *) strings
+ stroff
+ bfd_get_32 (abfd, stab)),
(const char *) NULL);
 
/* We have to restore the backslash, because, if
the linker is hashing stabs strings, we may
see the same string more than once. */
*p = '\\';
 
if (f != NULL)
free (f);
f = s;
}
 
save_stab (type, desc, value, s);
 
if (! parse_stab (dhandle, shandle, type, desc, value, s))
{
stab_context ();
free_saved_stabs ();
return FALSE;
}
 
/* Don't free f, since I think the stabs code
expects strings to hang around. This should be
straightened out. FIXME. */
}
}
 
free_saved_stabs ();
free (stabs);
 
/* Don't free strings, since I think the stabs code expects
the strings to hang around. This should be straightened
out. FIXME. */
}
}
 
if (shandle != NULL)
{
if (! finish_stab (dhandle, shandle))
return FALSE;
}
 
return TRUE;
}
 
/* Read stabs in the symbol table. */
 
static bfd_boolean
read_symbol_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
void *dhandle, bfd_boolean *pfound)
{
void *shandle;
asymbol **ps, **symend;
 
shandle = NULL;
symend = syms + symcount;
for (ps = syms; ps < symend; ps++)
{
symbol_info i;
 
bfd_get_symbol_info (abfd, *ps, &i);
 
if (i.type == '-')
{
const char *s;
char *f;
 
if (shandle == NULL)
{
shandle = start_stab (dhandle, abfd, FALSE, syms, symcount);
if (shandle == NULL)
return FALSE;
}
 
*pfound = TRUE;
 
s = i.name;
f = NULL;
while (s[strlen (s) - 1] == '\\'
&& ps + 1 < symend)
{
char *sc, *n;
 
++ps;
sc = xstrdup (s);
sc[strlen (sc) - 1] = '\0';
n = concat (sc, bfd_asymbol_name (*ps), (const char *) NULL);
free (sc);
if (f != NULL)
free (f);
f = n;
s = n;
}
 
save_stab (i.stab_type, i.stab_desc, i.value, s);
 
if (! parse_stab (dhandle, shandle, i.stab_type, i.stab_desc,
i.value, s))
{
stab_context ();
free_saved_stabs ();
return FALSE;
}
 
/* Don't free f, since I think the stabs code expects
strings to hang around. This should be straightened out.
FIXME. */
}
}
 
free_saved_stabs ();
 
if (shandle != NULL)
{
if (! finish_stab (dhandle, shandle))
return FALSE;
}
 
return TRUE;
}
 
/* Read IEEE debugging information. */
 
static bfd_boolean
read_ieee_debugging_info (bfd *abfd, void *dhandle, bfd_boolean *pfound)
{
asection *dsec;
bfd_size_type size;
bfd_byte *contents;
 
/* The BFD backend puts the debugging information into a section
named .debug. */
 
dsec = bfd_get_section_by_name (abfd, ".debug");
if (dsec == NULL)
return TRUE;
 
size = bfd_section_size (abfd, dsec);
contents = (bfd_byte *) xmalloc (size);
if (! bfd_get_section_contents (abfd, dsec, contents, 0, size))
return FALSE;
 
if (! parse_ieee (dhandle, abfd, contents, size))
return FALSE;
 
free (contents);
 
*pfound = TRUE;
 
return TRUE;
}
/* Record stabs strings, so that we can give some context for errors. */
 
#define SAVE_STABS_COUNT (16)
 
struct saved_stab
{
int type;
int desc;
bfd_vma value;
char *string;
};
 
static struct saved_stab saved_stabs[SAVE_STABS_COUNT];
static int saved_stabs_index;
 
/* Save a stabs string. */
 
static void
save_stab (int type, int desc, bfd_vma value, const char *string)
{
if (saved_stabs[saved_stabs_index].string != NULL)
free (saved_stabs[saved_stabs_index].string);
saved_stabs[saved_stabs_index].type = type;
saved_stabs[saved_stabs_index].desc = desc;
saved_stabs[saved_stabs_index].value = value;
saved_stabs[saved_stabs_index].string = xstrdup (string);
saved_stabs_index = (saved_stabs_index + 1) % SAVE_STABS_COUNT;
}
 
/* Provide context for an error. */
 
static void
stab_context (void)
{
int i;
 
fprintf (stderr, _("Last stabs entries before error:\n"));
fprintf (stderr, "n_type n_desc n_value string\n");
 
i = saved_stabs_index;
do
{
struct saved_stab *stabp;
 
stabp = saved_stabs + i;
if (stabp->string != NULL)
{
const char *s;
 
s = bfd_get_stab_name (stabp->type);
if (s != NULL)
fprintf (stderr, "%-6s", s);
else if (stabp->type == 0)
fprintf (stderr, "HdrSym");
else
fprintf (stderr, "%-6d", stabp->type);
fprintf (stderr, " %-6d ", stabp->desc);
fprintf_vma (stderr, stabp->value);
if (stabp->type != 0)
fprintf (stderr, " %s", stabp->string);
fprintf (stderr, "\n");
}
i = (i + 1) % SAVE_STABS_COUNT;
}
while (i != saved_stabs_index);
}
 
/* Free the saved stab strings. */
 
static void
free_saved_stabs (void)
{
int i;
 
for (i = 0; i < SAVE_STABS_COUNT; i++)
{
if (saved_stabs[i].string != NULL)
{
free (saved_stabs[i].string);
saved_stabs[i].string = NULL;
}
}
 
saved_stabs_index = 0;
}
/contrib/toolchain/binutils/binutils/rename.c
0,0 → 1,212
/* rename.c -- rename a file, preserving symlinks.
Copyright 1999, 2002, 2003, 2005, 2007, 2008 Free Software Foundation, Inc.
 
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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
#include "sysdep.h"
#include "bfd.h"
#include "bucomm.h"
 
#ifdef HAVE_GOOD_UTIME_H
#include <utime.h>
#else /* ! HAVE_GOOD_UTIME_H */
#ifdef HAVE_UTIMES
#include <sys/time.h>
#endif /* HAVE_UTIMES */
#endif /* ! HAVE_GOOD_UTIME_H */
 
#if ! defined (_WIN32) || defined (__CYGWIN32__)
static int simple_copy (const char *, const char *);
 
/* The number of bytes to copy at once. */
#define COPY_BUF 8192
 
/* Copy file FROM to file TO, performing no translations.
Return 0 if ok, -1 if error. */
 
static int
simple_copy (const char *from, const char *to)
{
int fromfd, tofd, nread;
int saved;
char buf[COPY_BUF];
 
fromfd = open (from, O_RDONLY | O_BINARY);
if (fromfd < 0)
return -1;
#ifdef O_CREAT
tofd = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0777);
#else
tofd = creat (to, 0777);
#endif
if (tofd < 0)
{
saved = errno;
close (fromfd);
errno = saved;
return -1;
}
while ((nread = read (fromfd, buf, sizeof buf)) > 0)
{
if (write (tofd, buf, nread) != nread)
{
saved = errno;
close (fromfd);
close (tofd);
errno = saved;
return -1;
}
}
saved = errno;
close (fromfd);
close (tofd);
if (nread < 0)
{
errno = saved;
return -1;
}
return 0;
}
#endif /* __CYGWIN32__ or not _WIN32 */
 
/* Set the times of the file DESTINATION to be the same as those in
STATBUF. */
 
void
set_times (const char *destination, const struct stat *statbuf)
{
int result;
 
{
#ifdef HAVE_GOOD_UTIME_H
struct utimbuf tb;
 
tb.actime = statbuf->st_atime;
tb.modtime = statbuf->st_mtime;
// result = utime (destination, &tb);
#else /* ! HAVE_GOOD_UTIME_H */
#ifndef HAVE_UTIMES
long tb[2];
 
tb[0] = statbuf->st_atime;
tb[1] = statbuf->st_mtime;
result = utime (destination, tb);
#else /* HAVE_UTIMES */
struct timeval tv[2];
 
tv[0].tv_sec = statbuf->st_atime;
tv[0].tv_usec = 0;
tv[1].tv_sec = statbuf->st_mtime;
tv[1].tv_usec = 0;
result = utimes (destination, tv);
#endif /* HAVE_UTIMES */
#endif /* ! HAVE_GOOD_UTIME_H */
}
 
if (result != 0)
non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
}
 
#ifndef S_ISLNK
#ifdef S_IFLNK
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#else
#define S_ISLNK(m) 0
#define lstat stat
#endif
#endif
 
/* Rename FROM to TO, copying if TO is a link.
Return 0 if ok, -1 if error. */
 
int
smart_rename (const char *from, const char *to, int preserve_dates ATTRIBUTE_UNUSED)
{
bfd_boolean exists;
struct stat s;
int ret = 0;
 
exists = lstat (to, &s) == 0;
 
#if 1
/* Win32, unlike unix, will not erase `to' in `rename(from, to)' but
fail instead. Also, chown is not present. */
 
if (exists)
remove (to);
 
ret = rename (from, to);
if (ret != 0)
{
/* We have to clean up here. */
non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno));
unlink (from);
}
#else
/* Use rename only if TO is not a symbolic link and has
only one hard link, and we have permission to write to it. */
if (! exists
|| (!S_ISLNK (s.st_mode)
&& S_ISREG (s.st_mode)
&& (s.st_mode & S_IWUSR)
&& s.st_nlink == 1)
)
{
ret = rename (from, to);
if (ret == 0)
{
if (exists)
{
/* Try to preserve the permission bits and ownership of
TO. First get the mode right except for the setuid
bit. Then change the ownership. Then fix the setuid
bit. We do the chmod before the chown because if the
chown succeeds, and we are a normal user, we won't be
able to do the chmod afterward. We don't bother to
fix the setuid bit first because that might introduce
a fleeting security problem, and because the chown
will clear the setuid bit anyhow. We only fix the
setuid bit if the chown succeeds, because we don't
want to introduce an unexpected setuid file owned by
the user running objcopy. */
// chmod (to, s.st_mode & 0777);
// if (chown (to, s.st_uid, s.st_gid) >= 0)
// chmod (to, s.st_mode & 07777);
}
}
else
{
/* We have to clean up here. */
non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno));
unlink (from);
}
}
else
{
ret = simple_copy (from, to);
if (ret != 0)
non_fatal (_("unable to copy file '%s'; reason: %s"), to, strerror (errno));
 
if (preserve_dates)
set_times (to, &s);
unlink (from);
}
#endif /* _WIN32 && !__CYGWIN32__ */
 
return ret;
}
/contrib/toolchain/binutils/binutils/stabs.c
0,0 → 1,5433
/* stabs.c -- Parse stabs debugging information
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, 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 "sysdep.h"
#include "bfd.h"
#include "libiberty.h"
#include "safe-ctype.h"
#include "demangle.h"
#include "debug.h"
#include "budbg.h"
#include "filenames.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 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 (const char *, int);
static bfd_vma parse_number (const char **, bfd_boolean *);
static void bad_stab (const char *);
static void warn_stab (const char *, const char *);
static bfd_boolean parse_stab_string
(void *, struct stab_handle *, int, int, bfd_vma, const char *);
static debug_type parse_stab_type
(void *, struct stab_handle *, const char *, const char **, debug_type **);
static bfd_boolean parse_stab_type_number (const char **, int *);
static debug_type parse_stab_range_type
(void *, struct stab_handle *, const char *, const char **, const int *);
static debug_type parse_stab_sun_builtin_type (void *, const char **);
static debug_type parse_stab_sun_floating_type (void *, const char **);
static debug_type parse_stab_enum_type (void *, const char **);
static debug_type parse_stab_struct_type
(void *, struct stab_handle *, const char *, const char **,
bfd_boolean, const int *);
static bfd_boolean parse_stab_baseclasses
(void *, struct stab_handle *, const char **, debug_baseclass **);
static bfd_boolean parse_stab_struct_fields
(void *, struct stab_handle *, const char **, debug_field **, bfd_boolean *);
static bfd_boolean parse_stab_cpp_abbrev
(void *, struct stab_handle *, const char **, debug_field *);
static bfd_boolean parse_stab_one_struct_field
(void *, struct stab_handle *, const char **, const char *,
debug_field *, bfd_boolean *);
static bfd_boolean parse_stab_members
(void *, struct stab_handle *, const char *, const char **, const int *,
debug_method **);
static debug_type parse_stab_argtypes
(void *, 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
(void *, struct stab_handle *, const char **, const int *, debug_type *,
bfd_boolean *);
static debug_type parse_stab_array_type
(void *, struct stab_handle *, const char **, bfd_boolean);
static void push_bincl (struct stab_handle *, const char *, bfd_vma);
static const char *pop_bincl (struct stab_handle *);
static bfd_boolean find_excl (struct stab_handle *, const char *, bfd_vma);
static bfd_boolean stab_record_variable
(void *, struct stab_handle *, const char *, debug_type,
enum debug_var_kind, bfd_vma);
static bfd_boolean stab_emit_pending_vars (void *, struct stab_handle *);
static debug_type *stab_find_slot (struct stab_handle *, const int *);
static debug_type stab_find_type (void *, struct stab_handle *, const int *);
static bfd_boolean stab_record_type
(void *, struct stab_handle *, const int *, debug_type);
static debug_type stab_xcoff_builtin_type
(void *, struct stab_handle *, int);
static debug_type stab_find_tagged_type
(void *, struct stab_handle *, const char *, int, enum debug_type_kind);
static debug_type *stab_demangle_argtypes
(void *, struct stab_handle *, const char *, bfd_boolean *, unsigned int);
static debug_type *stab_demangle_v3_argtypes
(void *, struct stab_handle *, const char *, bfd_boolean *);
static debug_type *stab_demangle_v3_arglist
(void *, struct stab_handle *, struct demangle_component *, bfd_boolean *);
static debug_type stab_demangle_v3_arg
(void *, struct stab_handle *, struct demangle_component *, debug_type,
bfd_boolean *);
 
/* Save a string in memory. */
 
static char *
savestring (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 (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 (d))
d -= '0';
else if (ISUPPER (d))
d -= 'A';
else if (ISLOWER (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 (const char *p)
{
fprintf (stderr, _("Bad stab: %s\n"), p);
}
 
/* Warn about something in a stab string. */
 
static void
warn_stab (const char *p, const char *err)
{
fprintf (stderr, _("Warning: %s: %s\n"), err, p);
}
 
/* Create a handle to parse stabs symbols with. */
 
void *
start_stab (void *dhandle ATTRIBUTE_UNUSED, bfd *abfd, bfd_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 (void *) 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 (void *dhandle, void *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 (void *dhandle, void *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))
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->within_function
? info->function_start_offset : 0)))
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 (void *dhandle, struct stab_handle *info, int stabtype,
int desc ATTRIBUTE_UNUSED, bfd_vma value, const char *string)
{
const char *p;
char *name;
int type;
debug_type dtype;
bfd_boolean synonym;
bfd_boolean self_crossref;
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;
}
}
 
/* 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 (*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,
(debug_type *) NULL, FALSE);
dtype = debug_make_pointer_type (dhandle, ftype);
}
}
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, (const char *) NULL, &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, (const char *) NULL, &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, (const char *) NULL, &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, (const char *) NULL, &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, name, &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, name, &p, &slot);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (name == NULL)
return TRUE;
 
/* INFO->SELF_CROSSREF is set by parse_stab_type if this type is
a cross reference to itself. These are generated by some
versions of g++. */
self_crossref = info->self_crossref;
 
dtype = debug_tag_type (dhandle, name, dtype);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (slot != NULL)
*slot = dtype;
 
/* See if we have a cross reference to this tag which we can now
fill in. Avoid filling in a cross reference to ourselves,
because that would lead to circular debugging information. */
if (! self_crossref)
{
register struct stab_tag **pst;
 
for (pst = &info->tags; *pst != NULL; pst = &(*pst)->next)
{
if ((*pst)->name[0] == name[0]
&& strcmp ((*pst)->name, name) == 0)
{
(*pst)->slot = dtype;
*pst = (*pst)->next;
break;
}
}
}
 
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, (const char *) NULL, &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, (const char *) NULL, &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, (const char *) NULL, &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, (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 'Y':
/* SUNPro C++ Namespace =Yn0. */
/* Skip the namespace mapping, as it is not used now. */
if (*(++p) == 'n' && *(++p) == '0')
{
/* =Yn0name; */
while (*p != ';')
++p;
++p;
return TRUE;
}
/* TODO SUNPro C++ support:
Support default arguments after F,P parameters
Ya = Anonymous unions
YM,YD = Pointers to class members
YT,YI = Templates
YR = Run-time type information (RTTI) */
 
/* Fall through. */
 
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. The typename argument is non-NULL if this is a
typedef or a tag definition. The pp argument points to the stab
string, and is updated. The slotp argument points to a place to
store the slot used if the type is being defined. */
 
static debug_type
parse_stab_type (void *dhandle, struct stab_handle *info, const char *type_name, const char **pp, debug_type **slotp)
{
const char *orig;
int typenums[2];
int size;
bfd_boolean stringp;
int descriptor;
debug_type dtype;
 
if (slotp != NULL)
*slotp = NULL;
 
orig = *pp;
 
size = -1;
stringp = FALSE;
 
info->self_crossref = FALSE;
 
/* Read type number if present. The type number may be omitted.
for instance in a two-dimensional array declared with type
"ar1;1;10;ar1;1;10;4". */
if (! ISDIGIT (**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 (*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);
size /= 8; /* Size is in bits. We store it in bytes. */
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;
 
/* 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;
}
if (q1 != NULL && p > q1 && p[1] == ':')
{
int nest = 0;
 
for (q2 = q1; *q2 != '\0'; ++q2)
{
if (*q2 == '<')
++nest;
else if (*q2 == '>')
--nest;
else if (*q2 == ':' && nest == 0)
break;
}
p = q2;
if (*p != ':')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
}
 
/* Some versions of g++ can emit stabs like
fleep:T20=xsfleep:
which define structures in terms of themselves. We need to
tell the caller to avoid building a circular structure. */
if (type_name != NULL
&& strncmp (type_name, *pp, p - *pp) == 0
&& type_name[p - *pp] == '\0')
info->self_crossref = TRUE;
 
dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code);
 
*pp = p + 1;
}
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, (const char *) NULL,
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,
(const char *) NULL,
pp,
(debug_type **) NULL));
break;
 
case '&':
/* Reference to another type. */
dtype = (debug_make_reference_type
(dhandle,
parse_stab_type (dhandle, info, (const char *) NULL, 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, (const char *) NULL, pp,
(debug_type **) NULL),
(debug_type *) NULL, FALSE));
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,
(const char *) NULL,
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, (const char *) NULL, 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, (const char *) NULL, 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, (const char *) NULL, 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, (const char *) NULL,
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,
(debug_type *) NULL, FALSE);
}
else
{
debug_type domain;
debug_type return_type;
debug_type *args;
unsigned int n;
unsigned int alloc;
bfd_boolean varargs;
 
domain = parse_stab_type (dhandle, info, (const char *) NULL,
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, (const char *) NULL,
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 (args, alloc * sizeof *args));
}
 
args[n] = parse_stab_type (dhandle, info, (const char *) NULL,
pp, (debug_type **) NULL);
if (args[n] == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
++n;
}
++*pp;
 
/* If the last type is not void, then this function takes a
variable number of arguments. Otherwise, we must strip
the void type. */
if (n == 0
|| debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID)
varargs = TRUE;
else
{
--n;
varargs = FALSE;
}
 
args[n] = DEBUG_TYPE_NULL;
 
dtype = debug_make_method_type (dhandle, return_type, domain, args,
varargs);
}
break;
 
case 'r':
/* Range type. */
dtype = parse_stab_range_type (dhandle, info, type_name, 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, type_name, 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,
(const char *) NULL,
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 DEBUG_TYPE_NULL;
}
 
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 bfd_boolean
parse_stab_type_number (const char **pp, int *typenums)
{
const char *orig;
 
orig = *pp;
 
if (**pp != '(')
{
typenums[0] = 0;
typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL);
}
else
{
++*pp;
typenums[0] = (int) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return FALSE;
}
++*pp;
typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ')')
{
bad_stab (orig);
return FALSE;
}
++*pp;
}
 
return TRUE;
}
 
/* Parse a range type. */
 
static debug_type
parse_stab_range_type (void *dhandle, struct stab_handle *info, const char *type_name, const char **pp, const int *typenums)
{
const char *orig;
int rangenums[2];
bfd_boolean self_subrange;
debug_type index_type;
const char *s2, *s3;
bfd_signed_vma n2, n3;
bfd_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, (const char *) NULL,
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 (CONST_STRNEQ (s2, LLLOW)
&& CONST_STRNEQ (s3, LLHIGH))
return debug_make_int_type (dhandle, 8, FALSE);
if (! ov2
&& n2 == 0
&& CONST_STRNEQ (s3, ULLHIGH))
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);
 
/* A type defined as a subrange of itself, with n2 positive and
n3 zero, is a complex type, and n2 is the number of bytes. */
if (self_subrange && n3 == 0 && n2 > 0)
return debug_make_complex_type (dhandle, n2);
 
/* 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)
{
/* When gcc is used with -gstabs, but not -gstabs+, it will emit
long long int:t6=r1;0;-1;
long long unsigned int:t7=r1;0;-1;
We hack here to handle this reasonably. */
if (type_name != NULL)
{
if (strcmp (type_name, "long long int") == 0)
return debug_make_int_type (dhandle, 8, FALSE);
else if (strcmp (type_name, "long long unsigned int") == 0)
return debug_make_int_type (dhandle, 8, TRUE);
}
/* 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);
else if (n3 == (bfd_signed_vma) 0xffffffff)
return debug_make_int_type (dhandle, 4, TRUE);
#ifdef BFD64
else if (n3 == ((((bfd_signed_vma) 0xffffffff) << 32) | 0xffffffff))
return debug_make_int_type (dhandle, 8, TRUE);
#endif
}
else if (n3 == 0
&& n2 < 0
&& (self_subrange || n2 == -8))
return debug_make_int_type (dhandle, - n2, TRUE);
else if (n2 == - n3 - 1 || 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);
#ifdef BFD64
else if (n3 == ((((bfd_vma) 0x7fffffff) << 32) | 0xffffffff))
return debug_make_int_type (dhandle, 8, FALSE);
#endif
}
}
 
/* 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 (void *dhandle, const char **pp)
{
const char *orig;
bfd_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;
 
/* OpenSolaris source code indicates that one of "cbv" characters
can come next and specify the intrinsic 'iformat' encoding.
'c' is character encoding, 'b' is boolean encoding, and 'v' is
varargs encoding. This field can be safely ignored because
the type of the field is determined from the bitwidth extracted
below. */
if (**pp == 'c' || **pp == 'b' || **pp == 'v')
++*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, (bfd_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, (bfd_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, (bfd_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 (void *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, (bfd_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, (bfd_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 (void *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, (bfd_boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
free (name);
free (names);
free (values);
return DEBUG_TYPE_NULL;
}
++*pp;
 
if (n + 1 >= alloc)
{
alloc += 10;
names = ((const char **)
xrealloc (names, alloc * sizeof *names));
values = ((bfd_signed_vma *)
xrealloc (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 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 (void *dhandle, struct stab_handle *info,
const char *tagname, const char **pp,
bfd_boolean structp, const int *typenums)
{
bfd_vma size;
debug_baseclass *baseclasses;
debug_field *fields = NULL;
bfd_boolean statics;
debug_method *methods;
debug_type vptrbase;
bfd_boolean ownvptr;
 
/* Get the size. */
size = parse_number (pp, (bfd_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, tagname, pp, typenums, &methods)
|| ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase,
&ownvptr))
{
if (fields != NULL)
free (fields);
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 bfd_boolean
parse_stab_baseclasses (void *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, (bfd_boolean *) NULL);
 
if (**pp != ',')
{
bad_stab (orig);
return FALSE;
}
++*pp;
 
classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp));
 
for (i = 0; i < c; i++)
{
bfd_boolean is_virtual;
enum debug_visibility visibility;
bfd_vma bitpos;
debug_type type;
 
switch (**pp)
{
case '0':
is_virtual = FALSE;
break;
case '1':
is_virtual = TRUE;
break;
default:
warn_stab (orig, _("unknown virtual character for baseclass"));
is_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, (bfd_boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return FALSE;
}
++*pp;
 
type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
return FALSE;
 
classes[i] = debug_make_baseclass (dhandle, type, bitpos, is_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 bfd_boolean
parse_stab_struct_fields (void *dhandle, struct stab_handle *info,
const char **pp, debug_field **retp,
bfd_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 (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))
{
free (fields);
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);
free (fields);
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 bfd_boolean
parse_stab_cpp_abbrev (void *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 *type_name;
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, (const char *) NULL, 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 */
type_name = debug_get_type_name (dhandle, context);
if (type_name == NULL)
{
warn_stab (orig, _("unnamed $vb type"));
type_name = "FOO";
}
name = concat ("_vb$", type_name, (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, (const char *) NULL, pp,
(debug_type **) NULL);
if (**pp != ',')
{
bad_stab (orig);
return FALSE;
}
++*pp;
 
bitpos = parse_number (pp, (bfd_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 bfd_boolean
parse_stab_one_struct_field (void *dhandle, struct stab_handle *info,
const char **pp, const char *p,
debug_field *retp, bfd_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, (const char *) NULL, pp,
(debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
{
free (name);
return FALSE;
}
 
if (**pp == ':')
{
char *varname;
 
/* This is a static class member. */
++*pp;
p = strchr (*pp, ';');
if (p == NULL)
{
bad_stab (orig);
free (name);
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);
free (name);
return FALSE;
}
++*pp;
 
bitpos = parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
free (name);
return FALSE;
}
++*pp;
 
bitsize = parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
free (name);
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 bfd_boolean
parse_stab_members (void *dhandle, struct stab_handle *info,
const char *tagname, const char **pp,
const int *typenums, debug_method **retp)
{
const char *orig;
debug_method *methods;
unsigned int c;
unsigned int alloc;
char *name = NULL;
debug_method_variant *variants = NULL;
char *argtypes = NULL;
 
*retp = NULL;
 
orig = *pp;
 
alloc = 0;
methods = NULL;
c = 0;
 
while (**pp != ';')
{
const char *p;
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 weird 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);
goto fail;
}
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;
bfd_boolean stub;
enum debug_visibility visibility;
bfd_boolean constp, volatilep, staticp;
bfd_vma voffset;
debug_type context;
const char *physname;
bfd_boolean varargs;
 
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, (const char *) NULL, pp,
(debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
goto fail;
 
if (**pp != ':')
{
bad_stab (orig);
goto fail;
}
}
 
++*pp;
p = strchr (*pp, ';');
if (p == NULL)
{
bad_stab (orig);
goto fail;
}
 
stub = FALSE;
if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD
&& debug_get_parameter_types (dhandle, type, &varargs) == NULL)
stub = TRUE;
 
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 supposedly set to distinguish
pointers-to-methods from virtual function indicies. */
++*pp;
voffset = parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
goto fail;
}
++*pp;
voffset &= 0x7fffffff;
 
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,
(const char *) NULL,
pp,
(debug_type **) NULL);
if (**pp == ':')
{
/* g++ version 1 overloaded methods. */
context = DEBUG_TYPE_NULL;
}
else
{
context = look_ahead_type;
look_ahead_type = DEBUG_TYPE_NULL;
if (**pp != ';')
{
bad_stab (orig);
goto fail;
}
++*pp;
}
}
break;
 
case '?':
/* static member function. */
++*pp;
staticp = TRUE;
voffset = 0;
context = DEBUG_TYPE_NULL;
if (strncmp (argtypes, name, strlen (name)) != 0)
stub = TRUE;
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 the type is not a stub, then the argtypes string is
the physical name of the function. Otherwise the
argtypes string is the mangled form of the argument
types, and the full type and the physical name must be
extracted from them. */
physname = argtypes;
if (stub)
{
debug_type class_type, return_type;
 
class_type = stab_find_type (dhandle, info, typenums);
if (class_type == DEBUG_TYPE_NULL)
goto fail;
return_type = debug_get_return_type (dhandle, type);
if (return_type == DEBUG_TYPE_NULL)
{
bad_stab (orig);
goto fail;
}
type = parse_stab_argtypes (dhandle, info, class_type, name,
tagname, return_type, argtypes,
constp, volatilep, &physname);
if (type == DEBUG_TYPE_NULL)
goto fail;
}
 
if (cvars + 1 >= allocvars)
{
allocvars += 10;
variants = ((debug_method_variant *)
xrealloc (variants,
allocvars * sizeof *variants));
}
 
if (! staticp)
variants[cvars] = debug_make_method_variant (dhandle, physname,
type, visibility,
constp, volatilep,
voffset, context);
else
variants[cvars] = debug_make_static_method_variant (dhandle,
physname,
type,
visibility,
constp,
volatilep);
if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL)
goto fail;
 
++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 (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;
 
fail:
if (name != NULL)
free (name);
if (variants != NULL)
free (variants);
if (argtypes != NULL)
free (argtypes);
return FALSE;
}
 
/* Parse a string representing argument types for a method. Stabs
tries to save space by packing argument types into a mangled
string. This string should give us enough information to extract
both argument types and the physical name of the function, given
the tag name. */
 
static debug_type
parse_stab_argtypes (void *dhandle, struct stab_handle *info,
debug_type class_type, const char *fieldname,
const char *tagname, debug_type return_type,
const char *argtypes, bfd_boolean constp,
bfd_boolean volatilep, const char **pphysname)
{
bfd_boolean is_full_physname_constructor;
bfd_boolean is_constructor;
bfd_boolean is_destructor;
bfd_boolean is_v3;
debug_type *args;
bfd_boolean varargs;
unsigned int physname_len = 0;
 
/* Constructors are sometimes handled specially. */
is_full_physname_constructor = ((argtypes[0] == '_'
&& argtypes[1] == '_'
&& (ISDIGIT (argtypes[2])
|| argtypes[2] == 'Q'
|| argtypes[2] == 't'))
|| CONST_STRNEQ (argtypes, "__ct"));
 
is_constructor = (is_full_physname_constructor
|| (tagname != NULL
&& strcmp (fieldname, tagname) == 0));
is_destructor = ((argtypes[0] == '_'
&& (argtypes[1] == '$' || argtypes[1] == '.')
&& argtypes[2] == '_')
|| CONST_STRNEQ (argtypes, "__dt"));
is_v3 = argtypes[0] == '_' && argtypes[1] == 'Z';
 
if (!(is_destructor || is_full_physname_constructor || is_v3))
{
unsigned int len;
const char *const_prefix;
const char *volatile_prefix;
char buf[20];
unsigned int mangled_name_len;
char *physname;
 
len = tagname == NULL ? 0 : strlen (tagname);
const_prefix = constp ? "C" : "";
volatile_prefix = volatilep ? "V" : "";
 
if (len == 0)
sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
else if (tagname != NULL && strchr (tagname, '<') != NULL)
{
/* Template methods are fully mangled. */
sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
tagname = NULL;
len = 0;
}
else
sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len);
 
mangled_name_len = ((is_constructor ? 0 : strlen (fieldname))
+ strlen (buf)
+ len
+ strlen (argtypes)
+ 1);
 
if (fieldname[0] == 'o'
&& fieldname[1] == 'p'
&& (fieldname[2] == '$' || fieldname[2] == '.'))
{
const char *opname;
 
opname = cplus_mangle_opname (fieldname + 3, 0);
if (opname == NULL)
{
fprintf (stderr, _("No mangling for \"%s\"\n"), fieldname);
return DEBUG_TYPE_NULL;
}
mangled_name_len += strlen (opname);
physname = (char *) xmalloc (mangled_name_len);
strncpy (physname, fieldname, 3);
strcpy (physname + 3, opname);
}
else
{
physname = (char *) xmalloc (mangled_name_len);
if (is_constructor)
physname[0] = '\0';
else
strcpy (physname, fieldname);
}
 
physname_len = strlen (physname);
strcat (physname, buf);
if (tagname != NULL)
strcat (physname, tagname);
strcat (physname, argtypes);
 
*pphysname = physname;
}
 
if (*argtypes == '\0' || is_destructor)
{
args = (debug_type *) xmalloc (sizeof *args);
*args = NULL;
return debug_make_method_type (dhandle, return_type, class_type, args,
FALSE);
}
 
args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs, physname_len);
if (args == NULL)
return DEBUG_TYPE_NULL;
 
return debug_make_method_type (dhandle, return_type, class_type, args,
varargs);
}
 
/* 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 bfd_boolean
parse_stab_tilde_field (void *dhandle, struct stab_handle *info,
const char **pp, const int *typenums,
debug_type *retvptrbase, bfd_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, (const char *) NULL, 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 (void *dhandle, struct stab_handle *info,
const char **pp, bfd_boolean stringp)
{
const char *orig;
const char *p;
int typenums[2];
debug_type index_type;
bfd_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. */
 
/* If the index type is type 0, we take it as int. */
p = *pp;
if (! parse_stab_type_number (&p, typenums))
return DEBUG_TYPE_NULL;
if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=')
{
index_type = debug_find_named_type (dhandle, "int");
if (index_type == DEBUG_TYPE_NULL)
{
index_type = debug_make_int_type (dhandle, 4, FALSE);
if (index_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
*pp = p;
}
else
{
index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
}
 
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
 
adjustable = FALSE;
 
if (! ISDIGIT (**pp) && **pp != '-')
{
++*pp;
adjustable = TRUE;
}
 
lower = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
 
if (! ISDIGIT (**pp) && **pp != '-')
{
++*pp;
adjustable = TRUE;
}
 
upper = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
 
element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
if (element_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
 
if (adjustable)
{
lower = 0;
upper = -1;
}
 
return debug_make_array_type (dhandle, element_type, index_type, lower,
upper, stringp);
}
 
/* This struct holds information about files we have seen using
N_BINCL. */
 
struct bincl_file
{
/* The next N_BINCL file. */
struct bincl_file *next;
/* The next N_BINCL on the stack. */
struct bincl_file *next_stack;
/* The file name. */
const char *name;
/* The hash value. */
bfd_vma hash;
/* The file index. */
unsigned int file;
/* The list of types defined in this file. */
struct stab_types *file_types;
};
 
/* Start a new N_BINCL file, pushing it onto the stack. */
 
static void
push_bincl (struct stab_handle *info, const char *name, bfd_vma hash)
{
struct bincl_file *n;
 
n = (struct bincl_file *) xmalloc (sizeof *n);
n->next = info->bincl_list;
n->next_stack = info->bincl_stack;
n->name = name;
n->hash = hash;
n->file = info->files;
n->file_types = NULL;
info->bincl_list = n;
info->bincl_stack = n;
 
++info->files;
info->file_types = ((struct stab_types **)
xrealloc (info->file_types,
(info->files
* sizeof *info->file_types)));
info->file_types[n->file] = NULL;
}
 
/* Finish an N_BINCL file, at an N_EINCL, popping the name off the
stack. */
 
static const char *
pop_bincl (struct stab_handle *info)
{
struct bincl_file *o;
 
o = info->bincl_stack;
if (o == NULL)
return info->main_filename;
info->bincl_stack = o->next_stack;
 
o->file_types = info->file_types[o->file];
 
if (info->bincl_stack == NULL)
return info->main_filename;
return info->bincl_stack->name;
}
 
/* Handle an N_EXCL: get the types from the corresponding N_BINCL. */
 
static bfd_boolean
find_excl (struct stab_handle *info, const char *name, bfd_vma hash)
{
struct bincl_file *l;
 
++info->files;
info->file_types = ((struct stab_types **)
xrealloc (info->file_types,
(info->files
* sizeof *info->file_types)));
 
for (l = info->bincl_list; l != NULL; l = l->next)
if (l->hash == hash && strcmp (l->name, name) == 0)
break;
if (l == NULL)
{
warn_stab (name, _("Undefined N_EXCL"));
info->file_types[info->files - 1] = NULL;
return TRUE;
}
 
info->file_types[info->files - 1] = l->file_types;
 
return TRUE;
}
 
/* Handle a variable definition. gcc emits variable definitions for a
block before the N_LBRAC, so we must hold onto them until we see
it. The SunPRO compiler emits variable definitions after the
N_LBRAC, so we can call debug_record_variable immediately. */
 
static bfd_boolean
stab_record_variable (void *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 ((kind == DEBUG_GLOBAL || kind == DEBUG_STATIC)
|| ! 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 bfd_boolean
stab_emit_pending_vars (void *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 (struct stab_handle *info, const int *typenums)
{
int filenum;
int tindex;
struct stab_types **ps;
 
filenum = typenums[0];
tindex = typenums[1];
 
if (filenum < 0 || (unsigned int) filenum >= info->files)
{
fprintf (stderr, _("Type file number %d out of range\n"), filenum);
return NULL;
}
if (tindex < 0)
{
fprintf (stderr, _("Type index number %d out of range\n"), tindex);
return NULL;
}
 
ps = info->file_types + filenum;
 
while (tindex >= STAB_TYPES_SLOTS)
{
if (*ps == NULL)
{
*ps = (struct stab_types *) xmalloc (sizeof **ps);
memset (*ps, 0, sizeof **ps);
}
ps = &(*ps)->next;
tindex -= STAB_TYPES_SLOTS;
}
if (*ps == NULL)
{
*ps = (struct stab_types *) xmalloc (sizeof **ps);
memset (*ps, 0, sizeof **ps);
}
 
return (*ps)->types + tindex;
}
 
/* 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 (void *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 bfd_boolean
stab_record_type (void *dhandle ATTRIBUTE_UNUSED, 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 (void *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;
}
 
/* Find or create a tagged type. */
 
static debug_type
stab_find_tagged_type (void *dhandle, struct stab_handle *info,
const char *p, int len, enum debug_type_kind kind)
{
char *name;
debug_type dtype;
struct stab_tag *st;
 
name = savestring (p, len);
 
/* We pass DEBUG_KIND_ILLEGAL 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_ILLEGAL);
if (dtype != DEBUG_TYPE_NULL)
{
free (name);
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)
{
if (st->kind == DEBUG_KIND_ILLEGAL)
st->kind = kind;
free (name);
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 = kind;
st->slot = DEBUG_TYPE_NULL;
st->type = debug_make_indirect_type (dhandle, &st->slot, name);
info->tags = st;
}
 
return st->type;
}
/* In order to get the correct argument types for a stubbed method, we
need to extract the argument types from a C++ mangled string.
Since the argument types can refer back to the return type, this
means that we must demangle the entire physical name. In gdb this
is done by calling cplus_demangle and running the results back
through the C++ expression parser. Since we have no expression
parser, we must duplicate much of the work of cplus_demangle here.
 
We assume that GNU style demangling is used, since this is only
done for method stubs, and only g++ should output that form of
debugging information. */
 
/* This structure is used to hold a pointer to type information which
demangling a string. */
 
struct stab_demangle_typestring
{
/* The start of the type. This is not null terminated. */
const char *typestring;
/* The length of the type. */
unsigned int len;
};
 
/* This structure is used to hold information while demangling a
string. */
 
struct stab_demangle_info
{
/* The debugging information handle. */
void *dhandle;
/* The stab information handle. */
struct stab_handle *info;
/* The array of arguments we are building. */
debug_type *args;
/* Whether the method takes a variable number of arguments. */
bfd_boolean varargs;
/* The array of types we have remembered. */
struct stab_demangle_typestring *typestrings;
/* The number of typestrings. */
unsigned int typestring_count;
/* The number of typestring slots we have allocated. */
unsigned int typestring_alloc;
};
 
static void stab_bad_demangle (const char *);
static unsigned int stab_demangle_count (const char **);
static bfd_boolean stab_demangle_get_count (const char **, unsigned int *);
static bfd_boolean stab_demangle_prefix
(struct stab_demangle_info *, const char **, unsigned int);
static bfd_boolean stab_demangle_function_name
(struct stab_demangle_info *, const char **, const char *);
static bfd_boolean stab_demangle_signature
(struct stab_demangle_info *, const char **);
static bfd_boolean stab_demangle_qualified
(struct stab_demangle_info *, const char **, debug_type *);
static bfd_boolean stab_demangle_template
(struct stab_demangle_info *, const char **, char **);
static bfd_boolean stab_demangle_class
(struct stab_demangle_info *, const char **, const char **);
static bfd_boolean stab_demangle_args
(struct stab_demangle_info *, const char **, debug_type **, bfd_boolean *);
static bfd_boolean stab_demangle_arg
(struct stab_demangle_info *, const char **, debug_type **,
unsigned int *, unsigned int *);
static bfd_boolean stab_demangle_type
(struct stab_demangle_info *, const char **, debug_type *);
static bfd_boolean stab_demangle_fund_type
(struct stab_demangle_info *, const char **, debug_type *);
static bfd_boolean stab_demangle_remember_type
(struct stab_demangle_info *, const char *, int);
 
/* Warn about a bad demangling. */
 
static void
stab_bad_demangle (const char *s)
{
fprintf (stderr, _("bad mangled name `%s'\n"), s);
}
 
/* Get a count from a stab string. */
 
static unsigned int
stab_demangle_count (const char **pp)
{
unsigned int count;
 
count = 0;
while (ISDIGIT (**pp))
{
count *= 10;
count += **pp - '0';
++*pp;
}
return count;
}
 
/* Require a count in a string. The count may be multiple digits, in
which case it must end in an underscore. */
 
static bfd_boolean
stab_demangle_get_count (const char **pp, unsigned int *pi)
{
if (! ISDIGIT (**pp))
return FALSE;
 
*pi = **pp - '0';
++*pp;
if (ISDIGIT (**pp))
{
unsigned int count;
const char *p;
 
count = *pi;
p = *pp;
do
{
count *= 10;
count += *p - '0';
++p;
}
while (ISDIGIT (*p));
if (*p == '_')
{
*pp = p + 1;
*pi = count;
}
}
 
return TRUE;
}
 
/* This function demangles a physical name, returning a NULL
terminated array of argument types. */
 
static debug_type *
stab_demangle_argtypes (void *dhandle, struct stab_handle *info,
const char *physname, bfd_boolean *pvarargs,
unsigned int physname_len)
{
struct stab_demangle_info minfo;
 
/* Check for the g++ V3 ABI. */
if (physname[0] == '_' && physname[1] == 'Z')
return stab_demangle_v3_argtypes (dhandle, info, physname, pvarargs);
 
minfo.dhandle = dhandle;
minfo.info = info;
minfo.args = NULL;
minfo.varargs = FALSE;
minfo.typestring_alloc = 10;
minfo.typestrings = ((struct stab_demangle_typestring *)
xmalloc (minfo.typestring_alloc
* sizeof *minfo.typestrings));
minfo.typestring_count = 0;
 
/* cplus_demangle checks for special GNU mangled forms, but we can't
see any of them in mangled method argument types. */
 
if (! stab_demangle_prefix (&minfo, &physname, physname_len))
goto error_return;
 
if (*physname != '\0')
{
if (! stab_demangle_signature (&minfo, &physname))
goto error_return;
}
 
free (minfo.typestrings);
minfo.typestrings = NULL;
 
if (minfo.args == NULL)
fprintf (stderr, _("no argument types in mangled string\n"));
 
*pvarargs = minfo.varargs;
return minfo.args;
 
error_return:
if (minfo.typestrings != NULL)
free (minfo.typestrings);
return NULL;
}
 
/* Demangle the prefix of the mangled name. */
 
static bfd_boolean
stab_demangle_prefix (struct stab_demangle_info *minfo, const char **pp,
unsigned int physname_len)
{
const char *scan;
unsigned int i;
 
/* cplus_demangle checks for global constructors and destructors,
but we can't see them in mangled argument types. */
 
if (physname_len)
scan = *pp + physname_len;
else
{
/* Look for `__'. */
scan = *pp;
do
scan = strchr (scan, '_');
while (scan != NULL && *++scan != '_');
 
if (scan == NULL)
{
stab_bad_demangle (*pp);
return FALSE;
}
 
--scan;
 
/* We found `__'; move ahead to the last contiguous `__' pair. */
i = strspn (scan, "_");
if (i > 2)
scan += i - 2;
}
 
if (scan == *pp
&& (ISDIGIT (scan[2])
|| scan[2] == 'Q'
|| scan[2] == 't'))
{
/* This is a GNU style constructor name. */
*pp = scan + 2;
return TRUE;
}
else if (scan == *pp
&& ! ISDIGIT (scan[2])
&& scan[2] != 't')
{
/* Look for the `__' that separates the prefix from the
signature. */
while (*scan == '_')
++scan;
scan = strstr (scan, "__");
if (scan == NULL || scan[2] == '\0')
{
stab_bad_demangle (*pp);
return FALSE;
}
 
return stab_demangle_function_name (minfo, pp, scan);
}
else if (scan[2] != '\0')
{
/* The name doesn't start with `__', but it does contain `__'. */
return stab_demangle_function_name (minfo, pp, scan);
}
else
{
stab_bad_demangle (*pp);
return FALSE;
}
/*NOTREACHED*/
}
 
/* Demangle a function name prefix. The scan argument points to the
double underscore which separates the function name from the
signature. */
 
static bfd_boolean
stab_demangle_function_name (struct stab_demangle_info *minfo,
const char **pp, const char *scan)
{
const char *name;
 
/* The string from *pp to scan is the name of the function. We
don't care about the name, since we just looking for argument
types. However, for conversion operators, the name may include a
type which we must remember in order to handle backreferences. */
 
name = *pp;
*pp = scan + 2;
 
if (*pp - name >= 5
&& CONST_STRNEQ (name, "type")
&& (name[4] == '$' || name[4] == '.'))
{
const char *tem;
 
/* This is a type conversion operator. */
tem = name + 5;
if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
return FALSE;
}
else if (name[0] == '_'
&& name[1] == '_'
&& name[2] == 'o'
&& name[3] == 'p')
{
const char *tem;
 
/* This is a type conversion operator. */
tem = name + 4;
if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
return FALSE;
}
 
return TRUE;
}
 
/* Demangle the signature. This is where the argument types are
found. */
 
static bfd_boolean
stab_demangle_signature (struct stab_demangle_info *minfo, const char **pp)
{
const char *orig;
bfd_boolean expect_func, func_done;
const char *hold;
 
orig = *pp;
 
expect_func = FALSE;
func_done = FALSE;
hold = NULL;
 
while (**pp != '\0')
{
switch (**pp)
{
case 'Q':
hold = *pp;
if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL)
|| ! stab_demangle_remember_type (minfo, hold, *pp - hold))
return FALSE;
expect_func = TRUE;
hold = NULL;
break;
 
case 'S':
/* Static member function. FIXME: Can this happen? */
if (hold == NULL)
hold = *pp;
++*pp;
break;
 
case 'C':
/* Const member function. */
if (hold == NULL)
hold = *pp;
++*pp;
break;
 
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (hold == NULL)
hold = *pp;
if (! stab_demangle_class (minfo, pp, (const char **) NULL)
|| ! stab_demangle_remember_type (minfo, hold, *pp - hold))
return FALSE;
expect_func = TRUE;
hold = NULL;
break;
 
case 'F':
/* Function. I don't know if this actually happens with g++
output. */
hold = NULL;
func_done = TRUE;
++*pp;
if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
return FALSE;
break;
 
case 't':
/* Template. */
if (hold == NULL)
hold = *pp;
if (! stab_demangle_template (minfo, pp, (char **) NULL)
|| ! stab_demangle_remember_type (minfo, hold, *pp - hold))
return FALSE;
hold = NULL;
expect_func = TRUE;
break;
 
case '_':
/* At the outermost level, we cannot have a return type
specified, so if we run into another '_' at this point we
are dealing with a mangled name that is either bogus, or
has been mangled by some algorithm we don't know how to
deal with. So just reject the entire demangling. */
stab_bad_demangle (orig);
return FALSE;
 
default:
/* Assume we have stumbled onto the first outermost function
argument token, and start processing args. */
func_done = TRUE;
if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
return FALSE;
break;
}
 
if (expect_func)
{
func_done = TRUE;
if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
return FALSE;
}
}
 
if (! func_done)
{
/* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
bar__3fooi is 'foo::bar(int)'. We get here when we find the
first case, and need to ensure that the '(void)' gets added
to the current declp. */
if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
return FALSE;
}
 
return TRUE;
}
 
/* Demangle a qualified name, such as "Q25Outer5Inner" which is the
mangled form of "Outer::Inner". */
 
static bfd_boolean
stab_demangle_qualified (struct stab_demangle_info *minfo, const char **pp,
debug_type *ptype)
{
const char *orig;
const char *p;
unsigned int qualifiers;
debug_type context;
 
orig = *pp;
 
switch ((*pp)[1])
{
case '_':
/* GNU mangled name with more than 9 classes. The count is
preceded by an underscore (to distinguish it from the <= 9
case) and followed by an underscore. */
p = *pp + 2;
if (! ISDIGIT (*p) || *p == '0')
{
stab_bad_demangle (orig);
return FALSE;
}
qualifiers = atoi (p);
while (ISDIGIT (*p))
++p;
if (*p != '_')
{
stab_bad_demangle (orig);
return FALSE;
}
*pp = p + 1;
break;
 
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
qualifiers = (*pp)[1] - '0';
/* Skip an optional underscore after the count. */
if ((*pp)[2] == '_')
++*pp;
*pp += 2;
break;
 
case '0':
default:
stab_bad_demangle (orig);
return FALSE;
}
 
context = DEBUG_TYPE_NULL;
 
/* Pick off the names. */
while (qualifiers-- > 0)
{
if (**pp == '_')
++*pp;
if (**pp == 't')
{
char *name;
 
if (! stab_demangle_template (minfo, pp,
ptype != NULL ? &name : NULL))
return FALSE;
 
if (ptype != NULL)
{
context = stab_find_tagged_type (minfo->dhandle, minfo->info,
name, strlen (name),
DEBUG_KIND_CLASS);
free (name);
if (context == DEBUG_TYPE_NULL)
return FALSE;
}
}
else
{
unsigned int len;
 
len = stab_demangle_count (pp);
if (strlen (*pp) < len)
{
stab_bad_demangle (orig);
return FALSE;
}
 
if (ptype != NULL)
{
const debug_field *fields;
 
fields = NULL;
if (context != DEBUG_TYPE_NULL)
fields = debug_get_fields (minfo->dhandle, context);
 
context = DEBUG_TYPE_NULL;
 
if (fields != NULL)
{
char *name;
 
/* Try to find the type by looking through the
fields of context until we find a field with the
same type. This ought to work for a class
defined within a class, but it won't work for,
e.g., an enum defined within a class. stabs does
not give us enough information to figure out the
latter case. */
 
name = savestring (*pp, len);
 
for (; *fields != DEBUG_FIELD_NULL; fields++)
{
debug_type ft;
const char *dn;
 
ft = debug_get_field_type (minfo->dhandle, *fields);
if (ft == NULL)
{
free (name);
return FALSE;
}
dn = debug_get_type_name (minfo->dhandle, ft);
if (dn != NULL && strcmp (dn, name) == 0)
{
context = ft;
break;
}
}
 
free (name);
}
 
if (context == DEBUG_TYPE_NULL)
{
/* We have to fall back on finding the type by name.
If there are more types to come, then this must
be a class. Otherwise, it could be anything. */
 
if (qualifiers == 0)
{
char *name;
 
name = savestring (*pp, len);
context = debug_find_named_type (minfo->dhandle,
name);
free (name);
}
 
if (context == DEBUG_TYPE_NULL)
{
context = stab_find_tagged_type (minfo->dhandle,
minfo->info,
*pp, len,
(qualifiers == 0
? DEBUG_KIND_ILLEGAL
: DEBUG_KIND_CLASS));
if (context == DEBUG_TYPE_NULL)
return FALSE;
}
}
}
 
*pp += len;
}
}
 
if (ptype != NULL)
*ptype = context;
 
return TRUE;
}
 
/* Demangle a template. If PNAME is not NULL, this sets *PNAME to a
string representation of the template. */
 
static bfd_boolean
stab_demangle_template (struct stab_demangle_info *minfo, const char **pp,
char **pname)
{
const char *orig;
unsigned int r, i;
 
orig = *pp;
 
++*pp;
 
/* Skip the template name. */
r = stab_demangle_count (pp);
if (r == 0 || strlen (*pp) < r)
{
stab_bad_demangle (orig);
return FALSE;
}
*pp += r;
 
/* Get the size of the parameter list. */
if (stab_demangle_get_count (pp, &r) == 0)
{
stab_bad_demangle (orig);
return FALSE;
}
 
for (i = 0; i < r; i++)
{
if (**pp == 'Z')
{
/* This is a type parameter. */
++*pp;
if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
return FALSE;
}
else
{
const char *old_p;
bfd_boolean pointerp, realp, integralp, charp, boolp;
bfd_boolean done;
 
old_p = *pp;
pointerp = FALSE;
realp = FALSE;
integralp = FALSE;
charp = FALSE;
boolp = FALSE;
done = FALSE;
 
/* This is a value parameter. */
 
if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
return FALSE;
 
while (*old_p != '\0' && ! done)
{
switch (*old_p)
{
case 'P':
case 'p':
case 'R':
pointerp = TRUE;
done = TRUE;
break;
case 'C': /* Const. */
case 'S': /* Signed. */
case 'U': /* Unsigned. */
case 'V': /* Volatile. */
case 'F': /* Function. */
case 'M': /* Member function. */
case 'O': /* ??? */
++old_p;
break;
case 'Q': /* Qualified name. */
integralp = TRUE;
done = TRUE;
break;
case 'T': /* Remembered type. */
abort ();
case 'v': /* Void. */
abort ();
case 'x': /* Long long. */
case 'l': /* Long. */
case 'i': /* Int. */
case 's': /* Short. */
case 'w': /* Wchar_t. */
integralp = TRUE;
done = TRUE;
break;
case 'b': /* Bool. */
boolp = TRUE;
done = TRUE;
break;
case 'c': /* Char. */
charp = TRUE;
done = TRUE;
break;
case 'r': /* Long double. */
case 'd': /* Double. */
case 'f': /* Float. */
realp = TRUE;
done = TRUE;
break;
default:
/* Assume it's a user defined integral type. */
integralp = TRUE;
done = TRUE;
break;
}
}
 
if (integralp)
{
if (**pp == 'm')
++*pp;
while (ISDIGIT (**pp))
++*pp;
}
else if (charp)
{
unsigned int val;
 
if (**pp == 'm')
++*pp;
val = stab_demangle_count (pp);
if (val == 0)
{
stab_bad_demangle (orig);
return FALSE;
}
}
else if (boolp)
{
unsigned int val;
 
val = stab_demangle_count (pp);
if (val != 0 && val != 1)
{
stab_bad_demangle (orig);
return FALSE;
}
}
else if (realp)
{
if (**pp == 'm')
++*pp;
while (ISDIGIT (**pp))
++*pp;
if (**pp == '.')
{
++*pp;
while (ISDIGIT (**pp))
++*pp;
}
if (**pp == 'e')
{
++*pp;
while (ISDIGIT (**pp))
++*pp;
}
}
else if (pointerp)
{
unsigned int len;
 
len = stab_demangle_count (pp);
if (len == 0)
{
stab_bad_demangle (orig);
return FALSE;
}
*pp += len;
}
}
}
 
/* We can translate this to a string fairly easily by invoking the
regular demangling routine. */
if (pname != NULL)
{
char *s1, *s2, *s3, *s4 = NULL;
char *from, *to;
 
s1 = savestring (orig, *pp - orig);
 
s2 = concat ("NoSuchStrinG__", s1, (const char *) NULL);
 
free (s1);
 
s3 = cplus_demangle (s2, DMGL_ANSI);
 
free (s2);
 
if (s3 != NULL)
s4 = strstr (s3, "::NoSuchStrinG");
if (s3 == NULL || s4 == NULL)
{
stab_bad_demangle (orig);
if (s3 != NULL)
free (s3);
return FALSE;
}
 
/* Eliminating all spaces, except those between > characters,
makes it more likely that the demangled name will match the
name which g++ used as the structure name. */
for (from = to = s3; from != s4; ++from)
if (*from != ' '
|| (from[1] == '>' && from > s3 && from[-1] == '>'))
*to++ = *from;
 
*pname = savestring (s3, to - s3);
 
free (s3);
}
 
return TRUE;
}
 
/* Demangle a class name. */
 
static bfd_boolean
stab_demangle_class (struct stab_demangle_info *minfo ATTRIBUTE_UNUSED,
const char **pp, const char **pstart)
{
const char *orig;
unsigned int n;
 
orig = *pp;
 
n = stab_demangle_count (pp);
if (strlen (*pp) < n)
{
stab_bad_demangle (orig);
return FALSE;
}
 
if (pstart != NULL)
*pstart = *pp;
 
*pp += n;
 
return TRUE;
}
 
/* Demangle function arguments. If the pargs argument is not NULL, it
is set to a NULL terminated array holding the arguments. */
 
static bfd_boolean
stab_demangle_args (struct stab_demangle_info *minfo, const char **pp,
debug_type **pargs, bfd_boolean *pvarargs)
{
const char *orig;
unsigned int alloc, count;
 
orig = *pp;
 
alloc = 10;
if (pargs != NULL)
{
*pargs = (debug_type *) xmalloc (alloc * sizeof **pargs);
*pvarargs = FALSE;
}
count = 0;
 
while (**pp != '_' && **pp != '\0' && **pp != 'e')
{
if (**pp == 'N' || **pp == 'T')
{
char temptype;
unsigned int r, t;
 
temptype = **pp;
++*pp;
 
if (temptype == 'T')
r = 1;
else
{
if (! stab_demangle_get_count (pp, &r))
{
stab_bad_demangle (orig);
return FALSE;
}
}
 
if (! stab_demangle_get_count (pp, &t))
{
stab_bad_demangle (orig);
return FALSE;
}
 
if (t >= minfo->typestring_count)
{
stab_bad_demangle (orig);
return FALSE;
}
while (r-- > 0)
{
const char *tem;
 
tem = minfo->typestrings[t].typestring;
if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc))
return FALSE;
}
}
else
{
if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc))
return FALSE;
}
}
 
if (pargs != NULL)
(*pargs)[count] = DEBUG_TYPE_NULL;
 
if (**pp == 'e')
{
if (pargs != NULL)
*pvarargs = TRUE;
++*pp;
}
 
return TRUE;
}
 
/* Demangle a single argument. */
 
static bfd_boolean
stab_demangle_arg (struct stab_demangle_info *minfo, const char **pp,
debug_type **pargs, unsigned int *pcount,
unsigned int *palloc)
{
const char *start;
debug_type type;
 
start = *pp;
if (! stab_demangle_type (minfo, pp,
pargs == NULL ? (debug_type *) NULL : &type)
|| ! stab_demangle_remember_type (minfo, start, *pp - start))
return FALSE;
 
if (pargs != NULL)
{
if (type == DEBUG_TYPE_NULL)
return FALSE;
 
if (*pcount + 1 >= *palloc)
{
*palloc += 10;
*pargs = ((debug_type *)
xrealloc (*pargs, *palloc * sizeof **pargs));
}
(*pargs)[*pcount] = type;
++*pcount;
}
 
return TRUE;
}
 
/* Demangle a type. If the ptype argument is not NULL, *ptype is set
to the newly allocated type. */
 
static bfd_boolean
stab_demangle_type (struct stab_demangle_info *minfo, const char **pp,
debug_type *ptype)
{
const char *orig;
 
orig = *pp;
 
switch (**pp)
{
case 'P':
case 'p':
/* A pointer type. */
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
if (ptype != NULL)
*ptype = debug_make_pointer_type (minfo->dhandle, *ptype);
break;
 
case 'R':
/* A reference type. */
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
if (ptype != NULL)
*ptype = debug_make_reference_type (minfo->dhandle, *ptype);
break;
 
case 'A':
/* An array. */
{
unsigned long high;
 
++*pp;
high = 0;
while (**pp != '\0' && **pp != '_')
{
if (! ISDIGIT (**pp))
{
stab_bad_demangle (orig);
return FALSE;
}
high *= 10;
high += **pp - '0';
++*pp;
}
if (**pp != '_')
{
stab_bad_demangle (orig);
return FALSE;
}
++*pp;
 
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
if (ptype != NULL)
{
debug_type int_type;
 
int_type = debug_find_named_type (minfo->dhandle, "int");
if (int_type == NULL)
int_type = debug_make_int_type (minfo->dhandle, 4, FALSE);
*ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type,
0, high, FALSE);
}
}
break;
 
case 'T':
/* A back reference to a remembered type. */
{
unsigned int i;
const char *p;
 
++*pp;
if (! stab_demangle_get_count (pp, &i))
{
stab_bad_demangle (orig);
return FALSE;
}
if (i >= minfo->typestring_count)
{
stab_bad_demangle (orig);
return FALSE;
}
p = minfo->typestrings[i].typestring;
if (! stab_demangle_type (minfo, &p, ptype))
return FALSE;
}
break;
 
case 'F':
/* A function. */
{
debug_type *args;
bfd_boolean varargs;
 
++*pp;
if (! stab_demangle_args (minfo, pp,
(ptype == NULL
? (debug_type **) NULL
: &args),
(ptype == NULL
? (bfd_boolean *) NULL
: &varargs)))
return FALSE;
if (**pp != '_')
{
/* cplus_demangle will accept a function without a return
type, but I don't know when that will happen, or what
to do if it does. */
stab_bad_demangle (orig);
return FALSE;
}
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
if (ptype != NULL)
*ptype = debug_make_function_type (minfo->dhandle, *ptype, args,
varargs);
 
}
break;
 
case 'M':
case 'O':
{
bfd_boolean memberp;
debug_type class_type = DEBUG_TYPE_NULL;
debug_type *args;
bfd_boolean varargs;
unsigned int n;
const char *name;
 
memberp = **pp == 'M';
args = NULL;
varargs = FALSE;
 
++*pp;
if (ISDIGIT (**pp))
{
n = stab_demangle_count (pp);
if (strlen (*pp) < n)
{
stab_bad_demangle (orig);
return FALSE;
}
name = *pp;
*pp += n;
 
if (ptype != NULL)
{
class_type = stab_find_tagged_type (minfo->dhandle,
minfo->info,
name, (int) n,
DEBUG_KIND_CLASS);
if (class_type == DEBUG_TYPE_NULL)
return FALSE;
}
}
else if (**pp == 'Q')
{
if (! stab_demangle_qualified (minfo, pp,
(ptype == NULL
? (debug_type *) NULL
: &class_type)))
return FALSE;
}
else
{
stab_bad_demangle (orig);
return FALSE;
}
 
if (memberp)
{
if (**pp == 'C')
{
++*pp;
}
else if (**pp == 'V')
{
++*pp;
}
if (**pp != 'F')
{
stab_bad_demangle (orig);
return FALSE;
}
++*pp;
if (! stab_demangle_args (minfo, pp,
(ptype == NULL
? (debug_type **) NULL
: &args),
(ptype == NULL
? (bfd_boolean *) NULL
: &varargs)))
return FALSE;
}
 
if (**pp != '_')
{
stab_bad_demangle (orig);
return FALSE;
}
++*pp;
 
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
 
if (ptype != NULL)
{
if (! memberp)
*ptype = debug_make_offset_type (minfo->dhandle, class_type,
*ptype);
else
{
/* FIXME: We have no way to record constp or
volatilep. */
*ptype = debug_make_method_type (minfo->dhandle, *ptype,
class_type, args, varargs);
}
}
}
break;
 
case 'G':
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
break;
 
case 'C':
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
if (ptype != NULL)
*ptype = debug_make_const_type (minfo->dhandle, *ptype);
break;
 
case 'Q':
{
if (! stab_demangle_qualified (minfo, pp, ptype))
return FALSE;
}
break;
 
default:
if (! stab_demangle_fund_type (minfo, pp, ptype))
return FALSE;
break;
}
 
return TRUE;
}
 
/* Demangle a fundamental type. If the ptype argument is not NULL,
*ptype is set to the newly allocated type. */
 
static bfd_boolean
stab_demangle_fund_type (struct stab_demangle_info *minfo, const char **pp,
debug_type *ptype)
{
const char *orig;
bfd_boolean constp, volatilep, unsignedp, signedp;
bfd_boolean done;
 
orig = *pp;
 
constp = FALSE;
volatilep = FALSE;
unsignedp = FALSE;
signedp = FALSE;
 
done = FALSE;
while (! done)
{
switch (**pp)
{
case 'C':
constp = TRUE;
++*pp;
break;
 
case 'U':
unsignedp = TRUE;
++*pp;
break;
 
case 'S':
signedp = TRUE;
++*pp;
break;
 
case 'V':
volatilep = TRUE;
++*pp;
break;
 
default:
done = TRUE;
break;
}
}
 
switch (**pp)
{
case '\0':
case '_':
/* cplus_demangle permits this, but I don't know what it means. */
stab_bad_demangle (orig);
break;
 
case 'v': /* void */
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "void");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_void_type (minfo->dhandle);
}
++*pp;
break;
 
case 'x': /* long long */
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle,
(unsignedp
? "long long unsigned int"
: "long long int"));
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp);
}
++*pp;
break;
 
case 'l': /* long */
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle,
(unsignedp
? "long unsigned int"
: "long int"));
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
}
++*pp;
break;
 
case 'i': /* int */
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle,
(unsignedp
? "unsigned int"
: "int"));
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
}
++*pp;
break;
 
case 's': /* short */
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle,
(unsignedp
? "short unsigned int"
: "short int"));
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp);
}
++*pp;
break;
 
case 'b': /* bool */
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "bool");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_bool_type (minfo->dhandle, 4);
}
++*pp;
break;
 
case 'c': /* char */
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle,
(unsignedp
? "unsigned char"
: (signedp
? "signed char"
: "char")));
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp);
}
++*pp;
break;
 
case 'w': /* wchar_t */
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "__wchar_t");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 2, TRUE);
}
++*pp;
break;
 
case 'r': /* long double */
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "long double");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_float_type (minfo->dhandle, 8);
}
++*pp;
break;
 
case 'd': /* double */
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "double");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_float_type (minfo->dhandle, 8);
}
++*pp;
break;
 
case 'f': /* float */
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "float");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_float_type (minfo->dhandle, 4);
}
++*pp;
break;
 
case 'G':
++*pp;
if (! ISDIGIT (**pp))
{
stab_bad_demangle (orig);
return FALSE;
}
/* Fall through. */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
const char *hold;
 
if (! stab_demangle_class (minfo, pp, &hold))
return FALSE;
if (ptype != NULL)
{
char *name;
 
name = savestring (hold, *pp - hold);
*ptype = debug_find_named_type (minfo->dhandle, name);
free (name);
if (*ptype == DEBUG_TYPE_NULL)
{
/* FIXME: It is probably incorrect to assume that
undefined types are tagged types. */
*ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
hold, *pp - hold,
DEBUG_KIND_ILLEGAL);
if (*ptype == DEBUG_TYPE_NULL)
return FALSE;
}
}
}
break;
 
case 't':
{
char *name;
 
if (! stab_demangle_template (minfo, pp,
ptype != NULL ? &name : NULL))
return FALSE;
if (ptype != NULL)
{
*ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
name, strlen (name),
DEBUG_KIND_CLASS);
free (name);
if (*ptype == DEBUG_TYPE_NULL)
return FALSE;
}
}
break;
 
default:
stab_bad_demangle (orig);
return FALSE;
}
 
if (ptype != NULL)
{
if (constp)
*ptype = debug_make_const_type (minfo->dhandle, *ptype);
if (volatilep)
*ptype = debug_make_volatile_type (minfo->dhandle, *ptype);
}
 
return TRUE;
}
 
/* Remember a type string in a demangled string. */
 
static bfd_boolean
stab_demangle_remember_type (struct stab_demangle_info *minfo,
const char *p, int len)
{
if (minfo->typestring_count >= minfo->typestring_alloc)
{
minfo->typestring_alloc += 10;
minfo->typestrings = ((struct stab_demangle_typestring *)
xrealloc (minfo->typestrings,
(minfo->typestring_alloc
* sizeof *minfo->typestrings)));
}
 
minfo->typestrings[minfo->typestring_count].typestring = p;
minfo->typestrings[minfo->typestring_count].len = (unsigned int) len;
++minfo->typestring_count;
 
return TRUE;
}
/* Demangle names encoded using the g++ V3 ABI. The newer versions of
g++ which use this ABI do not encode ordinary method argument types
in a mangled name; they simply output the argument types. However,
for a static method, g++ simply outputs the return type and the
physical name. So in that case we need to demangle the name here.
Here PHYSNAME is the physical name of the function, and we set the
variable pointed at by PVARARGS to indicate whether this function
is varargs. This returns NULL, or a NULL terminated array of
argument types. */
 
static debug_type *
stab_demangle_v3_argtypes (void *dhandle, struct stab_handle *info,
const char *physname, bfd_boolean *pvarargs)
{
struct demangle_component *dc;
void *mem;
debug_type *pargs;
 
dc = cplus_demangle_v3_components (physname, DMGL_PARAMS | DMGL_ANSI, &mem);
if (dc == NULL)
{
stab_bad_demangle (physname);
return NULL;
}
 
/* We expect to see TYPED_NAME, and the right subtree describes the
function type. */
if (dc->type != DEMANGLE_COMPONENT_TYPED_NAME
|| dc->u.s_binary.right->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
{
fprintf (stderr, _("Demangled name is not a function\n"));
free (mem);
return NULL;
}
 
pargs = stab_demangle_v3_arglist (dhandle, info,
dc->u.s_binary.right->u.s_binary.right,
pvarargs);
 
free (mem);
 
return pargs;
}
 
/* Demangle an argument list in a struct demangle_component tree.
Returns a DEBUG_TYPE_NULL terminated array of argument types, and
sets *PVARARGS to indicate whether this is a varargs function. */
 
static debug_type *
stab_demangle_v3_arglist (void *dhandle, struct stab_handle *info,
struct demangle_component *arglist,
bfd_boolean *pvarargs)
{
struct demangle_component *dc;
unsigned int alloc, count;
debug_type *pargs;
 
alloc = 10;
pargs = (debug_type *) xmalloc (alloc * sizeof *pargs);
*pvarargs = FALSE;
 
count = 0;
 
for (dc = arglist;
dc != NULL;
dc = dc->u.s_binary.right)
{
debug_type arg;
bfd_boolean varargs;
 
if (dc->type != DEMANGLE_COMPONENT_ARGLIST)
{
fprintf (stderr, _("Unexpected type in v3 arglist demangling\n"));
free (pargs);
return NULL;
}
 
/* PR 13925: Cope if the demangler returns an empty
context for a function with no arguments. */
if (dc->u.s_binary.left == NULL)
break;
arg = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left,
NULL, &varargs);
if (arg == NULL)
{
if (varargs)
{
*pvarargs = TRUE;
continue;
}
free (pargs);
return NULL;
}
 
if (count + 1 >= alloc)
{
alloc += 10;
pargs = (debug_type *) xrealloc (pargs, alloc * sizeof *pargs);
}
 
pargs[count] = arg;
++count;
}
 
pargs[count] = DEBUG_TYPE_NULL;
 
return pargs;
}
 
/* Convert a struct demangle_component tree describing an argument
type into a debug_type. */
 
static debug_type
stab_demangle_v3_arg (void *dhandle, struct stab_handle *info,
struct demangle_component *dc, debug_type context,
bfd_boolean *pvarargs)
{
debug_type dt;
 
if (pvarargs != NULL)
*pvarargs = FALSE;
 
switch (dc->type)
{
/* FIXME: These are demangle component types which we probably
need to handle one way or another. */
case DEMANGLE_COMPONENT_LOCAL_NAME:
case DEMANGLE_COMPONENT_TYPED_NAME:
case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
case DEMANGLE_COMPONENT_CTOR:
case DEMANGLE_COMPONENT_DTOR:
case DEMANGLE_COMPONENT_JAVA_CLASS:
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
case DEMANGLE_COMPONENT_COMPLEX:
case DEMANGLE_COMPONENT_IMAGINARY:
case DEMANGLE_COMPONENT_VENDOR_TYPE:
case DEMANGLE_COMPONENT_ARRAY_TYPE:
case DEMANGLE_COMPONENT_PTRMEM_TYPE:
case DEMANGLE_COMPONENT_ARGLIST:
default:
fprintf (stderr, _("Unrecognized demangle component %d\n"),
(int) dc->type);
return NULL;
 
case DEMANGLE_COMPONENT_NAME:
if (context != NULL)
{
const debug_field *fields;
 
fields = debug_get_fields (dhandle, context);
if (fields != NULL)
{
/* Try to find this type by looking through the context
class. */
for (; *fields != DEBUG_FIELD_NULL; fields++)
{
debug_type ft;
const char *dn;
 
ft = debug_get_field_type (dhandle, *fields);
if (ft == NULL)
return NULL;
dn = debug_get_type_name (dhandle, ft);
if (dn != NULL
&& (int) strlen (dn) == dc->u.s_name.len
&& strncmp (dn, dc->u.s_name.s, dc->u.s_name.len) == 0)
return ft;
}
}
}
return stab_find_tagged_type (dhandle, info, dc->u.s_name.s,
dc->u.s_name.len, DEBUG_KIND_ILLEGAL);
 
case DEMANGLE_COMPONENT_QUAL_NAME:
context = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left,
context, NULL);
if (context == NULL)
return NULL;
return stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.right,
context, NULL);
 
case DEMANGLE_COMPONENT_TEMPLATE:
{
char *p;
size_t alc;
 
/* We print this component to get a class name which we can
use. FIXME: This probably won't work if the template uses
template parameters which refer to an outer template. */
p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
if (p == NULL)
{
fprintf (stderr, _("Failed to print demangled template\n"));
return NULL;
}
dt = stab_find_tagged_type (dhandle, info, p, strlen (p),
DEBUG_KIND_CLASS);
free (p);
return dt;
}
 
case DEMANGLE_COMPONENT_SUB_STD:
return stab_find_tagged_type (dhandle, info, dc->u.s_string.string,
dc->u.s_string.len, DEBUG_KIND_ILLEGAL);
 
case DEMANGLE_COMPONENT_RESTRICT:
case DEMANGLE_COMPONENT_VOLATILE:
case DEMANGLE_COMPONENT_CONST:
case DEMANGLE_COMPONENT_POINTER:
case DEMANGLE_COMPONENT_REFERENCE:
dt = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, NULL,
NULL);
if (dt == NULL)
return NULL;
 
switch (dc->type)
{
default:
abort ();
case DEMANGLE_COMPONENT_RESTRICT:
/* FIXME: We have no way to represent restrict. */
return dt;
case DEMANGLE_COMPONENT_VOLATILE:
return debug_make_volatile_type (dhandle, dt);
case DEMANGLE_COMPONENT_CONST:
return debug_make_const_type (dhandle, dt);
case DEMANGLE_COMPONENT_POINTER:
return debug_make_pointer_type (dhandle, dt);
case DEMANGLE_COMPONENT_REFERENCE:
return debug_make_reference_type (dhandle, dt);
}
 
case DEMANGLE_COMPONENT_FUNCTION_TYPE:
{
debug_type *pargs;
bfd_boolean varargs;
 
if (dc->u.s_binary.left == NULL)
{
/* In this case the return type is actually unknown.
However, I'm not sure this will ever arise in practice;
normally an unknown return type would only appear at
the top level, which is handled above. */
dt = debug_make_void_type (dhandle);
}
else
dt = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, NULL,
NULL);
if (dt == NULL)
return NULL;
 
pargs = stab_demangle_v3_arglist (dhandle, info,
dc->u.s_binary.right,
&varargs);
if (pargs == NULL)
return NULL;
 
return debug_make_function_type (dhandle, dt, pargs, varargs);
}
 
case DEMANGLE_COMPONENT_BUILTIN_TYPE:
{
char *p;
size_t alc;
debug_type ret;
 
/* We print this component in order to find out the type name.
FIXME: Should we instead expose the
demangle_builtin_type_info structure? */
p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
if (p == NULL)
{
fprintf (stderr, _("Couldn't get demangled builtin type\n"));
return NULL;
}
 
/* The mangling is based on the type, but does not itself
indicate what the sizes are. So we have to guess. */
if (strcmp (p, "signed char") == 0)
ret = debug_make_int_type (dhandle, 1, FALSE);
else if (strcmp (p, "bool") == 0)
ret = debug_make_bool_type (dhandle, 1);
else if (strcmp (p, "char") == 0)
ret = debug_make_int_type (dhandle, 1, FALSE);
else if (strcmp (p, "double") == 0)
ret = debug_make_float_type (dhandle, 8);
else if (strcmp (p, "long double") == 0)
ret = debug_make_float_type (dhandle, 8);
else if (strcmp (p, "float") == 0)
ret = debug_make_float_type (dhandle, 4);
else if (strcmp (p, "__float128") == 0)
ret = debug_make_float_type (dhandle, 16);
else if (strcmp (p, "unsigned char") == 0)
ret = debug_make_int_type (dhandle, 1, TRUE);
else if (strcmp (p, "int") == 0)
ret = debug_make_int_type (dhandle, 4, FALSE);
else if (strcmp (p, "unsigned int") == 0)
ret = debug_make_int_type (dhandle, 4, TRUE);
else if (strcmp (p, "long") == 0)
ret = debug_make_int_type (dhandle, 4, FALSE);
else if (strcmp (p, "unsigned long") == 0)
ret = debug_make_int_type (dhandle, 4, TRUE);
else if (strcmp (p, "__int128") == 0)
ret = debug_make_int_type (dhandle, 16, FALSE);
else if (strcmp (p, "unsigned __int128") == 0)
ret = debug_make_int_type (dhandle, 16, TRUE);
else if (strcmp (p, "short") == 0)
ret = debug_make_int_type (dhandle, 2, FALSE);
else if (strcmp (p, "unsigned short") == 0)
ret = debug_make_int_type (dhandle, 2, TRUE);
else if (strcmp (p, "void") == 0)
ret = debug_make_void_type (dhandle);
else if (strcmp (p, "wchar_t") == 0)
ret = debug_make_int_type (dhandle, 4, TRUE);
else if (strcmp (p, "long long") == 0)
ret = debug_make_int_type (dhandle, 8, FALSE);
else if (strcmp (p, "unsigned long long") == 0)
ret = debug_make_int_type (dhandle, 8, TRUE);
else if (strcmp (p, "...") == 0)
{
if (pvarargs == NULL)
fprintf (stderr, _("Unexpected demangled varargs\n"));
else
*pvarargs = TRUE;
ret = NULL;
}
else
{
fprintf (stderr, _("Unrecognized demangled builtin type\n"));
ret = NULL;
}
 
free (p);
 
return ret;
}
}
}
/contrib/toolchain/binutils/binutils/sysdep.h
0,0 → 1,188
/* sysdep.h -- handle host dependencies for binutils
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009, 2012
Free Software Foundation, Inc.
 
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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef _BIN_SYSDEP_H
#define _BIN_SYSDEP_H
 
#include "alloca-conf.h"
#include "ansidecl.h"
#include <stdio.h>
#include <sys/types.h>
 
#include "bfdver.h"
 
#include <stdarg.h>
 
#ifdef USE_BINARY_FOPEN
#include "fopen-bin.h"
#else
#include "fopen-same.h"
#endif
 
#include <errno.h>
#ifndef errno
extern int errno;
#endif
 
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
 
#ifdef STRING_WITH_STRINGS
#include <string.h>
#include <strings.h>
#else
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#else
extern char *strchr ();
extern char *strrchr ();
#endif
#endif
#endif
 
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
 
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#else
#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
#endif
 
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
 
#include "binary-io.h"
 
#if !HAVE_DECL_STPCPY
extern char *stpcpy (char *, const char *);
#endif
 
#if !HAVE_DECL_STRSTR
extern char *strstr ();
#endif
 
#ifdef HAVE_SBRK
#if !HAVE_DECL_SBRK
extern char *sbrk ();
#endif
#endif
 
#if !HAVE_DECL_GETENV
extern char *getenv ();
#endif
 
#if !HAVE_DECL_ENVIRON
extern char **environ;
#endif
 
#if !HAVE_DECL_FPRINTF
extern int fprintf (FILE *, const char *, ...);
#endif
 
#if !HAVE_DECL_SNPRINTF
extern int snprintf(char *, size_t, const char *, ...);
#endif
 
#if !HAVE_DECL_VSNPRINTF
extern int vsnprintf(char *, size_t, const char *, va_list);
#endif
 
#ifndef O_RDONLY
#define O_RDONLY 0
#endif
 
#ifndef O_RDWR
#define O_RDWR 2
#endif
 
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
 
#ifdef HAVE_LOCALE_H
# ifndef ENABLE_NLS
/* The Solaris version of locale.h always includes libintl.h. If we have
been configured with --disable-nls then ENABLE_NLS will not be defined
and the dummy definitions of bindtextdomain (et al) below will conflict
with the defintions in libintl.h. So we define these values to prevent
the bogus inclusion of libintl.h. */
# define _LIBINTL_H
# define _LIBGETTEXT_H
# endif
# include <locale.h>
#endif
 
#ifdef ENABLE_NLS
# include <libintl.h>
# define _(String) gettext (String)
# ifdef gettext_noop
# define N_(String) gettext_noop (String)
# else
# define N_(String) (String)
# endif
#else
# define gettext(Msgid) (Msgid)
# define dgettext(Domainname, Msgid) (Msgid)
# define dcgettext(Domainname, Msgid, Category) (Msgid)
# define textdomain(Domainname) while (0) /* nothing */
# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */
# define _(String) (String)
# define N_(String) (String)
#endif
 
/* Used by ar.c and objcopy.c. */
#define BUFSIZE 8192
 
/* For PATH_MAX. */
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
 
#ifndef PATH_MAX
/* For MAXPATHLEN. */
# ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
# endif
# ifndef PATH_MAX
# ifdef MAXPATHLEN
# define PATH_MAX MAXPATHLEN
# else
# define PATH_MAX 1024
# endif
# endif
#endif
 
#endif /* _BIN_SYSDEP_H */
/contrib/toolchain/binutils/binutils/version.c
0,0 → 1,42
/* version.c -- binutils version information
Copyright 1991, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
Free Software Foundation, Inc.
 
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 3, 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, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
 
#include "sysdep.h"
#include "bfd.h"
#include "bucomm.h"
 
/* Print the version number and copyright information, and exit.
This implements the --version option for the various programs. */
 
void
print_version (const char *name)
{
/* This output is intended to follow the GNU standards document. */
/* xgettext:c-format */
printf ("GNU %s %s\n", name, BFD_VERSION_STRING);
printf (_("Copyright 2013 Free Software Foundation, Inc.\n"));
printf (_("\
This program is free software; you may redistribute it under the terms of\n\
the GNU General Public License version 3 or (at your option) any later version.\n\
This program has absolutely no warranty.\n"));
exit (0);
}
/contrib/toolchain/binutils/binutils/wrstabs.c
0,0 → 1,2272
/* wrstabs.c -- Output stabs debugging information
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006,
2007, 2009 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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
/* This file contains code which writes out stabs debugging
information. */
 
#include "sysdep.h"
#include <assert.h>
#include "bfd.h"
#include "libiberty.h"
#include "filenames.h"
#include "safe-ctype.h"
#include "bucomm.h"
#include "debug.h"
#include "budbg.h"
#include "aout/aout64.h"
#include "aout/stab_gnu.h"
 
/* The size of a stabs symbol. This presumes 32 bit values. */
 
#define STAB_SYMBOL_SIZE (12)
 
/* An entry in a string hash table. */
 
struct string_hash_entry
{
struct bfd_hash_entry root;
/* Next string in this table. */
struct string_hash_entry *next;
/* Index in string table. */
long index;
/* Size of type if this is a typedef. */
unsigned int size;
};
 
/* A string hash table. */
 
struct string_hash_table
{
struct bfd_hash_table table;
};
 
/* The type stack. Each element on the stack is a string. */
 
struct stab_type_stack
{
/* The next element on the stack. */
struct stab_type_stack *next;
/* This element as a string. */
char *string;
/* The type index of this element. */
long index;
/* The size of the type. */
unsigned int size;
/* Whether type string defines a new type. */
bfd_boolean definition;
/* String defining struct fields. */
char *fields;
/* NULL terminated array of strings defining base classes for a
class. */
char **baseclasses;
/* String defining class methods. */
char *methods;
/* String defining vtable pointer for a class. */
char *vtable;
};
 
/* This structure is used to keep track of type indices for tagged
types. */
 
struct stab_tag
{
/* The type index. */
long index;
/* The tag name. */
const char *tag;
/* The kind of type. This is set to DEBUG_KIND_ILLEGAL when the
type is defined. */
enum debug_type_kind kind;
/* The size of the struct. */
unsigned int size;
};
 
/* We remember various sorts of type indices. They are not related,
but, for convenience, we keep all the information in this
structure. */
 
struct stab_type_cache
{
/* The void type index. */
long void_type;
/* Signed integer type indices, indexed by size - 1. */
long signed_integer_types[8];
/* Unsigned integer type indices, indexed by size - 1. */
long unsigned_integer_types[8];
/* Floating point types, indexed by size - 1. */
long float_types[16];
/* Pointers to types, indexed by the type index. */
long *pointer_types;
size_t pointer_types_alloc;
/* Functions returning types, indexed by the type index. */
long *function_types;
size_t function_types_alloc;
/* References to types, indexed by the type index. */
long *reference_types;
size_t reference_types_alloc;
/* Struct/union/class type indices, indexed by the struct id. */
struct stab_tag *struct_types;
size_t struct_types_alloc;
};
 
/* This is the handle passed through debug_write. */
 
struct stab_write_handle
{
/* The BFD. */
bfd *abfd;
/* This buffer holds the symbols. */
bfd_byte *symbols;
size_t symbols_size;
size_t symbols_alloc;
/* This is a list of hash table entries for the strings. */
struct string_hash_entry *strings;
/* The last string hash table entry. */
struct string_hash_entry *last_string;
/* The size of the strings. */
size_t strings_size;
/* This hash table eliminates duplicate strings. */
struct string_hash_table strhash;
/* The type stack. */
struct stab_type_stack *type_stack;
/* The next type index. */
long type_index;
/* The type cache. */
struct stab_type_cache type_cache;
/* A mapping from typedef names to type indices. */
struct string_hash_table typedef_hash;
/* If this is not -1, it is the offset to the most recent N_SO
symbol, and the value of that symbol needs to be set. */
long so_offset;
/* If this is not -1, it is the offset to the most recent N_FUN
symbol, and the value of that symbol needs to be set. */
long fun_offset;
/* The last text section address seen. */
bfd_vma last_text_address;
/* The block nesting depth. */
unsigned int nesting;
/* The function address. */
bfd_vma fnaddr;
/* A pending LBRAC symbol. */
bfd_vma pending_lbrac;
/* The current line number file name. */
const char *lineno_filename;
};
 
static struct bfd_hash_entry *string_hash_newfunc
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
static bfd_boolean stab_write_symbol
(struct stab_write_handle *, int, int, bfd_vma, const char *);
static bfd_boolean stab_push_string
(struct stab_write_handle *, const char *, long, bfd_boolean, unsigned int);
static bfd_boolean stab_push_defined_type
(struct stab_write_handle *, long, unsigned int);
static char *stab_pop_type (struct stab_write_handle *);
static bfd_boolean stab_modify_type
(struct stab_write_handle *, int, unsigned int, long **, size_t *);
static long stab_get_struct_index
(struct stab_write_handle *, const char *, unsigned int,
enum debug_type_kind, unsigned int *);
static bfd_boolean stab_class_method_var
(struct stab_write_handle *, const char *, enum debug_visibility,
bfd_boolean, bfd_boolean, bfd_boolean, bfd_vma, bfd_boolean);
static bfd_boolean stab_start_compilation_unit (void *, const char *);
static bfd_boolean stab_start_source (void *, const char *);
static bfd_boolean stab_empty_type (void *);
static bfd_boolean stab_void_type (void *);
static bfd_boolean stab_int_type (void *, unsigned int, bfd_boolean);
static bfd_boolean stab_float_type (void *, unsigned int);
static bfd_boolean stab_complex_type (void *, unsigned int);
static bfd_boolean stab_bool_type (void *, unsigned int);
static bfd_boolean stab_enum_type
(void *, const char *, const char **, bfd_signed_vma *);
static bfd_boolean stab_pointer_type (void *);
static bfd_boolean stab_function_type (void *, int, bfd_boolean);
static bfd_boolean stab_reference_type (void *);
static bfd_boolean stab_range_type (void *, bfd_signed_vma, bfd_signed_vma);
static bfd_boolean stab_array_type
(void *, bfd_signed_vma, bfd_signed_vma, bfd_boolean);
static bfd_boolean stab_set_type (void *, bfd_boolean);
static bfd_boolean stab_offset_type (void *);
static bfd_boolean stab_method_type (void *, bfd_boolean, int, bfd_boolean);
static bfd_boolean stab_const_type (void *);
static bfd_boolean stab_volatile_type (void *);
static bfd_boolean stab_start_struct_type
(void *, const char *, unsigned int, bfd_boolean, unsigned int);
static bfd_boolean stab_struct_field
(void *, const char *, bfd_vma, bfd_vma, enum debug_visibility);
static bfd_boolean stab_end_struct_type (void *);
static bfd_boolean stab_start_class_type
(void *, const char *, unsigned int, bfd_boolean, unsigned int,
bfd_boolean, bfd_boolean);
static bfd_boolean stab_class_static_member
(void *, const char *, const char *, enum debug_visibility);
static bfd_boolean stab_class_baseclass
(void *, bfd_vma, bfd_boolean, enum debug_visibility);
static bfd_boolean stab_class_start_method (void *, const char *);
static bfd_boolean stab_class_method_variant
(void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean,
bfd_vma, bfd_boolean);
static bfd_boolean stab_class_static_method_variant
(void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean);
static bfd_boolean stab_class_end_method (void *);
static bfd_boolean stab_end_class_type (void *);
static bfd_boolean stab_typedef_type (void *, const char *);
static bfd_boolean stab_tag_type
(void *, const char *, unsigned int, enum debug_type_kind);
static bfd_boolean stab_typdef (void *, const char *);
static bfd_boolean stab_tag (void *, const char *);
static bfd_boolean stab_int_constant (void *, const char *, bfd_vma);
static bfd_boolean stab_float_constant (void *, const char *, double);
static bfd_boolean stab_typed_constant (void *, const char *, bfd_vma);
static bfd_boolean stab_variable
(void *, const char *, enum debug_var_kind, bfd_vma);
static bfd_boolean stab_start_function (void *, const char *, bfd_boolean);
static bfd_boolean stab_function_parameter
(void *, const char *, enum debug_parm_kind, bfd_vma);
static bfd_boolean stab_start_block (void *, bfd_vma);
static bfd_boolean stab_end_block (void *, bfd_vma);
static bfd_boolean stab_end_function (void *);
static bfd_boolean stab_lineno (void *, const char *, unsigned long, bfd_vma);
 
static const struct debug_write_fns stab_fns =
{
stab_start_compilation_unit,
stab_start_source,
stab_empty_type,
stab_void_type,
stab_int_type,
stab_float_type,
stab_complex_type,
stab_bool_type,
stab_enum_type,
stab_pointer_type,
stab_function_type,
stab_reference_type,
stab_range_type,
stab_array_type,
stab_set_type,
stab_offset_type,
stab_method_type,
stab_const_type,
stab_volatile_type,
stab_start_struct_type,
stab_struct_field,
stab_end_struct_type,
stab_start_class_type,
stab_class_static_member,
stab_class_baseclass,
stab_class_start_method,
stab_class_method_variant,
stab_class_static_method_variant,
stab_class_end_method,
stab_end_class_type,
stab_typedef_type,
stab_tag_type,
stab_typdef,
stab_tag,
stab_int_constant,
stab_float_constant,
stab_typed_constant,
stab_variable,
stab_start_function,
stab_function_parameter,
stab_start_block,
stab_end_block,
stab_end_function,
stab_lineno
};
/* Routine to create an entry in a string hash table. */
 
static struct bfd_hash_entry *
string_hash_newfunc (struct bfd_hash_entry *entry,
struct bfd_hash_table *table, const char *string)
{
struct string_hash_entry *ret = (struct string_hash_entry *) entry;
 
/* Allocate the structure if it has not already been allocated by a
subclass. */
if (ret == (struct string_hash_entry *) NULL)
ret = ((struct string_hash_entry *)
bfd_hash_allocate (table, sizeof (struct string_hash_entry)));
if (ret == (struct string_hash_entry *) NULL)
return NULL;
 
/* Call the allocation method of the superclass. */
ret = ((struct string_hash_entry *)
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
 
if (ret)
{
/* Initialize the local fields. */
ret->next = NULL;
ret->index = -1;
ret->size = 0;
}
 
return (struct bfd_hash_entry *) ret;
}
 
/* Look up an entry in a string hash table. */
 
#define string_hash_lookup(t, string, create, copy) \
((struct string_hash_entry *) \
bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
 
/* Add a symbol to the stabs debugging information we are building. */
 
static bfd_boolean
stab_write_symbol (struct stab_write_handle *info, int type, int desc,
bfd_vma value, const char *string)
{
bfd_size_type strx;
bfd_byte sym[STAB_SYMBOL_SIZE];
 
if (string == NULL)
strx = 0;
else
{
struct string_hash_entry *h;
 
h = string_hash_lookup (&info->strhash, string, TRUE, TRUE);
if (h == NULL)
{
non_fatal (_("string_hash_lookup failed: %s"),
bfd_errmsg (bfd_get_error ()));
return FALSE;
}
if (h->index != -1)
strx = h->index;
else
{
strx = info->strings_size;
h->index = strx;
if (info->last_string == NULL)
info->strings = h;
else
info->last_string->next = h;
info->last_string = h;
info->strings_size += strlen (string) + 1;
}
}
 
/* This presumes 32 bit values. */
bfd_put_32 (info->abfd, strx, sym);
bfd_put_8 (info->abfd, type, sym + 4);
bfd_put_8 (info->abfd, 0, sym + 5);
bfd_put_16 (info->abfd, desc, sym + 6);
bfd_put_32 (info->abfd, value, sym + 8);
 
if (info->symbols_size + STAB_SYMBOL_SIZE > info->symbols_alloc)
{
info->symbols_alloc *= 2;
info->symbols = (bfd_byte *) xrealloc (info->symbols,
info->symbols_alloc);
}
 
memcpy (info->symbols + info->symbols_size, sym, STAB_SYMBOL_SIZE);
 
info->symbols_size += STAB_SYMBOL_SIZE;
 
return TRUE;
}
 
/* Push a string on to the type stack. */
 
static bfd_boolean
stab_push_string (struct stab_write_handle *info, const char *string,
long tindex, bfd_boolean definition, unsigned int size)
{
struct stab_type_stack *s;
 
s = (struct stab_type_stack *) xmalloc (sizeof *s);
s->string = xstrdup (string);
s->index = tindex;
s->definition = definition;
s->size = size;
 
s->fields = NULL;
s->baseclasses = NULL;
s->methods = NULL;
s->vtable = NULL;
 
s->next = info->type_stack;
info->type_stack = s;
 
return TRUE;
}
 
/* Push a type index which has already been defined. */
 
static bfd_boolean
stab_push_defined_type (struct stab_write_handle *info, long tindex,
unsigned int size)
{
char buf[20];
 
sprintf (buf, "%ld", tindex);
return stab_push_string (info, buf, tindex, FALSE, size);
}
 
/* Pop a type off the type stack. The caller is responsible for
freeing the string. */
 
static char *
stab_pop_type (struct stab_write_handle *info)
{
struct stab_type_stack *s;
char *ret;
 
s = info->type_stack;
assert (s != NULL);
 
info->type_stack = s->next;
 
ret = s->string;
 
free (s);
 
return ret;
}
/* The general routine to write out stabs in sections debugging
information. This accumulates the stabs symbols and the strings in
two obstacks. We can't easily write out the information as we go
along, because we need to know the section sizes before we can
write out the section contents. ABFD is the BFD and DHANDLE is the
handle for the debugging information. This sets *PSYMS to point to
the symbols, *PSYMSIZE the size of the symbols, *PSTRINGS to the
strings, and *PSTRINGSIZE to the size of the strings. */
 
bfd_boolean
write_stabs_in_sections_debugging_info (bfd *abfd, void *dhandle,
bfd_byte **psyms,
bfd_size_type *psymsize,
bfd_byte **pstrings,
bfd_size_type *pstringsize)
{
struct stab_write_handle info;
struct string_hash_entry *h;
bfd_byte *p;
 
info.abfd = abfd;
 
info.symbols_size = 0;
info.symbols_alloc = 500;
info.symbols = (bfd_byte *) xmalloc (info.symbols_alloc);
 
info.strings = NULL;
info.last_string = NULL;
/* Reserve 1 byte for a null byte. */
info.strings_size = 1;
 
if (!bfd_hash_table_init (&info.strhash.table, string_hash_newfunc,
sizeof (struct string_hash_entry))
|| !bfd_hash_table_init (&info.typedef_hash.table, string_hash_newfunc,
sizeof (struct string_hash_entry)))
{
non_fatal ("bfd_hash_table_init_failed: %s",
bfd_errmsg (bfd_get_error ()));
return FALSE;
}
 
info.type_stack = NULL;
info.type_index = 1;
memset (&info.type_cache, 0, sizeof info.type_cache);
info.so_offset = -1;
info.fun_offset = -1;
info.last_text_address = 0;
info.nesting = 0;
info.fnaddr = 0;
info.pending_lbrac = (bfd_vma) -1;
 
/* The initial symbol holds the string size. */
if (! stab_write_symbol (&info, 0, 0, 0, (const char *) NULL))
return FALSE;
 
/* Output an initial N_SO symbol. */
info.so_offset = info.symbols_size;
if (! stab_write_symbol (&info, N_SO, 0, 0, bfd_get_filename (abfd)))
return FALSE;
 
if (! debug_write (dhandle, &stab_fns, (void *) &info))
return FALSE;
 
assert (info.pending_lbrac == (bfd_vma) -1);
 
/* Output a trailing N_SO. */
if (! stab_write_symbol (&info, N_SO, 0, info.last_text_address,
(const char *) NULL))
return FALSE;
 
/* Put the string size in the initial symbol. */
bfd_put_32 (abfd, info.strings_size, info.symbols + 8);
 
*psyms = info.symbols;
*psymsize = info.symbols_size;
 
*pstringsize = info.strings_size;
*pstrings = (bfd_byte *) xmalloc (info.strings_size);
 
p = *pstrings;
*p++ = '\0';
for (h = info.strings; h != NULL; h = h->next)
{
strcpy ((char *) p, h->root.string);
p += strlen ((char *) p) + 1;
}
 
return TRUE;
}
 
/* Start writing out information for a compilation unit. */
 
static bfd_boolean
stab_start_compilation_unit (void *p, const char *filename)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
/* We would normally output an N_SO symbol here. However, that
would force us to reset all of our type information. I think we
will be better off just outputting an N_SOL symbol, and not
worrying about splitting information between files. */
 
info->lineno_filename = filename;
 
return stab_write_symbol (info, N_SOL, 0, 0, filename);
}
 
/* Start writing out information for a particular source file. */
 
static bfd_boolean
stab_start_source (void *p, const char *filename)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
/* FIXME: The symbol's value is supposed to be the text section
address. However, we would have to fill it in later, and gdb
doesn't care, so we don't bother with it. */
 
info->lineno_filename = filename;
 
return stab_write_symbol (info, N_SOL, 0, 0, filename);
}
 
/* Push an empty type. This shouldn't normally happen. We just use a
void type. */
 
static bfd_boolean
stab_empty_type (void *p)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
/* We don't call stab_void_type if the type is not yet defined,
because that might screw up the typedef. */
 
if (info->type_cache.void_type != 0)
return stab_push_defined_type (info, info->type_cache.void_type, 0);
else
{
long tindex;
char buf[40];
 
tindex = info->type_index;
++info->type_index;
 
sprintf (buf, "%ld=%ld", tindex, tindex);
 
return stab_push_string (info, buf, tindex, FALSE, 0);
}
}
 
/* Push a void type. */
 
static bfd_boolean
stab_void_type (void *p)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
if (info->type_cache.void_type != 0)
return stab_push_defined_type (info, info->type_cache.void_type, 0);
else
{
long tindex;
char buf[40];
 
tindex = info->type_index;
++info->type_index;
 
info->type_cache.void_type = tindex;
 
sprintf (buf, "%ld=%ld", tindex, tindex);
 
return stab_push_string (info, buf, tindex, TRUE, 0);
}
}
 
/* Push an integer type. */
 
static bfd_boolean
stab_int_type (void *p, unsigned int size, bfd_boolean unsignedp)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
long *cache;
 
if (size <= 0 || (size > sizeof (long) && size != 8))
{
non_fatal (_("stab_int_type: bad size %u"), size);
return FALSE;
}
 
if (unsignedp)
cache = info->type_cache.signed_integer_types;
else
cache = info->type_cache.unsigned_integer_types;
 
if (cache[size - 1] != 0)
return stab_push_defined_type (info, cache[size - 1], size);
else
{
long tindex;
char buf[100];
 
tindex = info->type_index;
++info->type_index;
 
cache[size - 1] = tindex;
 
sprintf (buf, "%ld=r%ld;", tindex, tindex);
if (unsignedp)
{
strcat (buf, "0;");
if (size < sizeof (long))
sprintf (buf + strlen (buf), "%ld;", ((long) 1 << (size * 8)) - 1);
else if (size == sizeof (long))
strcat (buf, "-1;");
else if (size == 8)
strcat (buf, "01777777777777777777777;");
else
abort ();
}
else
{
if (size <= sizeof (long))
sprintf (buf + strlen (buf), "%ld;%ld;",
(long) - ((unsigned long) 1 << (size * 8 - 1)),
(long) (((unsigned long) 1 << (size * 8 - 1)) - 1));
else if (size == 8)
strcat (buf, "01000000000000000000000;0777777777777777777777;");
else
abort ();
}
 
return stab_push_string (info, buf, tindex, TRUE, size);
}
}
 
/* Push a floating point type. */
 
static bfd_boolean
stab_float_type (void *p, unsigned int size)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
if (size > 0
&& size - 1 < (sizeof info->type_cache.float_types
/ sizeof info->type_cache.float_types[0])
&& info->type_cache.float_types[size - 1] != 0)
return stab_push_defined_type (info,
info->type_cache.float_types[size - 1],
size);
else
{
long tindex;
char *int_type;
char buf[50];
 
/* Floats are defined as a subrange of int. */
if (! stab_int_type (info, 4, FALSE))
return FALSE;
int_type = stab_pop_type (info);
 
tindex = info->type_index;
++info->type_index;
 
if (size > 0
&& size - 1 < (sizeof info->type_cache.float_types
/ sizeof info->type_cache.float_types[0]))
info->type_cache.float_types[size - 1] = tindex;
 
sprintf (buf, "%ld=r%s;%u;0;", tindex, int_type, size);
 
free (int_type);
 
return stab_push_string (info, buf, tindex, TRUE, size);
}
}
 
/* Push a complex type. */
 
static bfd_boolean
stab_complex_type (void *p, unsigned int size)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
char buf[50];
long tindex;
 
tindex = info->type_index;
++info->type_index;
 
sprintf (buf, "%ld=r%ld;%u;0;", tindex, tindex, size);
 
return stab_push_string (info, buf, tindex, TRUE, size * 2);
}
 
/* Push a bfd_boolean type. We use an XCOFF predefined type, since gdb
always recognizes them. */
 
static bfd_boolean
stab_bool_type (void *p, unsigned int size)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
long tindex;
 
switch (size)
{
case 1:
tindex = -21;
break;
 
case 2:
tindex = -22;
break;
 
default:
case 4:
tindex = -16;
break;
 
case 8:
tindex = -33;
break;
}
 
return stab_push_defined_type (info, tindex, size);
}
 
/* Push an enum type. */
 
static bfd_boolean
stab_enum_type (void *p, const char *tag, const char **names,
bfd_signed_vma *vals)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
size_t len;
const char **pn;
char *buf;
long tindex = 0;
bfd_signed_vma *pv;
 
if (names == NULL)
{
assert (tag != NULL);
 
buf = (char *) xmalloc (10 + strlen (tag));
sprintf (buf, "xe%s:", tag);
/* FIXME: The size is just a guess. */
if (! stab_push_string (info, buf, 0, FALSE, 4))
return FALSE;
free (buf);
return TRUE;
}
 
len = 10;
if (tag != NULL)
len += strlen (tag);
for (pn = names; *pn != NULL; pn++)
len += strlen (*pn) + 20;
 
buf = (char *) xmalloc (len);
 
if (tag == NULL)
strcpy (buf, "e");
else
{
tindex = info->type_index;
++info->type_index;
sprintf (buf, "%s:T%ld=e", tag, tindex);
}
 
for (pn = names, pv = vals; *pn != NULL; pn++, pv++)
sprintf (buf + strlen (buf), "%s:%ld,", *pn, (long) *pv);
strcat (buf, ";");
 
if (tag == NULL)
{
/* FIXME: The size is just a guess. */
if (! stab_push_string (info, buf, 0, FALSE, 4))
return FALSE;
}
else
{
/* FIXME: The size is just a guess. */
if (! stab_write_symbol (info, N_LSYM, 0, 0, buf)
|| ! stab_push_defined_type (info, tindex, 4))
return FALSE;
}
 
free (buf);
 
return TRUE;
}
 
/* Push a modification of the top type on the stack. Cache the
results in CACHE and CACHE_ALLOC. */
 
static bfd_boolean
stab_modify_type (struct stab_write_handle *info, int mod,
unsigned int size, long **cache, size_t *cache_alloc)
{
long targindex;
long tindex;
char *s, *buf;
 
assert (info->type_stack != NULL);
targindex = info->type_stack->index;
 
if (targindex <= 0
|| cache == NULL)
{
bfd_boolean definition;
 
/* Either the target type has no index, or we aren't caching
this modifier. Either way we have no way of recording the
new type, so we don't bother to define one. */
definition = info->type_stack->definition;
s = stab_pop_type (info);
buf = (char *) xmalloc (strlen (s) + 2);
sprintf (buf, "%c%s", mod, s);
free (s);
if (! stab_push_string (info, buf, 0, definition, size))
return FALSE;
free (buf);
}
else
{
if ((size_t) targindex >= *cache_alloc)
{
size_t alloc;
 
alloc = *cache_alloc;
if (alloc == 0)
alloc = 10;
while ((size_t) targindex >= alloc)
alloc *= 2;
*cache = (long *) xrealloc (*cache, alloc * sizeof (long));
memset (*cache + *cache_alloc, 0,
(alloc - *cache_alloc) * sizeof (long));
*cache_alloc = alloc;
}
 
tindex = (*cache)[targindex];
if (tindex != 0 && ! info->type_stack->definition)
{
/* We have already defined a modification of this type, and
the entry on the type stack is not a definition, so we
can safely discard it (we may have a definition on the
stack, even if we already defined a modification, if it
is a struct which we did not define at the time it was
referenced). */
free (stab_pop_type (info));
if (! stab_push_defined_type (info, tindex, size))
return FALSE;
}
else
{
tindex = info->type_index;
++info->type_index;
 
s = stab_pop_type (info);
buf = (char *) xmalloc (strlen (s) + 20);
sprintf (buf, "%ld=%c%s", tindex, mod, s);
free (s);
 
(*cache)[targindex] = tindex;
 
if (! stab_push_string (info, buf, tindex, TRUE, size))
return FALSE;
 
free (buf);
}
}
 
return TRUE;
}
 
/* Push a pointer type. */
 
static bfd_boolean
stab_pointer_type (void *p)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
/* FIXME: The size should depend upon the architecture. */
return stab_modify_type (info, '*', 4, &info->type_cache.pointer_types,
&info->type_cache.pointer_types_alloc);
}
 
/* Push a function type. */
 
static bfd_boolean
stab_function_type (void *p, int argcount,
bfd_boolean varargs ATTRIBUTE_UNUSED)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
int i;
 
/* We have no way to represent the argument types, so we just
discard them. However, if they define new types, we must output
them. We do this by producing empty typedefs. */
for (i = 0; i < argcount; i++)
{
if (! info->type_stack->definition)
free (stab_pop_type (info));
else
{
char *s, *buf;
 
s = stab_pop_type (info);
 
buf = (char *) xmalloc (strlen (s) + 3);
sprintf (buf, ":t%s", s);
free (s);
 
if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
return FALSE;
 
free (buf);
}
}
 
return stab_modify_type (info, 'f', 0, &info->type_cache.function_types,
&info->type_cache.function_types_alloc);
}
 
/* Push a reference type. */
 
static bfd_boolean
stab_reference_type (void *p)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
/* FIXME: The size should depend upon the architecture. */
return stab_modify_type (info, '&', 4, &info->type_cache.reference_types,
&info->type_cache.reference_types_alloc);
}
 
/* Push a range type. */
 
static bfd_boolean
stab_range_type (void *p, bfd_signed_vma low, bfd_signed_vma high)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
bfd_boolean definition;
unsigned int size;
char *s, *buf;
 
definition = info->type_stack->definition;
size = info->type_stack->size;
 
s = stab_pop_type (info);
buf = (char *) xmalloc (strlen (s) + 100);
sprintf (buf, "r%s;%ld;%ld;", s, (long) low, (long) high);
free (s);
 
if (! stab_push_string (info, buf, 0, definition, size))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Push an array type. */
 
static bfd_boolean
stab_array_type (void *p, bfd_signed_vma low, bfd_signed_vma high,
bfd_boolean stringp)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
bfd_boolean definition;
unsigned int element_size;
char *range, *element, *buf;
long tindex;
unsigned int size;
 
definition = info->type_stack->definition;
range = stab_pop_type (info);
 
definition = definition || info->type_stack->definition;
element_size = info->type_stack->size;
element = stab_pop_type (info);
 
buf = (char *) xmalloc (strlen (range) + strlen (element) + 100);
 
if (! stringp)
{
tindex = 0;
*buf = '\0';
}
else
{
/* We need to define a type in order to include the string
attribute. */
tindex = info->type_index;
++info->type_index;
definition = TRUE;
sprintf (buf, "%ld=@S;", tindex);
}
 
sprintf (buf + strlen (buf), "ar%s;%ld;%ld;%s",
range, (long) low, (long) high, element);
free (range);
free (element);
 
if (high < low)
size = 0;
else
size = element_size * ((high - low) + 1);
if (! stab_push_string (info, buf, tindex, definition, size))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Push a set type. */
 
static bfd_boolean
stab_set_type (void *p, bfd_boolean bitstringp)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
bfd_boolean definition;
char *s, *buf;
long tindex;
 
definition = info->type_stack->definition;
 
s = stab_pop_type (info);
buf = (char *) xmalloc (strlen (s) + 30);
 
if (! bitstringp)
{
*buf = '\0';
tindex = 0;
}
else
{
/* We need to define a type in order to include the string
attribute. */
tindex = info->type_index;
++info->type_index;
definition = TRUE;
sprintf (buf, "%ld=@S;", tindex);
}
 
sprintf (buf + strlen (buf), "S%s", s);
free (s);
 
if (! stab_push_string (info, buf, tindex, definition, 0))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Push an offset type. */
 
static bfd_boolean
stab_offset_type (void *p)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
bfd_boolean definition;
char *target, *base, *buf;
 
definition = info->type_stack->definition;
target = stab_pop_type (info);
 
definition = definition || info->type_stack->definition;
base = stab_pop_type (info);
 
buf = (char *) xmalloc (strlen (target) + strlen (base) + 3);
sprintf (buf, "@%s,%s", base, target);
free (base);
free (target);
 
if (! stab_push_string (info, buf, 0, definition, 0))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Push a method type. */
 
static bfd_boolean
stab_method_type (void *p, bfd_boolean domainp, int argcount,
bfd_boolean varargs)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
bfd_boolean definition;
char *domain, *return_type, *buf;
char **args;
int i;
size_t len;
 
/* We don't bother with stub method types, because that would
require a mangler for C++ argument types. This will waste space
in the debugging output. */
 
/* We need a domain. I'm not sure DOMAINP can ever be false,
anyhow. */
if (! domainp)
{
if (! stab_empty_type (p))
return FALSE;
}
 
definition = info->type_stack->definition;
domain = stab_pop_type (info);
 
/* A non-varargs function is indicated by making the last parameter
type be void. */
 
if (argcount < 0)
{
args = NULL;
argcount = 0;
}
else if (argcount == 0)
{
if (varargs)
args = NULL;
else
{
args = (char **) xmalloc (1 * sizeof (*args));
if (! stab_empty_type (p))
return FALSE;
definition = definition || info->type_stack->definition;
args[0] = stab_pop_type (info);
argcount = 1;
}
}
else
{
args = (char **) xmalloc ((argcount + 1) * sizeof (*args));
for (i = argcount - 1; i >= 0; i--)
{
definition = definition || info->type_stack->definition;
args[i] = stab_pop_type (info);
}
if (! varargs)
{
if (! stab_empty_type (p))
return FALSE;
definition = definition || info->type_stack->definition;
args[argcount] = stab_pop_type (info);
++argcount;
}
}
 
definition = definition || info->type_stack->definition;
return_type = stab_pop_type (info);
 
len = strlen (domain) + strlen (return_type) + 10;
for (i = 0; i < argcount; i++)
len += strlen (args[i]);
 
buf = (char *) xmalloc (len);
 
sprintf (buf, "#%s,%s", domain, return_type);
free (domain);
free (return_type);
for (i = 0; i < argcount; i++)
{
strcat (buf, ",");
strcat (buf, args[i]);
free (args[i]);
}
strcat (buf, ";");
 
if (args != NULL)
free (args);
 
if (! stab_push_string (info, buf, 0, definition, 0))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Push a const version of a type. */
 
static bfd_boolean
stab_const_type (void *p)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
return stab_modify_type (info, 'k', info->type_stack->size,
(long **) NULL, (size_t *) NULL);
}
 
/* Push a volatile version of a type. */
 
static bfd_boolean
stab_volatile_type (void *p)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
return stab_modify_type (info, 'B', info->type_stack->size,
(long **) NULL, (size_t *) NULL);
}
 
/* Get the type index to use for a struct/union/class ID. This should
return -1 if it fails. */
 
static long
stab_get_struct_index (struct stab_write_handle *info, const char *tag,
unsigned int id, enum debug_type_kind kind,
unsigned int *psize)
{
if (id >= info->type_cache.struct_types_alloc)
{
size_t alloc;
 
alloc = info->type_cache.struct_types_alloc;
if (alloc == 0)
alloc = 10;
while (id >= alloc)
alloc *= 2;
info->type_cache.struct_types =
(struct stab_tag *) xrealloc (info->type_cache.struct_types,
alloc * sizeof (struct stab_tag));
memset ((info->type_cache.struct_types
+ info->type_cache.struct_types_alloc),
0,
((alloc - info->type_cache.struct_types_alloc)
* sizeof (struct stab_tag)));
info->type_cache.struct_types_alloc = alloc;
}
 
if (info->type_cache.struct_types[id].index == 0)
{
info->type_cache.struct_types[id].index = info->type_index;
++info->type_index;
info->type_cache.struct_types[id].tag = tag;
info->type_cache.struct_types[id].kind = kind;
}
 
if (kind == DEBUG_KIND_ILLEGAL)
{
/* This is a definition of the struct. */
info->type_cache.struct_types[id].kind = kind;
info->type_cache.struct_types[id].size = *psize;
}
else
*psize = info->type_cache.struct_types[id].size;
 
return info->type_cache.struct_types[id].index;
}
 
/* Start outputting a struct. We ignore the tag, and handle it in
stab_tag. */
 
static bfd_boolean
stab_start_struct_type (void *p, const char *tag, unsigned int id,
bfd_boolean structp, unsigned int size)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
long tindex;
bfd_boolean definition;
char buf[40];
 
if (id == 0)
{
tindex = 0;
*buf = '\0';
definition = FALSE;
}
else
{
tindex = stab_get_struct_index (info, tag, id, DEBUG_KIND_ILLEGAL,
&size);
if (tindex < 0)
return FALSE;
sprintf (buf, "%ld=", tindex);
definition = TRUE;
}
 
sprintf (buf + strlen (buf), "%c%u",
structp ? 's' : 'u',
size);
 
if (! stab_push_string (info, buf, tindex, definition, size))
return FALSE;
 
info->type_stack->fields = (char *) xmalloc (1);
info->type_stack->fields[0] = '\0';
 
return TRUE;
}
 
/* Add a field to a struct. */
 
static bfd_boolean
stab_struct_field (void *p, const char *name, bfd_vma bitpos,
bfd_vma bitsize, enum debug_visibility visibility)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
bfd_boolean definition;
unsigned int size;
char *s, *n;
const char *vis;
 
definition = info->type_stack->definition;
size = info->type_stack->size;
s = stab_pop_type (info);
 
/* Add this field to the end of the current struct fields, which is
currently on the top of the stack. */
 
assert (info->type_stack->fields != NULL);
n = (char *) xmalloc (strlen (info->type_stack->fields)
+ strlen (name)
+ strlen (s)
+ 50);
 
switch (visibility)
{
default:
abort ();
 
case DEBUG_VISIBILITY_PUBLIC:
vis = "";
break;
 
case DEBUG_VISIBILITY_PRIVATE:
vis = "/0";
break;
 
case DEBUG_VISIBILITY_PROTECTED:
vis = "/1";
break;
}
 
if (bitsize == 0)
{
bitsize = size * 8;
if (bitsize == 0)
non_fatal (_("%s: warning: unknown size for field `%s' in struct"),
bfd_get_filename (info->abfd), name);
}
 
sprintf (n, "%s%s:%s%s,%ld,%ld;", info->type_stack->fields, name, vis, s,
(long) bitpos, (long) bitsize);
 
free (info->type_stack->fields);
info->type_stack->fields = n;
 
if (definition)
info->type_stack->definition = TRUE;
 
return TRUE;
}
 
/* Finish up a struct. */
 
static bfd_boolean
stab_end_struct_type (void *p)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
bfd_boolean definition;
long tindex;
unsigned int size;
char *fields, *first, *buf;
 
assert (info->type_stack != NULL && info->type_stack->fields != NULL);
 
definition = info->type_stack->definition;
tindex = info->type_stack->index;
size = info->type_stack->size;
fields = info->type_stack->fields;
first = stab_pop_type (info);
 
buf = (char *) xmalloc (strlen (first) + strlen (fields) + 2);
sprintf (buf, "%s%s;", first, fields);
free (first);
free (fields);
 
if (! stab_push_string (info, buf, tindex, definition, size))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Start outputting a class. */
 
static bfd_boolean
stab_start_class_type (void *p, const char *tag, unsigned int id, bfd_boolean structp, unsigned int size, bfd_boolean vptr, bfd_boolean ownvptr)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
bfd_boolean definition;
char *vstring;
 
if (! vptr || ownvptr)
{
definition = FALSE;
vstring = NULL;
}
else
{
definition = info->type_stack->definition;
vstring = stab_pop_type (info);
}
 
if (! stab_start_struct_type (p, tag, id, structp, size))
return FALSE;
 
if (vptr)
{
char *vtable;
 
if (ownvptr)
{
assert (info->type_stack->index > 0);
vtable = (char *) xmalloc (20);
sprintf (vtable, "~%%%ld", info->type_stack->index);
}
else
{
vtable = (char *) xmalloc (strlen (vstring) + 3);
sprintf (vtable, "~%%%s", vstring);
free (vstring);
}
 
info->type_stack->vtable = vtable;
}
 
if (definition)
info->type_stack->definition = TRUE;
 
return TRUE;
}
 
/* Add a static member to the class on the type stack. */
 
static bfd_boolean
stab_class_static_member (void *p, const char *name, const char *physname,
enum debug_visibility visibility)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
bfd_boolean definition;
char *s, *n;
const char *vis;
 
definition = info->type_stack->definition;
s = stab_pop_type (info);
 
/* Add this field to the end of the current struct fields, which is
currently on the top of the stack. */
 
assert (info->type_stack->fields != NULL);
n = (char *) xmalloc (strlen (info->type_stack->fields)
+ strlen (name)
+ strlen (s)
+ strlen (physname)
+ 10);
 
switch (visibility)
{
default:
abort ();
 
case DEBUG_VISIBILITY_PUBLIC:
vis = "";
break;
 
case DEBUG_VISIBILITY_PRIVATE:
vis = "/0";
break;
 
case DEBUG_VISIBILITY_PROTECTED:
vis = "/1";
break;
}
 
sprintf (n, "%s%s:%s%s:%s;", info->type_stack->fields, name, vis, s,
physname);
 
free (info->type_stack->fields);
info->type_stack->fields = n;
 
if (definition)
info->type_stack->definition = TRUE;
 
return TRUE;
}
 
/* Add a base class to the class on the type stack. */
 
static bfd_boolean
stab_class_baseclass (void *p, bfd_vma bitpos, bfd_boolean is_virtual,
enum debug_visibility visibility)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
bfd_boolean definition;
char *s;
char *buf;
unsigned int c;
char **baseclasses;
 
definition = info->type_stack->definition;
s = stab_pop_type (info);
 
/* Build the base class specifier. */
 
buf = (char *) xmalloc (strlen (s) + 25);
buf[0] = is_virtual ? '1' : '0';
switch (visibility)
{
default:
abort ();
 
case DEBUG_VISIBILITY_PRIVATE:
buf[1] = '0';
break;
 
case DEBUG_VISIBILITY_PROTECTED:
buf[1] = '1';
break;
 
case DEBUG_VISIBILITY_PUBLIC:
buf[1] = '2';
break;
}
 
sprintf (buf + 2, "%ld,%s;", (long) bitpos, s);
free (s);
 
/* Add the new baseclass to the existing ones. */
 
assert (info->type_stack != NULL && info->type_stack->fields != NULL);
 
if (info->type_stack->baseclasses == NULL)
c = 0;
else
{
c = 0;
while (info->type_stack->baseclasses[c] != NULL)
++c;
}
 
baseclasses = (char **) xrealloc (info->type_stack->baseclasses,
(c + 2) * sizeof (*baseclasses));
baseclasses[c] = buf;
baseclasses[c + 1] = NULL;
 
info->type_stack->baseclasses = baseclasses;
 
if (definition)
info->type_stack->definition = TRUE;
 
return TRUE;
}
 
/* Start adding a method to the class on the type stack. */
 
static bfd_boolean
stab_class_start_method (void *p, const char *name)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
char *m;
 
assert (info->type_stack != NULL && info->type_stack->fields != NULL);
 
if (info->type_stack->methods == NULL)
{
m = (char *) xmalloc (strlen (name) + 3);
*m = '\0';
}
else
{
m = (char *) xrealloc (info->type_stack->methods,
(strlen (info->type_stack->methods)
+ strlen (name)
+ 4));
}
 
sprintf (m + strlen (m), "%s::", name);
 
info->type_stack->methods = m;
 
return TRUE;
}
 
/* Add a variant, either static or not, to the current method. */
 
static bfd_boolean
stab_class_method_var (struct stab_write_handle *info, const char *physname,
enum debug_visibility visibility,
bfd_boolean staticp, bfd_boolean constp,
bfd_boolean volatilep, bfd_vma voffset,
bfd_boolean contextp)
{
bfd_boolean definition;
char *type;
char *context = NULL;
char visc, qualc, typec;
 
definition = info->type_stack->definition;
type = stab_pop_type (info);
 
if (contextp)
{
definition = definition || info->type_stack->definition;
context = stab_pop_type (info);
}
 
assert (info->type_stack != NULL && info->type_stack->methods != NULL);
 
switch (visibility)
{
default:
abort ();
 
case DEBUG_VISIBILITY_PRIVATE:
visc = '0';
break;
 
case DEBUG_VISIBILITY_PROTECTED:
visc = '1';
break;
 
case DEBUG_VISIBILITY_PUBLIC:
visc = '2';
break;
}
 
if (constp)
{
if (volatilep)
qualc = 'D';
else
qualc = 'B';
}
else
{
if (volatilep)
qualc = 'C';
else
qualc = 'A';
}
 
if (staticp)
typec = '?';
else if (! contextp)
typec = '.';
else
typec = '*';
 
info->type_stack->methods =
(char *) xrealloc (info->type_stack->methods,
(strlen (info->type_stack->methods)
+ strlen (type)
+ strlen (physname)
+ (contextp ? strlen (context) : 0)
+ 40));
 
sprintf (info->type_stack->methods + strlen (info->type_stack->methods),
"%s:%s;%c%c%c", type, physname, visc, qualc, typec);
free (type);
 
if (contextp)
{
sprintf (info->type_stack->methods + strlen (info->type_stack->methods),
"%ld;%s;", (long) voffset, context);
free (context);
}
 
if (definition)
info->type_stack->definition = TRUE;
 
return TRUE;
}
 
/* Add a variant to the current method. */
 
static bfd_boolean
stab_class_method_variant (void *p, const char *physname,
enum debug_visibility visibility,
bfd_boolean constp, bfd_boolean volatilep,
bfd_vma voffset, bfd_boolean contextp)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
return stab_class_method_var (info, physname, visibility, FALSE, constp,
volatilep, voffset, contextp);
}
 
/* Add a static variant to the current method. */
 
static bfd_boolean
stab_class_static_method_variant (void *p, const char *physname,
enum debug_visibility visibility,
bfd_boolean constp, bfd_boolean volatilep)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
return stab_class_method_var (info, physname, visibility, TRUE, constp,
volatilep, 0, FALSE);
}
 
/* Finish up a method. */
 
static bfd_boolean
stab_class_end_method (void *p)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
assert (info->type_stack != NULL && info->type_stack->methods != NULL);
 
/* We allocated enough room on info->type_stack->methods to add the
trailing semicolon. */
strcat (info->type_stack->methods, ";");
 
return TRUE;
}
 
/* Finish up a class. */
 
static bfd_boolean
stab_end_class_type (void *p)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
size_t len;
unsigned int i = 0;
char *buf;
 
assert (info->type_stack != NULL && info->type_stack->fields != NULL);
 
/* Work out the size we need to allocate for the class definition. */
 
len = (strlen (info->type_stack->string)
+ strlen (info->type_stack->fields)
+ 10);
if (info->type_stack->baseclasses != NULL)
{
len += 20;
for (i = 0; info->type_stack->baseclasses[i] != NULL; i++)
len += strlen (info->type_stack->baseclasses[i]);
}
if (info->type_stack->methods != NULL)
len += strlen (info->type_stack->methods);
if (info->type_stack->vtable != NULL)
len += strlen (info->type_stack->vtable);
 
/* Build the class definition. */
 
buf = (char *) xmalloc (len);
 
strcpy (buf, info->type_stack->string);
 
if (info->type_stack->baseclasses != NULL)
{
sprintf (buf + strlen (buf), "!%u,", i);
for (i = 0; info->type_stack->baseclasses[i] != NULL; i++)
{
strcat (buf, info->type_stack->baseclasses[i]);
free (info->type_stack->baseclasses[i]);
}
free (info->type_stack->baseclasses);
info->type_stack->baseclasses = NULL;
}
 
strcat (buf, info->type_stack->fields);
free (info->type_stack->fields);
info->type_stack->fields = NULL;
 
if (info->type_stack->methods != NULL)
{
strcat (buf, info->type_stack->methods);
free (info->type_stack->methods);
info->type_stack->methods = NULL;
}
 
strcat (buf, ";");
 
if (info->type_stack->vtable != NULL)
{
strcat (buf, info->type_stack->vtable);
free (info->type_stack->vtable);
info->type_stack->vtable = NULL;
}
 
/* Replace the string on the top of the stack with the complete
class definition. */
free (info->type_stack->string);
info->type_stack->string = buf;
 
return TRUE;
}
 
/* Push a typedef which was previously defined. */
 
static bfd_boolean
stab_typedef_type (void *p, const char *name)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
struct string_hash_entry *h;
 
h = string_hash_lookup (&info->typedef_hash, name, FALSE, FALSE);
assert (h != NULL && h->index > 0);
 
return stab_push_defined_type (info, h->index, h->size);
}
 
/* Push a struct, union or class tag. */
 
static bfd_boolean
stab_tag_type (void *p, const char *name, unsigned int id,
enum debug_type_kind kind)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
long tindex;
unsigned int size = 0;
 
tindex = stab_get_struct_index (info, name, id, kind, &size);
if (tindex < 0)
return FALSE;
 
return stab_push_defined_type (info, tindex, size);
}
 
/* Define a typedef. */
 
static bfd_boolean
stab_typdef (void *p, const char *name)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
long tindex;
unsigned int size;
char *s, *buf;
struct string_hash_entry *h;
 
tindex = info->type_stack->index;
size = info->type_stack->size;
s = stab_pop_type (info);
 
buf = (char *) xmalloc (strlen (name) + strlen (s) + 20);
 
if (tindex > 0)
sprintf (buf, "%s:t%s", name, s);
else
{
tindex = info->type_index;
++info->type_index;
sprintf (buf, "%s:t%ld=%s", name, tindex, s);
}
 
free (s);
 
if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
return FALSE;
 
free (buf);
 
h = string_hash_lookup (&info->typedef_hash, name, TRUE, FALSE);
if (h == NULL)
{
non_fatal (_("string_hash_lookup failed: %s"),
bfd_errmsg (bfd_get_error ()));
return FALSE;
}
 
/* I don't think we care about redefinitions. */
 
h->index = tindex;
h->size = size;
 
return TRUE;
}
 
/* Define a tag. */
 
static bfd_boolean
stab_tag (void *p, const char *tag)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
char *s, *buf;
 
s = stab_pop_type (info);
 
buf = (char *) xmalloc (strlen (tag) + strlen (s) + 3);
 
sprintf (buf, "%s:T%s", tag, s);
free (s);
 
if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Define an integer constant. */
 
static bfd_boolean
stab_int_constant (void *p, const char *name, bfd_vma val)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
char *buf;
 
buf = (char *) xmalloc (strlen (name) + 20);
sprintf (buf, "%s:c=i%ld", name, (long) val);
 
if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Define a floating point constant. */
 
static bfd_boolean
stab_float_constant (void *p, const char *name, double val)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
char *buf;
 
buf = (char *) xmalloc (strlen (name) + 20);
sprintf (buf, "%s:c=f%g", name, val);
 
if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Define a typed constant. */
 
static bfd_boolean
stab_typed_constant (void *p, const char *name, bfd_vma val)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
char *s, *buf;
 
s = stab_pop_type (info);
 
buf = (char *) xmalloc (strlen (name) + strlen (s) + 20);
sprintf (buf, "%s:c=e%s,%ld", name, s, (long) val);
free (s);
 
if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Record a variable. */
 
static bfd_boolean
stab_variable (void *p, const char *name, enum debug_var_kind kind,
bfd_vma val)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
char *s, *buf;
int stab_type;
const char *kindstr;
 
s = stab_pop_type (info);
 
switch (kind)
{
default:
abort ();
 
case DEBUG_GLOBAL:
stab_type = N_GSYM;
kindstr = "G";
break;
 
case DEBUG_STATIC:
stab_type = N_STSYM;
kindstr = "S";
break;
 
case DEBUG_LOCAL_STATIC:
stab_type = N_STSYM;
kindstr = "V";
break;
 
case DEBUG_LOCAL:
stab_type = N_LSYM;
kindstr = "";
 
/* Make sure that this is a type reference or definition. */
if (! ISDIGIT (*s))
{
char *n;
long tindex;
 
tindex = info->type_index;
++info->type_index;
n = (char *) xmalloc (strlen (s) + 20);
sprintf (n, "%ld=%s", tindex, s);
free (s);
s = n;
}
break;
 
case DEBUG_REGISTER:
stab_type = N_RSYM;
kindstr = "r";
break;
}
 
buf = (char *) xmalloc (strlen (name) + strlen (s) + 3);
sprintf (buf, "%s:%s%s", name, kindstr, s);
free (s);
 
if (! stab_write_symbol (info, stab_type, 0, val, buf))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Start outputting a function. */
 
static bfd_boolean
stab_start_function (void *p, const char *name, bfd_boolean globalp)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
char *rettype, *buf;
 
assert (info->nesting == 0 && info->fun_offset == -1);
 
rettype = stab_pop_type (info);
 
buf = (char *) xmalloc (strlen (name) + strlen (rettype) + 3);
sprintf (buf, "%s:%c%s", name,
globalp ? 'F' : 'f',
rettype);
 
/* We don't know the value now, so we set it in start_block. */
info->fun_offset = info->symbols_size;
 
if (! stab_write_symbol (info, N_FUN, 0, 0, buf))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Output a function parameter. */
 
static bfd_boolean
stab_function_parameter (void *p, const char *name, enum debug_parm_kind kind, bfd_vma val)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
char *s, *buf;
int stab_type;
char kindc;
 
s = stab_pop_type (info);
 
switch (kind)
{
default:
abort ();
 
case DEBUG_PARM_STACK:
stab_type = N_PSYM;
kindc = 'p';
break;
 
case DEBUG_PARM_REG:
stab_type = N_RSYM;
kindc = 'P';
break;
 
case DEBUG_PARM_REFERENCE:
stab_type = N_PSYM;
kindc = 'v';
break;
 
case DEBUG_PARM_REF_REG:
stab_type = N_RSYM;
kindc = 'a';
break;
}
 
buf = (char *) xmalloc (strlen (name) + strlen (s) + 3);
sprintf (buf, "%s:%c%s", name, kindc, s);
free (s);
 
if (! stab_write_symbol (info, stab_type, 0, val, buf))
return FALSE;
 
free (buf);
 
return TRUE;
}
 
/* Start a block. */
 
static bfd_boolean
stab_start_block (void *p, bfd_vma addr)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
/* Fill in any slots which have been waiting for the first known
text address. */
 
if (info->so_offset != -1)
{
bfd_put_32 (info->abfd, addr, info->symbols + info->so_offset + 8);
info->so_offset = -1;
}
 
if (info->fun_offset != -1)
{
bfd_put_32 (info->abfd, addr, info->symbols + info->fun_offset + 8);
info->fun_offset = -1;
}
 
++info->nesting;
 
/* We will be called with a top level block surrounding the
function, but stabs information does not output that block, so we
ignore it. */
 
if (info->nesting == 1)
{
info->fnaddr = addr;
return TRUE;
}
 
/* We have to output the LBRAC symbol after any variables which are
declared inside the block. We postpone the LBRAC until the next
start_block or end_block. */
 
/* If we have postponed an LBRAC, output it now. */
if (info->pending_lbrac != (bfd_vma) -1)
{
if (! stab_write_symbol (info, N_LBRAC, 0, info->pending_lbrac,
(const char *) NULL))
return FALSE;
}
 
/* Remember the address and output it later. */
 
info->pending_lbrac = addr - info->fnaddr;
 
return TRUE;
}
 
/* End a block. */
 
static bfd_boolean
stab_end_block (void *p, bfd_vma addr)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
if (addr > info->last_text_address)
info->last_text_address = addr;
 
/* If we have postponed an LBRAC, output it now. */
if (info->pending_lbrac != (bfd_vma) -1)
{
if (! stab_write_symbol (info, N_LBRAC, 0, info->pending_lbrac,
(const char *) NULL))
return FALSE;
info->pending_lbrac = (bfd_vma) -1;
}
 
assert (info->nesting > 0);
 
--info->nesting;
 
/* We ignore the outermost block. */
if (info->nesting == 0)
return TRUE;
 
return stab_write_symbol (info, N_RBRAC, 0, addr - info->fnaddr,
(const char *) NULL);
}
 
/* End a function. */
 
static bfd_boolean
stab_end_function (void *p ATTRIBUTE_UNUSED)
{
return TRUE;
}
 
/* Output a line number. */
 
static bfd_boolean
stab_lineno (void *p, const char *file, unsigned long lineno, bfd_vma addr)
{
struct stab_write_handle *info = (struct stab_write_handle *) p;
 
assert (info->lineno_filename != NULL);
 
if (addr > info->last_text_address)
info->last_text_address = addr;
 
if (filename_cmp (file, info->lineno_filename) != 0)
{
if (! stab_write_symbol (info, N_SOL, 0, addr, file))
return FALSE;
info->lineno_filename = file;
}
 
return stab_write_symbol (info, N_SLINE, lineno, addr - info->fnaddr,
(const char *) NULL);
}
/contrib/toolchain/binutils/ld/ldlex.c
4275,8 → 4275,8
if (yyin)
{
result = fread (buf, 1, max_size, yyin);
// if (result < max_size && ferror (yyin))
// einfo ("%F%P: read in flex scanner failed\n");
if (result < max_size && ferror (yyin))
einfo ("%F%P: read in flex scanner failed\n");
}
}
return result;
/contrib/toolchain/binutils/libiberty/Makefile
16,7 → 16,7
fopen_unlocked.c getopt.c getopt1.c getpwd.c \
getruntime.c hashtab.c hex.c index.c insque.c \
lbasename.c lrealpath.c make-relative-prefix.c \
make-temp-file.c md5.c memmem.c mempcpy.c mkstemps.c \
make-temp-file.c md5.c memmem.c mempcpy.c \
objalloc.c obstack.c partition.c physmem.c random.c \
regex.c rindex.c safe-ctype.c setenv.c setproctitle.c \
sha1.c sigsetmask.c simple-object.c simple-object-coff.c\
/contrib/toolchain/binutils/libiberty/config.h
165,7 → 165,7
#define HAVE_MEMSET 1
 
/* Define to 1 if you have the `mkstemps' function. */
/* #undef HAVE_MKSTEMPS */
#define HAVE_MKSTEMPS 1
 
/* Define to 1 if you have a working `mmap' system call. */
/* #undef HAVE_MMAP */
/contrib/toolchain/binutils/libiberty/make-temp-file.c
89,7 → 89,7
 
#endif
 
static char *memoized_tmpdir;
//static char *memoized_tmpdir;
 
/*
 
105,70 → 105,9
char *
choose_tmpdir (void)
{
if (!memoized_tmpdir)
{
#if !defined(_WIN32) || defined(__CYGWIN__)
const char *base = 0;
char *tmpdir;
unsigned int len;
#ifdef VMS
/* Try VMS standard temp logical. */
base = try_dir ("/sys$scratch", base);
#else
base = try_dir (getenv ("TMPDIR"), base);
base = try_dir (getenv ("TMP"), base);
base = try_dir (getenv ("TEMP"), base);
#endif
#ifdef P_tmpdir
/* We really want a directory name here as if concatenated with say \dir
we do not end up with a double \\ which defines an UNC path. */
if (strcmp (P_tmpdir, "\\") == 0)
base = try_dir ("\\.", base);
else
base = try_dir (P_tmpdir, base);
#endif
 
/* Try /var/tmp, /usr/tmp, then /tmp. */
base = try_dir (vartmp, base);
base = try_dir (usrtmp, base);
base = try_dir (tmp, base);
/* If all else fails, use the current directory! */
if (base == 0)
base = ".";
/* Append DIR_SEPARATOR to the directory we've chosen
and return it. */
len = strlen (base);
tmpdir = XNEWVEC (char, len + 2);
strcpy (tmpdir, base);
tmpdir[len] = DIR_SEPARATOR;
tmpdir[len+1] = '\0';
memoized_tmpdir = tmpdir;
#else /* defined(_WIN32) && !defined(__CYGWIN__) */
DWORD len;
 
/* Figure out how much space we need. */
len = GetTempPath(0, NULL);
if (len)
{
memoized_tmpdir = XNEWVEC (char, len);
if (!GetTempPath(len, memoized_tmpdir))
{
XDELETEVEC (memoized_tmpdir);
memoized_tmpdir = NULL;
return "/tmp0/1/";
}
}
if (!memoized_tmpdir)
/* If all else fails, use the current directory. */
memoized_tmpdir = xstrdup (".\\");
#endif /* defined(_WIN32) && !defined(__CYGWIN__) */
}
 
return memoized_tmpdir;
}
 
/*
 
@deftypefn Replacement char* make_temp_file (const char *@var{suffix})
/contrib/toolchain/binutils/libiberty/mkstemps.c
100,9 → 100,9
#ifdef HAVE_GETTIMEOFDAY
/* Get some more or less random data. */
gettimeofday (&tv, NULL);
value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; // ^ getpid ();
#else
value += getpid ();
value += 1;//getpid ();
#endif
 
for (count = 0; count < TMP_MAX; ++count)
/contrib/toolchain/binutils/libiberty/unlink-if-ordinary.c
64,9 → 64,9
{
struct stat st;
 
// if (lstat (name, &st) == 0
// && (S_ISREG (st.st_mode) || S_ISLNK (st.st_mode)))
// return unlink (name);
if (lstat (name, &st) == 0
&& (S_ISREG (st.st_mode) || S_ISLNK (st.st_mode)))
return unlink (name);
 
return 1;
}