RFA: Read Dwarf 2 preprocessor macro info

Jim Blandy jimb@redhat.com
Thu May 9 13:02:00 GMT 2002


2002-05-09  Jim Blandy  <jimb@redhat.com>

	Teach the Dwarf 2 reader to read macro information.
	* dwarf2read.c: #include "macrotab.h".
	(dwarf_macinfo_buffer): New variable.
	(struct dwarf2_pinfo): New members: dwarf_macinfo_buffer, and
	dwarf_macinfo_size.
	(DWARF_MACINFO_BUFFER, DWARF_MACINFO_SIZE): New macros.
	(dwarf2_missing_macinfo_section, dwarf2_macros_too_long,
	dwarf2_macros_not_terminated, dwarf2_macro_outside_file,
	dwarf2_macro_unmatched_end_file, dwarf2_macro_malformed_definition,
	dwarf2_macro_spaces_in_definition): New complaints.
	(dwarf2_has_info): Initialize dwarf_macinfo_offset.
	(dwarf2_build_psymtabs): Read the .dwarf_macinfo section.
	(dwarf2_build_psymtabs_hard): Record the buffer and its size in
	the partial symbol table.
	(psymtab_to_symtab_1): Set the macinfo buffer and size globals
	from what's recorded in the partial symbol table.
	(read_file_scope): If the compilation unit has a
	`DW_AT_macro_info' attribute, read its macro information.
	* Makefile.in (dwarf2read.o): Depend on macrotab.h.

Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.180.2.5
diff -c -r1.180.2.5 Makefile.in
*** gdb/Makefile.in	9 May 2002 18:47:13 -0000	1.180.2.5
--- gdb/Makefile.in	9 May 2002 19:43:15 -0000
***************
*** 1415,1421 ****
  
  dwarf2read.o: dwarf2read.c $(bfd_h) $(buildsym_h) $(defs_h) \
  	$(expression_h) $(gdbtypes_h) $(language_h) $(objfiles_h) \
! 	$(symfile_h) $(symtab_h) $(gdb_string_h)
  
  elfread.o: elfread.c $(bfd_h) $(buildsym_h) $(complaints_h) $(defs_h) \
  	$(gdb_stabs_h) $(objfiles_h) $(symfile_h) $(symtab_h) $(gdb_string_h) \
--- 1415,1421 ----
  
  dwarf2read.o: dwarf2read.c $(bfd_h) $(buildsym_h) $(defs_h) \
  	$(expression_h) $(gdbtypes_h) $(language_h) $(objfiles_h) \
! 	$(symfile_h) $(symtab_h) $(gdb_string_h) $(macrotab_h)
  
  elfread.o: elfread.c $(bfd_h) $(buildsym_h) $(complaints_h) $(defs_h) \
  	$(gdb_stabs_h) $(objfiles_h) $(symfile_h) $(symtab_h) $(gdb_string_h) \
Index: gdb/dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.54
diff -c -r1.54 dwarf2read.c
*** gdb/dwarf2read.c	6 May 2002 21:00:20 -0000	1.54
--- gdb/dwarf2read.c	9 May 2002 19:43:17 -0000
***************
*** 37,42 ****
--- 37,43 ----
  #include "demangle.h"
  #include "expression.h"
  #include "filenames.h"	/* for DOSish file names */
+ #include "macrotab.h"
  
  #include "language.h"
  #include "complaints.h"
***************
*** 350,355 ****
--- 351,357 ----
  static char *dwarf_abbrev_buffer;
  static char *dwarf_line_buffer;
  static char *dwarf_str_buffer;
+ static char *dwarf_macinfo_buffer;
  
  /* A zeroed version of a partial die for initialization purposes.  */
  static struct partial_die_info zeroed_partial_die;
***************
*** 439,444 ****
--- 441,455 ----
      /* Size of dwarf string section for the objfile.  */
  
      unsigned int dwarf_str_size;
+ 
+     /* Pointer to start of dwarf macro buffer for the objfile.  */
+ 
+     char *dwarf_macinfo_buffer;
+ 
+     /* Size of dwarf macinfo section for the objfile.  */
+     
+     unsigned int dwarf_macinfo_size;
+ 
    };
  
  #define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
***************
*** 449,454 ****
--- 460,467 ----
  #define DWARF_LINE_BUFFER(p) (PST_PRIVATE(p)->dwarf_line_buffer)
  #define DWARF_STR_BUFFER(p)  (PST_PRIVATE(p)->dwarf_str_buffer)
  #define DWARF_STR_SIZE(p)    (PST_PRIVATE(p)->dwarf_str_size)
+ #define DWARF_MACINFO_BUFFER(p) (PST_PRIVATE(p)->dwarf_macinfo_buffer)
+ #define DWARF_MACINFO_SIZE(p)   (PST_PRIVATE(p)->dwarf_macinfo_size)
  
  /* Maintain an array of referenced fundamental types for the current
     compilation unit being read.  For DWARF version 1, we have to construct
***************
*** 612,617 ****
--- 625,658 ----
  {
    "line number info header doesn't fit in `.debug_line' section", 0, 0
  };
