This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFC objdump new feature to generate debug info using ctags style


This is from a couple of months ago:

On 12/05/03 08:17 Nick Clifton wrote:

I managed to modify prdbg.c to print the information in a format compatible with Exuberant Ctags (plus some fields not available in
E.Ctags).



Thanks very much for submitting this patch.


Since this patch adds a new feature to objdump it definitely needs a
copyright assignment before it can be accepted.

Ok, I think this is done. I received the papers, signed them, sent it back to FSF and got an e-mail confirmation (no regular letter, just e-mail).
Can you check if all is ok?


If you are willing
to make such an assignment please fill out the email form attached
below and send it off the FSF.  The process will take a while but it
should be worth it as they we can consider accepting your patches.

As for the patch itself, there are a couple of issues:

* It needs a ChangeLog entry.

Added.

 * Since you are adding a new feature it needs to be documented.
   Please extend the patch to include changes to
   binutils/doc/binutils.texi and binutils/NEWS.

Also added.

 * Please try to follow the GNU coding standard.  (In the patch there
   are several comments that ought to be reformatted to include a
   terminating period followed by two spaces.  Also there are places
   where there is no space between a function name and its opening
   parenthesis).

Ok, I checked manually and with a diff between the file and the "indent" output. I followed indent suggestions for all but things that the original author did in a different way. The most important differences is between:
if (! condition)
and
if (!condition)


Attached is the output of cvs diff -u.

Regards,
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: ChangeLog
===================================================================
RCS file: /cvs/src/src/binutils/ChangeLog,v
retrieving revision 1.670
diff -u -r1.670 ChangeLog
--- ChangeLog	18 Jul 2003 11:34:41 -0000	1.670
+++ ChangeLog	21 Jul 2003 19:31:51 -0000
@@ -1,3 +1,12 @@
+2003-07-21  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.
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	21 Jul 2003 19:31:51 -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: objdump.c
===================================================================
RCS file: /cvs/src/src/binutils/objdump.c,v
retrieving revision 1.69
diff -u -r1.69 objdump.c
--- objdump.c	18 Jul 2003 11:34:41 -0000	1.69
+++ objdump.c	21 Jul 2003 19:31:51 -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,15 +2071,17 @@
 	}
     }
 
-  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 @@
       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)
     {
@@ -2783,6 +2789,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: 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	21 Jul 2003 19:31:52 -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,23 @@
   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);
+    }
 
-  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 +464,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.  */
@@ -1893,4 +2068,997 @@
      PTR p ATTRIBUTE_UNUSED;
 {
   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 (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", 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.  */
+	  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
+    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 (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;
+}
+
+/* Convert the visibility value into a human readable name.  */
+
+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;
 }
Index: NEWS
===================================================================
RCS file: /cvs/src/src/binutils/NEWS,v
retrieving revision 1.37
diff -u -r1.37 NEWS
--- NEWS	26 Jun 2003 08:14:10 -0000	1.37
+++ NEWS	21 Jul 2003 19:31:52 -0000
@@ -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
Index: doc/binutils.texi
===================================================================
RCS file: /cvs/src/src/binutils/doc/binutils.texi,v
retrieving revision 1.44
diff -u -r1.44 binutils.texi
--- doc/binutils.texi	18 Jul 2003 11:34:41 -0000	1.44
+++ doc/binutils.texi	21 Jul 2003 19:31:53 -0000
@@ -1435,6 +1435,7 @@
         [@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 @@
 
 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
@@ -1535,6 +1536,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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]