This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
RFC objdump new feature to generate debug info using ctags style
- From: Salvador Eduardo Tropea <salvador at inti dot gov dot ar>
- To: binutils at sources dot redhat dot com
- Date: Fri, 02 May 2003 12:49:56 -0300
- Subject: RFC objdump new feature to generate debug info using ctags style
Hi All!
I managed to modify prdbg.c to print the information in a format
compatible with Exuberant Ctags (plus some fileds not available in
E.Ctags). I just added some arguments to print_debugging_info and
created a new debug_write_fns structure with pointers to the
replacements needed to generate the data using this format.
The code seems to be working and I tested it for a medium weight project
that generated more than 10 MB of tags (6 MB after sorting and
discarding repeated entries).
My question is: should it be accepted?
I also patched objdump to use it with a new command line option.
The patch is 34 KB, mostly additions to prdbg.c.
I attached it to this mail but I think it should be passed by indent
before applying it.
SET
--
Salvador Eduardo Tropea (SET). (Electronics Engineer)
Visit my home page: http://welcome.to/SetSoft or
http://www.geocities.com/SiliconValley/Vista/6552/
Alternative e-mail: set@computer.org set@ieee.org
Address: Curapaligue 2124, Caseros, 3 de Febrero
Buenos Aires, (1678), ARGENTINA Phone: +(5411) 4759 0013
Index: objdump.c
===================================================================
RCS file: /cvs/src/src/binutils/objdump.c,v
retrieving revision 1.66
diff -u -r1.66 objdump.c
--- objdump.c 1 May 2003 00:40:41 -0000 1.66
+++ objdump.c 2 May 2003 15:46:39 -0000
@@ -74,6 +74,7 @@
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 @@
-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 @@
{"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,7 +2071,8 @@
}
}
- printf (_("\n%s: file format %s\n"), bfd_get_filename (abfd),
+ 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);
@@ -2076,7 +2080,8 @@
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 @@
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 @@
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)
{
@@ -2779,6 +2785,12 @@
break;
case 'g':
dump_debugging = 1;
+ seenflag = TRUE;
+ break;
+ case 'e':
+ dump_debugging = 1;
+ dump_debugging_tags = 1;
+ do_demangle = TRUE;
seenflag = TRUE;
break;
case 'G':
Index: budbg.h
===================================================================
RCS file: /cvs/src/src/binutils/budbg.h,v
retrieving revision 1.3
diff -u -r1.3 budbg.h
--- budbg.h 30 Nov 2002 08:39:41 -0000 1.3
+++ budbg.h 2 May 2003 15:46:39 -0000
@@ -32,8 +32,8 @@
/* Routine used to print generic debugging information. */
extern bfd_boolean print_debugging_info
- PARAMS ((FILE *, PTR));
-
+ PARAMS ((FILE *, PTR, bfd *, asymbol **, PTR, bfd_boolean));
+
/* Routines used to read and write stabs information. */
extern PTR start_stab
Index: prdbg.c
===================================================================
RCS file: /cvs/src/src/binutils/prdbg.c,v
retrieving revision 1.6
diff -u -r1.6 prdbg.c
--- prdbg.c 30 Nov 2002 08:39:41 -0000 1.6
+++ prdbg.c 2 May 2003 15:46:40 -0000
@@ -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_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) PARAMS ((bfd *, const char *));
};
/* The type stack. */
@@ -57,6 +67,13 @@
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
@@ -67,6 +84,8 @@
PARAMS ((struct pr_handle *, const char *));
static bfd_boolean append_type
PARAMS ((struct pr_handle *, const char *));
+static bfd_boolean append_parent
+ PARAMS ((struct pr_handle *, const char *));
static bfd_boolean substitute_type
PARAMS ((struct pr_handle *, const char *));
static bfd_boolean indent_type
@@ -77,6 +96,16 @@
PARAMS ((bfd_vma, char *, bfd_boolean, bfd_boolean));
static bfd_boolean pr_fix_visibility
PARAMS ((struct pr_handle *, enum debug_visibility));
+/* Only used by tg_ code */
+static bfd_boolean tg_fix_visibility
+ PARAMS ((struct pr_handle *, enum debug_visibility));
+static void find_address_in_section
+ PARAMS ((bfd *abfd, asection *section, PTR data));
+static void translate_addresses
+ PARAMS ((bfd *abfd, char *addr_hex, FILE *f, asymbol **syms));
+static const char *visibility_name
+ PARAMS ((enum debug_visibility visibility));
+
static bfd_boolean pr_start_compilation_unit
PARAMS ((PTR, const char *));
static bfd_boolean pr_start_source
@@ -169,6 +198,63 @@
static bfd_boolean pr_lineno
PARAMS ((PTR, const char *, unsigned long, bfd_vma));
+/* Tags style replacements */
+static bfd_boolean tg_start_compilation_unit
+ PARAMS ((PTR, const char *));
+static bfd_boolean tg_start_source
+ PARAMS ((PTR, const char *));
+static bfd_boolean tg_enum_type
+ PARAMS ((PTR, const char *, const char **, bfd_signed_vma *));
+static bfd_boolean tg_start_struct_type
+ PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int));
+static bfd_boolean pr_struct_field
+ PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility));
+static bfd_boolean tg_struct_field
+ PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility));
+static bfd_boolean tg_struct_field
+ PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility));
+static bfd_boolean tg_end_struct_type
+ PARAMS ((PTR));
+static bfd_boolean tg_start_class_type
+ PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int,
+ bfd_boolean, bfd_boolean));
+static bfd_boolean tg_class_static_member
+ PARAMS ((PTR, const char *, const char *, enum debug_visibility));
+static bfd_boolean tg_class_baseclass
+ PARAMS ((PTR, bfd_vma, bfd_boolean, enum debug_visibility));
+static bfd_boolean tg_class_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, bfd_boolean,
+ bfd_vma, bfd_boolean));
+static bfd_boolean tg_class_static_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean,
+ bfd_boolean));
+static bfd_boolean tg_end_class_type
+ PARAMS ((PTR));
+static bfd_boolean tg_tag_type
+ PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind));
+static bfd_boolean tg_typdef
+ PARAMS ((PTR, const char *));
+static bfd_boolean tg_tag
+ PARAMS ((PTR, const char *));
+static bfd_boolean tg_int_constant
+ PARAMS ((PTR, const char *, bfd_vma));
+static bfd_boolean tg_float_constant
+ PARAMS ((PTR, const char *, double));
+static bfd_boolean tg_typed_constant
+ PARAMS ((PTR, const char *, bfd_vma));
+static bfd_boolean tg_variable
+ PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma));
+static bfd_boolean tg_start_function
+ PARAMS ((PTR, const char *, bfd_boolean));
+static bfd_boolean tg_function_parameter
+ PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma));
+static bfd_boolean tg_start_block
+ PARAMS ((PTR, bfd_vma));
+static bfd_boolean tg_end_block
+ PARAMS ((PTR, bfd_vma));
+static bfd_boolean tg_lineno
+ PARAMS ((PTR, const char *, unsigned long, bfd_vma));
+
static const struct debug_write_fns pr_fns =
{
pr_start_compilation_unit,
@@ -217,12 +303,64 @@
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 +368,22 @@
info.indent = 0;
info.stack = NULL;
info.parameter = 0;
+ info.filename = NULL;
+ info.abfd = abfd;
+ info.syms = syms;
+ info.demangler = demangler;
+
+ 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);
+ /*!_TAG_PROGRAM_VERSION 5.2.2 //*/
+ }
- return debug_write (dhandle, &pr_fns, (PTR) &info);
+ return as_tags ? debug_write (dhandle, &tg_fns, (PTR) &info)
+ : debug_write (dhandle, &pr_fns, (PTR) &info);
}
/* Indent to the current indentation level. */
@@ -311,6 +463,28 @@
return TRUE;
}
+/* Append a string to the parents on the top of the type stack. */
+
+static bfd_boolean
+append_parent (info, s)
+ 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 +2068,1006 @@
{
return TRUE;
}
+
+/*****************************************************************************
+
+ Tags style generation functions from 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 (abfd, section, data)
+ bfd *abfd;
+ asection *section;
+ PTR 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 (abfd, addr_hex, f, syms)
+ 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 (%s)", line, addr_hex);
+ fprintf (f, "%u", line);
+}
+
+/* Start a new compilation unit. */
+
+static bfd_boolean
+tg_start_compilation_unit (p, filename)
+ PTR 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 (p, filename)
+ PTR 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 (p, tag, names, values)
+ PTR 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 (p, tag, id, structp, size)
+ PTR 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 (info, 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 (p, name, bitpos, bitsize, visibility)
+ PTR 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 (p)
+ PTR 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 (p, tag, id, structp, size, vptr, ownvptr)
+ PTR 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 (p, name, physname, visibility)
+ PTR 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 (p, bitpos, virtual, visibility)
+ PTR 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 (p, physname, visibility, constp, volatilep, voffset,
+ context)
+ PTR 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 (p, physname, visibility, constp, volatilep)
+ PTR 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 (p)
+ PTR 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 (p, name, id, kind)
+ PTR 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 (p, name)
+ PTR 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 (p, name)
+ PTR 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 (p, name, val)
+ PTR 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 (p, name, val)
+ PTR 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 (p, name, val)
+ PTR 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 (p, name, kind, val)
+ PTR 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 */
+ /*fprintf(stderr,"%s => %s\n",name,dname);*/
+ 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 (p, name, global)
+ PTR 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
+ fprintf(stderr,"%s => %s\n",name,dname);*/
+ }
+ else
+ info->stack->method = NULL;
+
+ info->stack->parents = strdup (name);
+ //fprintf (info->f, "%s\t%s\t", name, info->filename);
+
+ if (! info->stack->method && ! append_type (info, "("))
+ return FALSE;
+
+ info->parameter = 1;
+
+ return TRUE;
+}
+
+/* Output a function parameter. */
+
+static bfd_boolean
+tg_function_parameter (p, name, kind, val)
+ PTR 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 (p, addr)
+ PTR 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 (p, filename, lineno, addr)
+ PTR 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 (p, addr)
+ PTR p ATTRIBUTE_UNUSED;
+ bfd_vma addr ATTRIBUTE_UNUSED;
+{
+ return TRUE;
+}
+
+static
+const char *visibility_name (visibility)
+ 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;
+}
+