aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binutils/ChangeLog9
-rw-r--r--binutils/NEWS3
-rw-r--r--binutils/budbg.h8
-rw-r--r--binutils/doc/binutils.texi8
-rw-r--r--binutils/objdump.c22
-rw-r--r--binutils/prdbg.c1062
6 files changed, 1098 insertions, 14 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 11a79ce..38b3b87 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,12 @@
+2003-07-22 Salvador Eduardo Tropea <set@computer.org>
+
+ * objdump.c: New command line option --debugging-tags.
+ * doc/binutils.texi: Document new command line option.
+ * prdbg.c: Code to print the debug info as tags compatible
+ with ctags.
+ * budbg.h: Adjust prototype.
+ * NEWS: Mention new switch
+
2003-07-18 Nick Clifton <nickc@redhat.com>
* objdump.c (main) :Accept multiple -M switch.
diff --git a/binutils/NEWS b/binutils/NEWS
index 4338946..0a8c0cf 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -1,5 +1,8 @@
-*- text -*-
+* objdump now accepts --debugging-tags to print the debug information in a
+ format compatible with ctags tool.
+
* objcopy and strip now accept --only-keep-debug to create a file containing
those sections that would be stripped out by --strip-debug. The idea is that
this can be used in conjunction with the --add-gnu-debuglink switch to create
diff --git a/binutils/budbg.h b/binutils/budbg.h
index dc68703..e4eee83 100644
--- a/binutils/budbg.h
+++ b/binutils/budbg.h
@@ -1,5 +1,5 @@
/* budbg.c -- Interfaces to the generic debugging information routines.
- Copyright 1995, 1996, 2002 Free Software Foundation, Inc.
+ Copyright 1995, 1996, 2002, 2003 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GNU Binutils.
@@ -26,13 +26,13 @@
/* Routine used to read generic debugging information. */
-extern PTR read_debugging_info
+extern PTR read_debugging_info
PARAMS ((bfd *, asymbol **, long));
-
+
/* Routine used to print generic debugging information. */
extern bfd_boolean print_debugging_info
- PARAMS ((FILE *, PTR));
+ (FILE *, void *, bfd *, asymbol **, void *, bfd_boolean);
/* Routines used to read and write stabs information. */
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 256acf0..f86169d 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -1435,6 +1435,7 @@ objdump [@option{-a}|@option{--archive-headers}]
[@option{-f}|@option{--file-headers}]
[@option{--file-start-context}]
[@option{-g}|@option{--debugging}]
+ [@option{-e}|@option{--debugging-tags}]
[@option{-h}|@option{--section-headers}|@option{--headers}]
[@option{-i}|@option{--info}]
[@option{-j} @var{section}|@option{--section=}@var{section}]
@@ -1480,7 +1481,7 @@ object files.
The long and short forms of options, shown here as alternatives, are
equivalent. At least one option from the list
-@option{-a,-d,-D,-f,-g,-G,-h,-H,-p,-r,-R,-S,-t,-T,-V,-x} must be given.
+@option{-a,-d,-D,-e,-f,-g,-G,-h,-H,-p,-r,-R,-S,-t,-T,-V,-x} must be given.
@table @env
@item -a
@@ -1536,6 +1537,11 @@ Only certain types of debugging information have been implemented.
Some other types are supported by @command{readelf -w}.
@xref{readelf}.
+@item -e
+@itemx --debugging-tags
+Like @option{-g}, but the information is generated in a format compatible
+with ctags tool.
+
@item -d
@itemx --disassemble
@cindex disassembling object code
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 47da66f..8011b58 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -74,6 +74,7 @@ static int wide_output; /* -w */
static bfd_vma start_address = (bfd_vma) -1; /* --start-address */
static bfd_vma stop_address = (bfd_vma) -1; /* --stop-address */
static int dump_debugging; /* --debugging */
+static int dump_debugging_tags; /* --debugging-tags */
static bfd_vma adjust_section_vma = 0; /* --adjust-vma */
static int file_start_context = 0; /* --file-start-context */
@@ -208,6 +209,7 @@ usage (stream, status)
-S, --source Intermix source code with disassembly\n\
-s, --full-contents Display the full contents of all sections requested\n\
-g, --debugging Display debug information in object file\n\
+ -e, --debugging-tags Display debug information using ctags style\n\
-G, --stabs Display (in raw form) any STABS info in the file\n\
-t, --syms Display the contents of the symbol table(s)\n\
-T, --dynamic-syms Display the contents of the dynamic symbol table\n\
@@ -266,6 +268,7 @@ static struct option long_options[]=
{"architecture", required_argument, NULL, 'm'},
{"archive-headers", no_argument, NULL, 'a'},
{"debugging", no_argument, NULL, 'g'},
+ {"debugging-tags", no_argument, NULL, 'e'},
{"demangle", optional_argument, NULL, 'C'},
{"disassemble", no_argument, NULL, 'd'},
{"disassemble-all", no_argument, NULL, 'D'},
@@ -2068,15 +2071,17 @@ dump_bfd (abfd)
}
}
- printf (_("\n%s: file format %s\n"), bfd_get_filename (abfd),
- abfd->xvec->name);
+ if (! dump_debugging_tags)
+ printf (_("\n%s: file format %s\n"), bfd_get_filename (abfd),
+ abfd->xvec->name);
if (dump_ar_hdrs)
print_arelt_descr (stdout, abfd, TRUE);
if (dump_file_header)
dump_bfd_header (abfd);
if (dump_private_headers)
dump_bfd_private_header (abfd);
- putchar ('\n');
+ if (! dump_debugging_tags)
+ putchar ('\n');
if (dump_section_headers)
dump_headers (abfd);
@@ -2106,7 +2111,8 @@ dump_bfd (abfd)
dhandle = read_debugging_info (abfd, syms, symcount);
if (dhandle != NULL)
{
- if (! print_debugging_info (stdout, dhandle))
+ if (! print_debugging_info (stdout, dhandle, abfd, syms, demangle,
+ dump_debugging_tags ? TRUE : FALSE))
{
non_fatal (_("%s: printing debugging information failed"),
bfd_get_filename (abfd));
@@ -2648,7 +2654,7 @@ main (argc, argv)
bfd_init ();
set_default_bfd_target ();
- while ((c = getopt_long (argc, argv, "pib:m:M:VvCdDlfaHhrRtTxsSj:wE:zgG",
+ while ((c = getopt_long (argc, argv, "pib:m:M:VvCdDlfaHhrRtTxsSj:wE:zgeG",
long_options, (int *) 0))
!= EOF)
{
@@ -2785,6 +2791,12 @@ main (argc, argv)
dump_debugging = 1;
seenflag = TRUE;
break;
+ case 'e':
+ dump_debugging = 1;
+ dump_debugging_tags = 1;
+ do_demangle = TRUE;
+ seenflag = TRUE;
+ break;
case 'G':
dump_stab_section_info = TRUE;
seenflag = TRUE;
diff --git a/binutils/prdbg.c b/binutils/prdbg.c
index b29eec6..33ba213 100644
--- a/binutils/prdbg.c
+++ b/binutils/prdbg.c
@@ -1,6 +1,7 @@
/* prdbg.c -- Print out generic debugging information.
- Copyright 1995, 1996, 2002 Free Software Foundation, Inc.
+ Copyright 1995, 1996, 2002, 2003 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
+ Tags style generation written by Salvador E. Tropea <set@computer.org>.
This file is part of GNU Binutils.
@@ -43,6 +44,15 @@ struct pr_handle
struct pr_stack *stack;
/* Parameter number we are about to output. */
int parameter;
+ /* The following are used only by the tags code (tg_). */
+ /* Name of the file we are using. */
+ char *filename;
+ /* The BFD. */
+ bfd *abfd;
+ /* The symbols table for this BFD. */
+ asymbol **syms;
+ /* Pointer to a function to demangle symbols. */
+ char *(*demangler) (bfd *, const char *);
};
/* The type stack. */
@@ -57,6 +67,13 @@ struct pr_stack
enum debug_visibility visibility;
/* Name of the current method we are handling. */
const char *method;
+ /* The following are used only by the tags code (tg_). */
+ /* Type for the container (struct, union, class, union class). */
+ const char *flavor;
+ /* A comma separated list of parent classes. */
+ char *parents;
+ /* How many parents contains parents. */
+ int num_parents;
};
static void indent
@@ -168,7 +185,40 @@ static bfd_boolean pr_end_function
PARAMS ((PTR));
static bfd_boolean pr_lineno
PARAMS ((PTR, const char *, unsigned long, bfd_vma));
-
+static bfd_boolean append_parent (struct pr_handle *, const char *);
+/* Only used by tg_ code. */
+static bfd_boolean tg_fix_visibility (struct pr_handle *, enum debug_visibility);
+static void find_address_in_section (bfd *, asection *, void *);
+static void translate_addresses (bfd *, char *, FILE *, asymbol **);
+static const char *visibility_name (enum debug_visibility);
+/* Tags style replacements. */
+static bfd_boolean tg_start_compilation_unit (void *, const char *);
+static bfd_boolean tg_start_source (void *, const char *);
+static bfd_boolean tg_enum_type (void *, const char *, const char **, bfd_signed_vma *);
+static bfd_boolean tg_start_struct_type (void *, const char *, unsigned int, bfd_boolean, unsigned int);
+static bfd_boolean pr_struct_field (void *, const char *, bfd_vma, bfd_vma, enum debug_visibility);
+static bfd_boolean tg_struct_field (void *, const char *, bfd_vma, bfd_vma, enum debug_visibility);
+static bfd_boolean tg_struct_field (void *, const char *, bfd_vma, bfd_vma, enum debug_visibility);
+static bfd_boolean tg_end_struct_type (void *);
+static bfd_boolean tg_start_class_type (void *, const char *, unsigned int, bfd_boolean, unsigned int, bfd_boolean, bfd_boolean);
+static bfd_boolean tg_class_static_member (void *, const char *, const char *, enum debug_visibility);
+static bfd_boolean tg_class_baseclass (void *, bfd_vma, bfd_boolean, enum debug_visibility);
+static bfd_boolean tg_class_method_variant (void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean, bfd_vma, bfd_boolean);
+static bfd_boolean tg_class_static_method_variant (void *, const char *, enum debug_visibility, bfd_boolean, bfd_boolean);
+static bfd_boolean tg_end_class_type (void *);
+static bfd_boolean tg_tag_type (void *, const char *, unsigned int, enum debug_type_kind);
+static bfd_boolean tg_typdef (void *, const char *);
+static bfd_boolean tg_tag (void *, const char *);
+static bfd_boolean tg_int_constant (void *, const char *, bfd_vma);
+static bfd_boolean tg_float_constant (void *, const char *, double);
+static bfd_boolean tg_typed_constant (void *, const char *, bfd_vma);
+static bfd_boolean tg_variable (void *, const char *, enum debug_var_kind, bfd_vma);
+static bfd_boolean tg_start_function (void *, const char *, bfd_boolean);
+static bfd_boolean tg_function_parameter (void *, const char *, enum debug_parm_kind, bfd_vma);
+static bfd_boolean tg_start_block (void *, bfd_vma);
+static bfd_boolean tg_end_block (void *, bfd_vma);
+static bfd_boolean tg_lineno (void *, const char *, unsigned long, bfd_vma);
+
static const struct debug_write_fns pr_fns =
{
pr_start_compilation_unit,
@@ -217,12 +267,64 @@ static const struct debug_write_fns pr_fns =
pr_lineno
};
+static const struct debug_write_fns tg_fns =
+{
+ tg_start_compilation_unit,
+ tg_start_source,
+ pr_empty_type, /* Same, push_type. */
+ pr_void_type, /* Same, push_type. */
+ pr_int_type, /* Same, push_type. */
+ pr_float_type, /* Same, push_type. */
+ pr_complex_type, /* Same, push_type. */
+ pr_bool_type, /* Same, push_type. */
+ tg_enum_type,
+ pr_pointer_type, /* Same, changes to pointer. */
+ pr_function_type, /* Same, push_type. */
+ pr_reference_type, /* Same, changes to reference. */
+ pr_range_type, /* FIXME: What's that?. */
+ pr_array_type, /* Same, push_type. */
+ pr_set_type, /* FIXME: What's that?. */
+ pr_offset_type, /* FIXME: What's that?. */
+ pr_method_type, /* Same. */
+ pr_const_type, /* Same, changes to const. */
+ pr_volatile_type, /* Same, changes to volatile. */
+ tg_start_struct_type,
+ tg_struct_field,
+ tg_end_struct_type,
+ tg_start_class_type,
+ tg_class_static_member,
+ tg_class_baseclass,
+ pr_class_start_method, /* Same, remmembers that's a method. */
+ tg_class_method_variant,
+ tg_class_static_method_variant,
+ pr_class_end_method, /* Same, forgets that's a method. */
+ tg_end_class_type,
+ pr_typedef_type, /* Same, just push type. */
+ tg_tag_type,
+ tg_typdef,
+ tg_tag,
+ tg_int_constant, /* Untested. */
+ tg_float_constant, /* Untested. */
+ tg_typed_constant, /* Untested. */
+ tg_variable,
+ tg_start_function,
+ tg_function_parameter,
+ tg_start_block,
+ tg_end_block,
+ pr_end_function, /* Same, does nothing. */
+ tg_lineno
+};
+
/* Print out the generic debugging information recorded in dhandle. */
bfd_boolean
-print_debugging_info (f, dhandle)
+print_debugging_info (f, dhandle, abfd, syms, demangler, as_tags)
FILE *f;
PTR dhandle;
+ bfd *abfd;
+ asymbol **syms;
+ PTR demangler;
+ bfd_boolean as_tags;
{
struct pr_handle info;
@@ -230,8 +332,21 @@ print_debugging_info (f, dhandle)
info.indent = 0;
info.stack = NULL;
info.parameter = 0;
+ info.filename = NULL;
+ info.abfd = abfd;
+ info.syms = syms;
+ info.demangler = demangler;
- return debug_write (dhandle, &pr_fns, (PTR) &info);
+ if (as_tags)
+ {
+ fputs ("!_TAG_FILE_FORMAT\t2\t/extended format/\n", f);
+ fputs ("!_TAG_FILE_SORTED\t0\t/0=unsorted, 1=sorted/\n", f);
+ fputs ("!_TAG_PROGRAM_AUTHOR\tIan Lance Taylor, Salvador E. Tropea and others\t//\n", f);
+ fputs ("!_TAG_PROGRAM_NAME\tobjdump\t/From GNU binutils/\n", f);
+ }
+
+ return as_tags ? debug_write (dhandle, &tg_fns, (void *) & info)
+ : debug_write (dhandle, &pr_fns, (void *) & info);
}
/* Indent to the current indentation level. */
@@ -311,6 +426,26 @@ append_type (info, s)
return TRUE;
}
+/* Append a string to the parents on the top of the type stack. */
+
+static bfd_boolean
+append_parent (struct pr_handle *info, const char *s)
+{
+ unsigned int len;
+
+ if (s == NULL)
+ return FALSE;
+
+ assert (info->stack != NULL);
+
+ len = info->stack->parents ? strlen (info->stack->parents) : 0;
+ info->stack->parents = (char *) xrealloc (info->stack->parents,
+ len + strlen (s) + 1);
+ strcpy (info->stack->parents + len, s);
+
+ return TRUE;
+}
+
/* We use an underscore to indicate where the name should go in a type
string. This function substitutes a string for the underscore. If
there is no underscore, the name follows the type. */
@@ -1894,3 +2029,922 @@ pr_end_function (p)
{
return TRUE;
}
+
+/* Tags style generation functions start here. */
+
+/* Variables for address to line translation. */
+static bfd_vma pc;
+static const char *filename;
+static const char *functionname;
+static unsigned int line;
+static bfd_boolean found;
+
+/* Look for an address in a section. This is called via
+ bfd_map_over_sections. */
+
+static void
+find_address_in_section (bfd *abfd, asection *section, void *data)
+{
+ bfd_vma vma;
+ bfd_size_type size;
+ asymbol **syms = (asymbol **) data;
+
+ if (found)
+ return;
+
+ if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0)
+ return;
+
+ vma = bfd_get_section_vma (abfd, section);
+ if (pc < vma)
+ return;
+
+ size = bfd_get_section_size_before_reloc (section);
+ if (pc >= vma + size)
+ return;
+
+ found = bfd_find_nearest_line (abfd, section, syms, pc - vma,
+ &filename, &functionname, &line);
+}
+
+static void
+translate_addresses (bfd *abfd, char *addr_hex, FILE *f, asymbol **syms)
+{
+ pc = bfd_scan_vma (addr_hex, NULL, 16);
+ found = FALSE;
+ bfd_map_over_sections (abfd, find_address_in_section, syms);
+
+ if (! found)
+ fprintf (f, "??");
+ else
+ fprintf (f, "%u", line);
+}
+
+/* Start a new compilation unit. */
+
+static bfd_boolean
+tg_start_compilation_unit (void * p, const char *filename ATTRIBUTE_UNUSED)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ fprintf (stderr, "New compilation unit: %s\n", filename);
+
+ free (info->filename);
+ /* Should it be relative? best way to do it here?. */
+ info->filename = strdup (filename);
+
+ return TRUE;
+}
+
+/* Start a source file within a compilation unit. */
+
+static bfd_boolean
+tg_start_source (void *p, const char *filename)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ free (info->filename);
+ /* Should it be relative? best way to do it here?. */
+ info->filename = strdup (filename);
+
+ return TRUE;
+}
+
+/* Push an enum type onto the type stack. */
+
+static bfd_boolean
+tg_enum_type (void *p, const char *tag, const char **names,
+ bfd_signed_vma *values)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ unsigned int i;
+ const char *name;
+ char ab[20];
+
+ if (! pr_enum_type (p, tag, names, values))
+ return FALSE;
+
+ name = tag ? tag : "unknown";
+ /* Generate an entry for the enum. */
+ if (tag)
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:e\ttype:%s\n", tag,
+ info->filename, info->stack->type);
+
+ /* Generate entries for the values. */
+ if (names != NULL)
+ {
+ for (i = 0; names[i] != NULL; i++)
+ {
+ print_vma (values[i], ab, FALSE, FALSE);
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:g\tenum:%s\tvalue:%s\n",
+ names[i], info->filename, name, ab);
+ }
+ }
+
+ return TRUE;
+}
+
+/* Start accumulating a struct type. */
+
+static bfd_boolean
+tg_start_struct_type (void *p, const char *tag, unsigned int id,
+ bfd_boolean structp, unsigned int size ATTRIBUTE_UNUSED)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ const char *name;
+ char idbuf[20];
+
+ if (tag != NULL)
+ name = tag;
+ else
+ {
+ name = idbuf;
+ sprintf (idbuf, "%%anon%u", id);
+ }
+
+ if (! push_type (info, name))
+ return FALSE;
+
+ info->stack->flavor = structp ? "struct" : "union";
+
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:%c\n", name, info->filename,
+ info->stack->flavor[0]);
+
+ info->stack->visibility = DEBUG_VISIBILITY_PUBLIC;
+
+ return indent_type (info);
+}
+
+/* Output the visibility of a field in a struct. */
+
+static bfd_boolean
+tg_fix_visibility (struct pr_handle *info, enum debug_visibility visibility)
+{
+ assert (info->stack != NULL);
+
+ if (info->stack->visibility == visibility)
+ return TRUE;
+
+ assert (info->stack->visibility != DEBUG_VISIBILITY_IGNORE);
+
+ info->stack->visibility = visibility;
+
+ return TRUE;
+}
+
+/* Add a field to a struct type. */
+
+static bfd_boolean
+tg_struct_field (void *p, const char *name, bfd_vma bitpos ATTRIBUTE_UNUSED,
+ bfd_vma bitsize ATTRIBUTE_UNUSED,
+ enum debug_visibility visibility)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return FALSE;
+
+ if (! tg_fix_visibility (info, visibility))
+ return FALSE;
+
+ /* It happends, a bug? */
+ if (! name[0])
+ return TRUE;
+
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:m\ttype:%s\t%s:%s\taccess:%s\n",
+ name, info->filename, t, info->stack->flavor, info->stack->type,
+ visibility_name (visibility));
+
+ return TRUE;
+}
+
+/* Finish a struct type. */
+
+static bfd_boolean
+tg_end_struct_type (void *p ATTRIBUTE_UNUSED)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ assert (info->stack != NULL);
+
+ return TRUE;
+}
+
+/* Start a class type. */
+
+static bfd_boolean
+tg_start_class_type (void *p, const char *tag, unsigned int id,
+ bfd_boolean structp, unsigned int size,
+ bfd_boolean vptr, bfd_boolean ownvptr)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *tv = NULL;
+ const char *name;
+
+ info->indent += 2;
+
+ if (vptr && ! ownvptr)
+ {
+ tv = pop_type (info);
+ if (tv == NULL)
+ return FALSE;
+ }
+
+ if (tag != NULL)
+ name = tag;
+ else
+ {
+ char idbuf[20];
+
+ sprintf (idbuf, "%%anon%u", id);
+ name = idbuf;
+ }
+
+ if (! push_type (info, name))
+ return FALSE;
+
+ info->stack->flavor = structp ? "class" : "union class";
+ info->stack->parents = NULL;
+ info->stack->num_parents = 0;
+
+ if (size != 0 || vptr || ownvptr || tag != NULL)
+ {
+ if (vptr)
+ {
+ if (! append_type (info, " vtable "))
+ return FALSE;
+ if (ownvptr)
+ {
+ if (! append_type (info, "self "))
+ return FALSE;
+ }
+ else
+ {
+ if (! append_type (info, tv)
+ || ! append_type (info, " "))
+ return FALSE;
+ }
+ }
+ }
+
+ info->stack->visibility = DEBUG_VISIBILITY_PRIVATE;
+
+ return TRUE;
+}
+
+/* Add a static member to a class. */
+
+static bfd_boolean
+tg_class_static_member (void *p, const char *name,
+ const char *physname ATTRIBUTE_UNUSED,
+ enum debug_visibility visibility)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+ int len_var, len_class;
+ char *full_name;
+
+ len_var = strlen (name);
+ len_class = strlen (info->stack->next->type);
+ full_name = (char *) xmalloc (len_var + len_class + 3);
+ if (! full_name)
+ return FALSE;
+ memcpy (full_name, info->stack->next->type, len_class);
+ memcpy (full_name + len_class, "::", 2);
+ memcpy (full_name + len_class + 2, name, len_var + 1);
+
+ if (! substitute_type (info, full_name))
+ return FALSE;
+
+ if (! prepend_type (info, "static "))
+ return FALSE;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return FALSE;
+
+ if (! tg_fix_visibility (info, visibility))
+ return FALSE;
+
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:x\ttype:%s\tclass:%s\taccess:%s\n",
+ name, info->filename, t, info->stack->type,
+ visibility_name (visibility));
+ free (t);
+ free (full_name);
+
+ return TRUE;
+}
+
+/* Add a base class to a class. */
+
+static bfd_boolean
+tg_class_baseclass (void *p, bfd_vma bitpos ATTRIBUTE_UNUSED,
+ bfd_boolean virtual, enum debug_visibility visibility)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+ const char *prefix;
+
+ assert (info->stack != NULL && info->stack->next != NULL);
+
+ t = pop_type (info);
+ if (t == NULL)
+ return FALSE;
+
+ if (strncmp (t, "class ", sizeof "class " - 1) == 0)
+ t += sizeof "class " - 1;
+
+ /* Push it back on to take advantage of the prepend_type and
+ append_type routines. */
+ if (! push_type (info, t))
+ return FALSE;
+
+ if (virtual)
+ {
+ if (! prepend_type (info, "virtual "))
+ return FALSE;
+ }
+
+ switch (visibility)
+ {
+ case DEBUG_VISIBILITY_PUBLIC:
+ prefix = "public ";
+ break;
+ case DEBUG_VISIBILITY_PROTECTED:
+ prefix = "protected ";
+ break;
+ case DEBUG_VISIBILITY_PRIVATE:
+ prefix = "private ";
+ break;
+ default:
+ prefix = "/* unknown visibility */ ";
+ break;
+ }
+
+ if (! prepend_type (info, prefix))
+ return FALSE;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return FALSE;
+
+ if (info->stack->num_parents && ! append_parent (info, ", "))
+ return FALSE;
+
+ if (! append_parent (info, t))
+ return FALSE;
+ info->stack->num_parents++;
+
+ free (t);
+
+ return TRUE;
+}
+
+/* Add a variant to a method. */
+
+static bfd_boolean
+tg_class_method_variant (void *p, const char *physname ATTRIBUTE_UNUSED,
+ enum debug_visibility visibility,
+ bfd_boolean constp, bfd_boolean volatilep,
+ bfd_vma voffset ATTRIBUTE_UNUSED,
+ bfd_boolean context)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *method_type;
+ char *context_type;
+ char *method_name;
+
+ assert (info->stack != NULL);
+ assert (info->stack->next != NULL);
+
+ /* Put the const and volatile qualifiers on the type. */
+ if (volatilep)
+ {
+ if (! append_type (info, " volatile"))
+ return FALSE;
+ }
+ if (constp)
+ {
+ if (! append_type (info, " const"))
+ return FALSE;
+ }
+
+ method_name = strdup (context ? info->stack->next->next->method
+ : info->stack->next->method);
+
+ /* Stick the name of the method into its type. */
+ if (! substitute_type (info, method_name))
+ return FALSE;
+
+ /* Get the type. */
+ method_type = pop_type (info);
+ if (method_type == NULL)
+ return FALSE;
+
+ /* Pull off the context type if there is one. */
+ if (! context)
+ context_type = NULL;
+ else
+ {
+ context_type = pop_type (info);
+ if (context_type == NULL)
+ return FALSE;
+ }
+
+ /* Now the top of the stack is the class. */
+ if (! tg_fix_visibility (info, visibility))
+ return FALSE;
+
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:p\ttype:%s\tclass:%s\n",
+ method_name, info->filename, method_type, info->stack->type);
+ free (method_type);
+ free (method_name);
+ free (context_type);
+
+ return TRUE;
+}
+
+/* Add a static variant to a method. */
+
+static bfd_boolean
+tg_class_static_method_variant (void *p,
+ const char *physname ATTRIBUTE_UNUSED,
+ enum debug_visibility visibility,
+ bfd_boolean constp,
+ bfd_boolean volatilep)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *method_type;
+ char *method_name;
+
+ assert (info->stack != NULL);
+ assert (info->stack->next != NULL);
+ assert (info->stack->next->method != NULL);
+
+ /* Put the const and volatile qualifiers on the type. */
+ if (volatilep)
+ {
+ if (! append_type (info, " volatile"))
+ return FALSE;
+ }
+ if (constp)
+ {
+ if (! append_type (info, " const"))
+ return FALSE;
+ }
+
+ /* Mark it as static. */
+ if (! prepend_type (info, "static "))
+ return FALSE;
+
+ method_name = strdup (info->stack->next->method);
+ /* Stick the name of the method into its type. */
+ if (! substitute_type (info, info->stack->next->method))
+ return FALSE;
+
+ /* Get the type. */
+ method_type = pop_type (info);
+ if (method_type == NULL)
+ return FALSE;
+
+ /* Now the top of the stack is the class. */
+ if (! tg_fix_visibility (info, visibility))
+ return FALSE;
+
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:p\ttype:%s\tclass:%s\taccess:%s\n",
+ method_name, info->filename, method_type, info->stack->type,
+ visibility_name (visibility));
+ free (method_type);
+ free (method_name);
+
+ return TRUE;
+}
+
+/* Finish up a class. */
+
+static bfd_boolean
+tg_end_class_type (void *p)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:c\ttype:%s", info->stack->type,
+ info->filename, info->stack->flavor);
+ if (info->stack->num_parents)
+ {
+ fprintf (info->f, "\tinherits:%s", info->stack->parents);
+ free (info->stack->parents);
+ }
+ fputc ('\n', info->f);
+
+ return tg_end_struct_type (p);
+}
+
+/* Push a type on the stack using a tag name. */
+
+static bfd_boolean
+tg_tag_type (void *p, const char *name, unsigned int id,
+ enum debug_type_kind kind)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ const char *t, *tag;
+ char idbuf[20];
+
+ switch (kind)
+ {
+ case DEBUG_KIND_STRUCT:
+ t = "struct ";
+ break;
+ case DEBUG_KIND_UNION:
+ t = "union ";
+ break;
+ case DEBUG_KIND_ENUM:
+ t = "enum ";
+ break;
+ case DEBUG_KIND_CLASS:
+ t = "class ";
+ break;
+ case DEBUG_KIND_UNION_CLASS:
+ t = "union class ";
+ break;
+ default:
+ abort ();
+ return FALSE;
+ }
+
+ if (! push_type (info, t))
+ return FALSE;
+ if (name != NULL)
+ tag = name;
+ else
+ {
+ sprintf (idbuf, "%%anon%u", id);
+ tag = idbuf;
+ }
+
+ if (! append_type (info, tag))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Output a typedef. */
+
+static bfd_boolean
+tg_typdef (void *p, const char *name)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *s;
+
+ s = pop_type (info);
+ if (s == NULL)
+ return FALSE;
+
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:t\ttype:%s\n", name,
+ info->filename, s);
+
+ free (s);
+
+ return TRUE;
+}
+
+/* Output a tag. The tag should already be in the string on the
+ stack, so all we have to do here is print it out. */
+
+static bfd_boolean
+tg_tag (void *p ATTRIBUTE_UNUSED, const char *name ATTRIBUTE_UNUSED)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return FALSE;
+ free (t);
+
+ return TRUE;
+}
+
+/* Output an integer constant. */
+
+static bfd_boolean
+tg_int_constant (void *p, const char *name, bfd_vma val)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[20];
+
+ indent (info);
+ print_vma (val, ab, FALSE, FALSE);
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:v\ttype:const int\tvalue:%s\n",
+ name, info->filename, ab);
+ return TRUE;
+}
+
+/* Output a floating point constant. */
+
+static bfd_boolean
+tg_float_constant (void *p, const char *name, double val)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+
+ indent (info);
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:v\ttype:const double\tvalue:%g\n",
+ name, info->filename, val);
+ return TRUE;
+}
+
+/* Output a typed constant. */
+
+static bfd_boolean
+tg_typed_constant (void *p, const char *name, bfd_vma val)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+ char ab[20];
+
+ t = pop_type (info);
+ if (t == NULL)
+ return FALSE;
+
+ indent (info);
+ print_vma (val, ab, FALSE, FALSE);
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:v\ttype:const %s\tvalue:%s\n",
+ name, info->filename, t, ab);
+
+ free (t);
+
+ return TRUE;
+}
+
+/* Output a variable. */
+
+static bfd_boolean
+tg_variable (void *p, const char *name, enum debug_var_kind kind,
+ bfd_vma val ATTRIBUTE_UNUSED)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+ const char *dname, *from_class;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return FALSE;
+
+ dname = name;
+ if (info->demangler)
+ {
+ dname = info->demangler (info->abfd, name);
+ if (strcmp (name, dname) == 0)
+ {
+ free ((char *) dname);
+ dname = name;
+ }
+ }
+
+ if (dname != name)
+ {
+ char *sep;
+ sep = strstr (dname, "::");
+ if (sep)
+ {
+ *sep = 0;
+ name = sep + 2;
+ from_class = dname;
+ }
+ else
+ {
+ /* Obscure types as vts and type_info nodes. */
+ name = dname;
+ from_class = NULL;
+ }
+ }
+ else
+ from_class = NULL;
+
+ fprintf (info->f, "%s\t%s\t0;\"\tkind:v\ttype:%s", name, info->filename, t);
+
+ switch (kind)
+ {
+ case DEBUG_STATIC:
+ case DEBUG_LOCAL_STATIC:
+ fprintf (info->f, "\tfile:");
+ break;
+ case DEBUG_REGISTER:
+ fprintf (info->f, "\tregister:");
+ break;
+ default:
+ break;
+ }
+
+ if (from_class)
+ {
+ fprintf (info->f, "\tclass:%s",from_class);
+ free ((char *) dname);
+ }
+
+ fprintf (info->f, "\n");
+
+ free (t);
+
+ return TRUE;
+}
+
+/* Start outputting a function. */
+
+static bfd_boolean
+tg_start_function (void *p, const char *name, bfd_boolean global)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ const char *dname;
+
+ if (! global)
+ info->stack->flavor = "static";
+ else
+ info->stack->flavor = NULL;
+
+ dname = name;
+ if (info->demangler)
+ {
+ dname = info->demangler (info->abfd, name);
+ if (strcmp (name, dname) == 0)
+ {
+ free ((char *) dname);
+ dname = name;
+ }
+ }
+
+ if (! substitute_type (info, dname))
+ return FALSE;
+
+ if (dname != name)
+ {
+ char *sep;
+ sep = strstr (dname, "::");
+ if (sep)
+ {
+ info->stack->method = dname;
+ *sep = 0;
+ name = sep + 2;
+ }
+ else
+ {
+ info->stack->method = "";
+ name = dname;
+ }
+ sep = strchr (name, '(');
+ if (sep)
+ *sep = 0;
+ /* Obscure functions as type_info function. */
+ }
+ else
+ info->stack->method = NULL;
+
+ info->stack->parents = strdup (name);
+
+ if (! info->stack->method && ! append_type (info, "("))
+ return FALSE;
+
+ info->parameter = 1;
+
+ return TRUE;
+}
+
+/* Output a function parameter. */
+
+static bfd_boolean
+tg_function_parameter (void *p, const char *name, enum debug_parm_kind kind,
+ bfd_vma val ATTRIBUTE_UNUSED)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char *t;
+
+ if (kind == DEBUG_PARM_REFERENCE
+ || kind == DEBUG_PARM_REF_REG)
+ {
+ if (! pr_reference_type (p))
+ return FALSE;
+ }
+
+ if (! substitute_type (info, name))
+ return FALSE;
+
+ t = pop_type (info);
+ if (t == NULL)
+ return FALSE;
+
+ if (! info->stack->method)
+ {
+ if (info->parameter != 1 && ! append_type (info, ", "))
+ return FALSE;
+
+ if (kind == DEBUG_PARM_REG || kind == DEBUG_PARM_REF_REG)
+ if (! append_type (info, "register "))
+ return FALSE;
+
+ if (! append_type (info, t))
+ return FALSE;
+ }
+
+ free (t);
+
+ ++info->parameter;
+
+ return TRUE;
+}
+
+/* Start writing out a block. */
+
+static bfd_boolean
+tg_start_block (void *p, bfd_vma addr)
+{
+ struct pr_handle *info = (struct pr_handle *) p;
+ char ab[20], kind, *partof;
+ char *t;
+ bfd_boolean local;
+
+ if (info->parameter > 0)
+ {
+ info->parameter = 0;
+
+ /* Delayed name. */
+ fprintf (info->f, "%s\t%s\t", info->stack->parents, info->filename);
+ free (info->stack->parents);
+
+ print_vma (addr, ab, TRUE, TRUE);
+ translate_addresses (info->abfd, ab, info->f, info->syms);
+ local = info->stack->flavor != NULL;
+ if (info->stack->method && *info->stack->method)
+ {
+ kind = 'm';
+ partof = (char *) info->stack->method;
+ }
+ else
+ {
+ kind = 'f';
+ partof = NULL;
+ if (! info->stack->method && ! append_type (info, ")"))
+ return FALSE;
+ }
+ t = pop_type (info);
+ if (t == NULL)
+ return FALSE;
+ fprintf (info->f, ";\"\tkind:%c\ttype:%s", kind, t);
+ if (local)
+ fputs ("\tfile:", info->f);
+ if (partof)
+ {
+ fprintf (info->f, "\tclass:%s", partof);
+ free (partof);
+ }
+ fputc ('\n', info->f);
+ }
+
+ return TRUE;
+}
+
+/* Write out line number information. */
+
+static bfd_boolean
+tg_lineno (void *p ATTRIBUTE_UNUSED,
+ const char *filename ATTRIBUTE_UNUSED,
+ unsigned long lineno ATTRIBUTE_UNUSED,
+ bfd_vma addr ATTRIBUTE_UNUSED)
+{
+ return TRUE;
+}
+
+/* Finish writing out a block. */
+
+static bfd_boolean
+tg_end_block (void *p ATTRIBUTE_UNUSED, bfd_vma addr ATTRIBUTE_UNUSED)
+{
+ return TRUE;
+}
+
+/* Convert the visibility value into a human readable name. */
+
+static const char *
+visibility_name (enum debug_visibility visibility)
+{
+ const char *s;
+
+ switch (visibility)
+ {
+ case DEBUG_VISIBILITY_PUBLIC:
+ s = "public";
+ break;
+ case DEBUG_VISIBILITY_PRIVATE:
+ s = "private";
+ break;
+ case DEBUG_VISIBILITY_PROTECTED:
+ s = "protected";
+ break;
+ case DEBUG_VISIBILITY_IGNORE:
+ s = "/* ignore */";
+ break;
+ default:
+ abort ();
+ return FALSE;
+ }
+ return s;
+}