+ static struct complaint dwarf2_missing_macinfo_section =
+ {
+   "missing .debug_macinfo section", 0, 0
+ };
+ static struct complaint dwarf2_macros_too_long =
+ {
+   "macro info runs off end of `.debug_macinfo' section", 0, 0
+ };
+ static struct complaint dwarf2_macros_not_terminated =
+ {
+   "no terminating 0-type entry for macros in `.debug_macinfo' section", 0, 0
+ };
+ static struct complaint dwarf2_macro_outside_file =
+ {
+   "debug info gives macro %s outside of any file: %s", 0, 0
+ };
+ static struct complaint dwarf2_macro_unmatched_end_file =
+ {
+   "macro debug info has an unmatched `close_file' directive", 0, 0
+ };
+ static struct complaint dwarf2_macro_malformed_definition =
+ {
+   "macro debug info contains a malformed macro definition:\n`%s'", 0, 0
+ };
+ static struct complaint dwarf2_macro_spaces_in_definition =
+ {
+   "macro definition contains spaces in formal argument list:\n`%s'", 0, 0
+ };
  
  /* local function prototypes */
  
***************
*** 857,871 ****
  
  static void add_to_cu_func_list (const char *, CORE_ADDR, CORE_ADDR);
  
  /* Try to locate the sections we need for DWARF 2 debugging
     information and return true if we have enough to do something.  */
  
  int
  dwarf2_has_info (bfd *abfd)
  {
!   dwarf_info_offset = dwarf_abbrev_offset = dwarf_line_offset = 0;
    dwarf_str_offset = 0;
!   dwarf_frame_offset = dwarf_eh_frame_offset = 0;
    bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
    if (dwarf_info_offset && dwarf_abbrev_offset)
      {
--- 898,920 ----
  
  static void add_to_cu_func_list (const char *, CORE_ADDR, CORE_ADDR);
  
+ static void dwarf_decode_macros (struct line_header *, unsigned int,
+                                  char *, bfd *, const struct comp_unit_head *,
+                                  struct objfile *);
+ 
  /* Try to locate the sections we need for DWARF 2 debugging
     information and return true if we have enough to do something.  */
  
  int
  dwarf2_has_info (bfd *abfd)
  {
!   dwarf_info_offset = 0;
!   dwarf_abbrev_offset = 0;
!   dwarf_line_offset = 0;
    dwarf_str_offset = 0;
!   dwarf_macinfo_offset = 0;
!   dwarf_frame_offset = 0;
!   dwarf_eh_frame_offset = 0;
    bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
    if (dwarf_info_offset && dwarf_abbrev_offset)
      {
***************
*** 961,966 ****
--- 1010,1022 ----
    else
      dwarf_str_buffer = NULL;
  
+   if (dwarf_macinfo_offset)
+     dwarf_macinfo_buffer = dwarf2_read_section (objfile,
+                                                 dwarf_macinfo_offset,
+                                                 dwarf_macinfo_size);
+   else
+     dwarf_macinfo_buffer = NULL;
+ 
    if (mainline
        || (objfile->global_psymbols.size == 0
  	  && objfile->static_psymbols.size == 0))
***************
*** 1168,1173 ****
--- 1224,1231 ----
        DWARF_LINE_BUFFER (pst) = dwarf_line_buffer;
        DWARF_STR_BUFFER (pst) = dwarf_str_buffer;
        DWARF_STR_SIZE (pst) = dwarf_str_size;
+       DWARF_MACINFO_BUFFER (pst) = dwarf_macinfo_buffer;
+       DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size;
        baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
  
        /* Store the function that reads in the rest of the symbol table */
***************
*** 1469,1474 ****
--- 1527,1534 ----
    dwarf_line_buffer = DWARF_LINE_BUFFER (pst);
    dwarf_str_buffer = DWARF_STR_BUFFER (pst);
    dwarf_str_size = DWARF_STR_SIZE (pst);
+   dwarf_macinfo_buffer = DWARF_MACINFO_BUFFER (pst);
+   dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst);
    baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
    cu_header_offset = offset;
    info_ptr = dwarf_info_buffer + offset;
***************
*** 1731,1736 ****
--- 1791,1807 ----
          }
      }
  
+   /* Decode macro information, if present.  Dwarf 2 macro information
+      refers to information in the line number info statement program
+      header, so we can only read it if we've read the header
+      successfully.  */
+   attr = dwarf_attr (die, DW_AT_macro_info);
+   if (attr)
+     {
+       unsigned int macro_offset = DW_UNSND (attr);
+       dwarf_decode_macros (line_header, macro_offset,
+                            comp_dir, abfd, cu_header, objfile);
+     }
    do_cleanups (back_to);
  }
  
***************
*** 6361,6364 ****
--- 6432,6808 ----
    die = (struct die_info *) xmalloc (sizeof (struct die_info));
    memset (die, 0, sizeof (struct die_info));
    return (die);
+ }
+ 
+ 
+ /* Macro support.  */
+ 
+ 
+ /* Return the full name of file number I in *LH's file name table.
+    Use COMP_DIR as the name of the current directory of the
+    compilation.  The result is allocated using xmalloc; the caller is
+    responsible for freeing it.  */
+ static char *
+ file_full_name (int file, struct line_header *lh, const char *comp_dir)
+ {
+   struct file_entry *fe = &lh->file_names[file - 1];
+   
+   if (IS_ABSOLUTE_PATH (fe->name))
+     return xstrdup (fe->name);
+   else
+     {
+       const char *dir;
+       int dir_len;
+       char *full_name;
+ 
+       if (fe->dir_index)
+         dir = lh->include_dirs[fe->dir_index - 1];
+       else
+         dir = comp_dir;
+ 
+       if (dir)
+         {
+           dir_len = strlen (dir);
+           full_name = xmalloc (dir_len + 1 + strlen (fe->name) + 1);
+           strcpy (full_name, dir);
+           full_name[dir_len] = '/';
+           strcpy (full_name + dir_len + 1, fe->name);
+           return full_name;
+         }
+       else
+         return xstrdup (fe->name);
+     }
+ }
+ 
+ 
+ static struct macro_source_file *
+ macro_start_file (int file, int line,
+                   struct macro_source_file *current_file,
+                   const char *comp_dir,
+                   struct line_header *lh, struct objfile *objfile)
+ {
+   /* The full name of this source file.  */
+   char *full_name = file_full_name (file, lh, comp_dir);
+ 
+   /* We don't create a macro table for this compilation unit
+      at all until we actually get a filename.  */
+   if (! pending_macros)
+     pending_macros = new_macro_table (&objfile->symbol_obstack,
+                                       &objfile->macro_cache);
+ 
+   if (! current_file)
+     /* If we have no current file, then this must be the start_file
+        directive for the compilation unit's main source file.  */
+     current_file = macro_set_main (pending_macros, full_name);
+   else
+     current_file = macro_include (current_file, line, full_name);
+ 
+   xfree (full_name);
+               
+   return current_file;
+ }
+ 
+ 
+ /* Copy the LEN characters at BUF to a xmalloc'ed block of memory,
+    followed by a null byte.  */
+ static char *
+ copy_string (const char *buf, int len)
+ {
+   char *s = xmalloc (len + 1);
+   memcpy (s, buf, len);
+   s[len] = '\0';
+ 
+   return s;
+ }
+ 
+ 
+ static const char *
+ consume_improper_spaces (const char *p, const char *body)
+ {
+   if (*p == ' ')
+     {
+       complain (&dwarf2_macro_spaces_in_definition, body);
+ 
+       while (*p == ' ')
+         p++;
+     }
+ 
+   return p;
+ }
+ 
+ 
+ static void
+ parse_macro_definition (struct macro_source_file *file, int line,
+                         const char *body)
+ {
+   const char *p;
+ 
+   /* The body string takes one of two forms.  For object-like macro
+      definitions, it should be:
+ 
+         <macro name> " " <definition>
+ 
+      For function-like macro definitions, it should be:
+ 
+         <macro name> "() " <definition>
+      or
+         <macro name> "(" <arg name> ( "," <arg name> ) * ") " <definition>
+ 
+      Spaces may appear only where explicitly indicated, and in the
+      <definition>.
+ 
+      The Dwarf 2 spec says that an object-like macro's name is always
+      followed by a space, but versions of GCC around March 2002 omit
+      the space when the macro's definition is the empty string. 
+ 
+      The Dwarf 2 spec says that there should be no spaces between the
+      formal arguments in a function-like macro's formal argument list,
+      but versions of GCC around March 2002 include spaces after the
+      commas.  */
+ 
+ 
+   /* Find the extent of the macro name.  The macro name is terminated
+      by either a space or null character (for an object-like macro) or
+      an opening paren (for a function-like macro).  */
+   for (p = body; *p; p++)
+     if (*p == ' ' || *p == '(')
+       break;
+ 
+   if (*p == ' ' || *p == '\0')
+     {
+       /* It's an object-like macro.  */
+       int name_len = p - body;
+       char *name = copy_string (body, name_len);
+       const char *replacement;
+ 
+       if (*p == ' ')
+         replacement = body + name_len + 1;
+       else
+         {
+           complain (&dwarf2_macro_malformed_definition, body);
+           replacement = body + name_len;
+         }
+       
+       macro_define_object (file, line, name, replacement);
+ 
+       xfree (name);
+     }
+   else if (*p == '(')
+     {
+       /* It's a function-like macro.  */
+       char *name = copy_string (body, p - body);
+       int argc = 0;
+       int argv_size = 1;
+       char **argv = xmalloc (argv_size * sizeof (*argv));
+ 
+       p++;
+ 
+       p = consume_improper_spaces (p, body);
+ 
+       /* Parse the formal argument list.  */
+       while (*p && *p != ')')
+         {
+           /* Find the extent of the current argument name.  */
+           const char *arg_start = p;
+ 
+           while (*p && *p != ',' && *p != ')' && *p != ' ')
+             p++;
+ 
+           if (! *p || p == arg_start)
+             complain (&dwarf2_macro_malformed_definition,
+                       body);
+           else
+             {
+               /* Make sure argv has room for the new argument.  */
+               if (argc >= argv_size)
+                 {
+                   argv_size *= 2;
+                   argv = xrealloc (argv, argv_size * sizeof (*argv));
+                 }
+ 
+               argv[argc++] = copy_string (arg_start, p - arg_start);
+             }
+ 
+           p = consume_improper_spaces (p, body);
+ 
+           /* Consume the comma, if present.  */
+           if (*p == ',')
+             {
+               p++;
+ 
+               p = consume_improper_spaces (p, body);
+             }
+         }
+ 
+       if (*p == ')')
+         {
+           p++;
+ 
+           if (*p == ' ')
+             /* Perfectly formed definition, no complaints.  */
+             macro_define_function (file, line, name,
+                                    argc, (const char **) argv, 
+                                    p + 1);
+           else if (*p == '\0')
+             {
+               /* Complain, but do define it.  */
+               complain (&dwarf2_macro_malformed_definition, body);
+               macro_define_function (file, line, name,
+                                      argc, (const char **) argv, 
+                                      p);
+             }
+           else
+             /* Just complain.  */
+             complain (&dwarf2_macro_malformed_definition, body);
+         }
+       else
+         /* Just complain.  */
+         complain (&dwarf2_macro_malformed_definition, body);
+ 
+       xfree (name);
+       {
+         int i;
+ 
+         for (i = 0; i < argc; i++)
+           xfree (argv[i]);
+       }
+       xfree (argv);
+     }
+   else
+     complain (&dwarf2_macro_malformed_definition, body);
+ }
+ 
+ 
+ static void
+ dwarf_decode_macros (struct line_header *lh, unsigned int offset,
+                      char *comp_dir, bfd *abfd,
+                      const struct comp_unit_head *cu_header,
+                      struct objfile *objfile)
+ {
+   char *mac_ptr, *mac_end;
+   struct macro_source_file *current_file = 0;
+ 
+   if (dwarf_macinfo_buffer == NULL)
+     {
+       complain (&dwarf2_missing_macinfo_section);
+       return;
+     }
+ 
+   mac_ptr = dwarf_macinfo_buffer + offset;
+   mac_end = dwarf_macinfo_buffer + dwarf_macinfo_size;
+ 
+   for (;;)
+     {
+       enum dwarf_macinfo_record_type macinfo_type;
+ 
+       /* Do we at least have room for a macinfo type byte?  */
+       if (mac_ptr >= mac_end)
+         {
+           complain (&dwarf2_macros_too_long);
+           return;
+         }
+ 
+       macinfo_type = read_1_byte (abfd, mac_ptr);
+       mac_ptr++;
+ 
+       switch (macinfo_type)
+         {
+           /* A zero macinfo type indicates the end of the macro
+              information.  */
+         case 0:
+           return;
+ 
+         case DW_MACINFO_define:
+         case DW_MACINFO_undef:
+           {
+             int bytes_read;
+             int line;
+             char *body;
+ 
+             line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+             mac_ptr += bytes_read;
+             body = read_string (abfd, mac_ptr, &bytes_read);
+             mac_ptr += bytes_read;
+ 
+             if (! current_file)
+               complain (&dwarf2_macro_outside_file,
+                         macinfo_type == DW_MACINFO_define ? "definition" :
+                         macinfo_type == DW_MACINFO_undef ? "undefinition" :
+                         "something-or-other",
+                         body);
+             else
+               {
+                 if (macinfo_type == DW_MACINFO_define)
+                   parse_macro_definition (current_file, line, body);
+                 else if (macinfo_type == DW_MACINFO_undef)
+                   macro_undef (current_file, line, body);
+               }
+           }
+           break;
+ 
+         case DW_MACINFO_start_file:
+           {
+             int bytes_read;
+             int line, file;
+ 
+             line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+             mac_ptr += bytes_read;
+             file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+             mac_ptr += bytes_read;
+ 
+             current_file = macro_start_file (file, line,
+                                              current_file, comp_dir,
+                                              lh, objfile);
+           }
+           break;
+ 
+         case DW_MACINFO_end_file:
+           if (! current_file)
+             complain (&dwarf2_macro_unmatched_end_file);
+           else
+             {
+               current_file = current_file->included_by;
+               if (! current_file)
+                 {
+                   enum dwarf_macinfo_record_type next_type;
+ 
+                   /* GCC circa March 2002 doesn't produce the zero
+                      type byte marking the end of the compilation
+                      unit.  Complain if it's not there, but exit no
+                      matter what.  */
+ 
+                   /* Do we at least have room for a macinfo type byte?  */
+                   if (mac_ptr >= mac_end)
+                     {
+                       complain (&dwarf2_macros_too_long);
+                       return;
+                     }
+ 
+                   /* We don't increment mac_ptr here, so this is just
+                      a look-ahead.  */
+                   next_type = read_1_byte (abfd, mac_ptr);
+                   if (next_type != 0)
+                     complain (&dwarf2_macros_not_terminated);
+ 
+                   return;
+                 }
+             }
+           break;
+ 
+         case DW_MACINFO_vendor_ext:
+           {
+             int bytes_read;
+             int constant;
+             char *string;
+ 
+             constant = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+             mac_ptr += bytes_read;
+             string = read_string (abfd, mac_ptr, &bytes_read);
+             mac_ptr += bytes_read;
+ 
+             /* We don't recognize any vendor extensions.  */
+           }
+           break;
+         }
+     }
  }



More information about the Gdb-patches mailing list