[RFC,2/3] gdb: fix a few spots to not assume that we have a .text section

Message ID 20200519161431.1577904-3-simon.marchi@efficios.com
State New
Headers show
Series
  • What to do with objfiles with no .text section?
Related show

Commit Message

Simon Marchi via Gdb-patches May 19, 2020, 4:14 p.m.
Following the previous patch, it's possible for objfile::sect_index_text
to have the -1 value, if the objfile has no .text section.  Trying to
debug a program that uses such a library leads to failed assertions,
because of using objfile::text_section_offset and SECT_OFF_TEXT.

This patch fixes enough of these spots so that I'm able to do "start"
and "backtrace" a program that uses a library with no .text section, to
illustrate what kinds of fixes would be needed to make GDB not assume
that .text is always present.

In the DWARF reader, sometimes it is enough to move the call to
text_section_offset in a narrower code path.  Sometimes, we need to do a
bit more work to identify the correct section, like in
add_partial_symbol.  In symab functions that do lookup by pc, we need to
skip the objfiles that don't have any text.
---
 gdb/dwarf2/read.c | 175 +++++++++++++++++++++++++++++-----------------
 gdb/objfiles.h    |   3 +-
 gdb/psympriv.h    |  13 ++++
 gdb/psymtab.c     |   7 +-
 gdb/symfile.c     |   7 +-
 5 files changed, 130 insertions(+), 75 deletions(-)

-- 
2.26.2

Patch

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 719051bc5b2f..77bffc2b5e5a 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -7327,7 +7327,6 @@  process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
   struct objfile *objfile = cu->per_cu->dwarf2_per_objfile->objfile;
   struct gdbarch *gdbarch = objfile->arch ();
   struct dwarf2_per_cu_data *per_cu = cu->per_cu;
-  CORE_ADDR baseaddr;
   CORE_ADDR best_lowpc = 0, best_highpc = 0;
   dwarf2_psymtab *pst;
   enum pc_bounds_kind cu_bounds_kind;
@@ -7356,8 +7355,6 @@  process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
   /* This must be done before calling dwarf2_build_include_psymtabs.  */
   pst->dirname = dwarf2_string_attr (comp_unit_die, DW_AT_comp_dir, cu);
 
-  baseaddr = objfile->text_section_offset ();
-
   dwarf2_find_base_address (comp_unit_die, cu);
 
   /* Possibly set the default values of LOWPC and HIGHPC from
@@ -7366,6 +7363,7 @@  process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
 					 &best_highpc, cu, pst);
   if (cu_bounds_kind == PC_BOUNDS_HIGH_LOW && best_lowpc < best_highpc)
     {
+      CORE_ADDR baseaddr = objfile->text_section_offset ();
       CORE_ADDR low
 	= (gdbarch_adjust_dwarf2_addr (gdbarch, best_lowpc + baseaddr)
 	   - baseaddr);
@@ -7407,12 +7405,18 @@  process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
 	  best_highpc = highpc;
 	}
     }
-  pst->set_text_low (gdbarch_adjust_dwarf2_addr (gdbarch,
-						 best_lowpc + baseaddr)
-		     - baseaddr);
-  pst->set_text_high (gdbarch_adjust_dwarf2_addr (gdbarch,
-						  best_highpc + baseaddr)
-		      - baseaddr);
+
+  if (best_lowpc != 0 || best_highpc != 0)
+    {
+      CORE_ADDR baseaddr = objfile->text_section_offset ();
+
+      pst->set_text_low (gdbarch_adjust_dwarf2_addr (gdbarch,
+						     best_lowpc + baseaddr)
+			 - baseaddr);
+      pst->set_text_high (gdbarch_adjust_dwarf2_addr (gdbarch,
+						      best_highpc + baseaddr)
+			  - baseaddr);
+    }
 
   end_psymtab_common (objfile, pst);
 
@@ -8239,6 +8243,27 @@  partial_die_full_name (struct partial_die_info *pdi,
 							   pdi->name, 0, cu));
 }
 
+/* Find in which section of ABFD the address ADDR falls.  Return the index of
+   such section, or -1 if no section matches.  */
+
+static int
+find_bfd_section_for_address (bfd *abfd, CORE_ADDR addr)
+{
+  for (asection *sec = abfd->sections; sec != nullptr; sec = sec->next)
+    {
+      if ((bfd_section_flags (sec) & SEC_ALLOC) == 0)
+	continue;
+
+      CORE_ADDR start = bfd_section_vma (sec);
+      CORE_ADDR end = start + bfd_section_size (sec);
+
+      if (addr >= start && addr < end)
+	return sec->index;
+    }
+
+  return -1;
+}
+
 static void
 add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
 {
@@ -8248,9 +8273,6 @@  add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
   struct gdbarch *gdbarch = objfile->arch ();
   CORE_ADDR addr = 0;
   const char *actual_name = NULL;
-  CORE_ADDR baseaddr;
-
-  baseaddr = objfile->text_section_offset ();
 
   gdb::unique_xmalloc_ptr<char> built_actual_name
     = partial_die_full_name (pdi, cu);
@@ -8273,31 +8295,37 @@  add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
     {
     case DW_TAG_inlined_subroutine:
     case DW_TAG_subprogram:
-      addr = (gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr)
-	      - baseaddr);
-      if (pdi->is_external
-	  || cu->language == language_ada
-	  || (cu->language == language_fortran
-	      && pdi->die_parent != NULL
-	      && pdi->die_parent->tag == DW_TAG_subprogram))
-	{
-          /* Normally, only "external" DIEs are part of the global scope.
-             But in Ada and Fortran, we want to be able to access nested
-             procedures globally.  So all Ada and Fortran subprograms are
-             stored in the global scope.  */
-	  where = psymbol_placement::GLOBAL;
-	}
-      else
-	where = psymbol_placement::STATIC;
+      {
+	CORE_ADDR baseaddr = objfile->text_section_offset ();
+
+	addr = (gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr)
+		- baseaddr);
+	if (pdi->is_external
+	    || cu->language == language_ada
+	    || (cu->language == language_fortran
+		&& pdi->die_parent != NULL
+		&& pdi->die_parent->tag == DW_TAG_subprogram))
+	  {
+	    /* Normally, only "external" DIEs are part of the global scope.
+	       But in Ada and Fortran, we want to be able to access nested
+	       procedures globally.  So all Ada and Fortran subprograms are
+	       stored in the global scope.  */
+	    where = psymbol_placement::GLOBAL;
+	  }
+	else
+	  where = psymbol_placement::STATIC;
 
-      psymbol.domain = VAR_DOMAIN;
-      psymbol.aclass = LOC_BLOCK;
-      psymbol.ginfo.section = SECT_OFF_TEXT (objfile);
-      psymbol.ginfo.value.address = addr;
+	psymbol.domain = VAR_DOMAIN;
+	psymbol.aclass = LOC_BLOCK;
+	psymbol.ginfo.section
+	  = find_bfd_section_for_address (objfile->obfd, addr);
+	psymbol.ginfo.value.address = addr;
+
+	if (pdi->main_subprogram && actual_name != NULL)
+	  set_objfile_main_name (objfile, actual_name, cu->language);
+	break;
+      }
 
-      if (pdi->main_subprogram && actual_name != NULL)
-	set_objfile_main_name (objfile, actual_name, cu->language);
-      break;
     case DW_TAG_constant:
       psymbol.domain = VAR_DOMAIN;
       psymbol.aclass = LOC_STATIC;
@@ -8337,7 +8365,8 @@  add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
 	    {
 	      psymbol.domain = VAR_DOMAIN;
 	      psymbol.aclass = LOC_STATIC;
-	      psymbol.ginfo.section = SECT_OFF_TEXT (objfile);
+	      psymbol.ginfo.section
+		= find_bfd_section_for_address (objfile->obfd, addr);
 	      psymbol.ginfo.value.address = addr;
 	      where = psymbol_placement::GLOBAL;
 	    }
@@ -8353,9 +8382,12 @@  add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
 
 	  psymbol.domain = VAR_DOMAIN;
 	  psymbol.aclass = LOC_STATIC;
-	  psymbol.ginfo.section = SECT_OFF_TEXT (objfile);
 	  if (has_loc)
-	    psymbol.ginfo.value.address = addr;
+	    {
+	      psymbol.ginfo.section
+		= find_bfd_section_for_address (objfile->obfd, addr);
+	      psymbol.ginfo.value.address = addr;
+	    }
 	  where = psymbol_placement::STATIC;
 	}
       break;
@@ -9637,12 +9669,9 @@  process_full_comp_unit (struct dwarf2_per_cu_data *per_cu,
   struct gdbarch *gdbarch = objfile->arch ();
   CORE_ADDR lowpc, highpc;
   struct compunit_symtab *cust;
-  CORE_ADDR baseaddr;
   struct block *static_block;
   CORE_ADDR addr;
 
-  baseaddr = objfile->text_section_offset ();
-
   /* Clear the list here in case something was left over.  */
   cu->method_list.clear ();
 
@@ -9669,18 +9698,30 @@  process_full_comp_unit (struct dwarf2_per_cu_data *per_cu,
      it, by scanning the DIE's below the compilation unit.  */
   get_scope_pc_bounds (cu->dies, &lowpc, &highpc, cu);
 
-  addr = gdbarch_adjust_dwarf2_addr (gdbarch, highpc + baseaddr);
+  if (lowpc != -1 && highpc != 0)
+    {
+      CORE_ADDR baseaddr = objfile->text_section_offset ();
+      addr = gdbarch_adjust_dwarf2_addr (gdbarch, highpc + baseaddr);
+    }
+  else
+    addr = 0;
+
   static_block = cu->get_builder ()->end_symtab_get_static_block (addr, 0, 1);
 
-  /* If the comp unit has DW_AT_ranges, it may have discontiguous ranges.
-     Also, DW_AT_ranges may record ranges not belonging to any child DIEs
-     (such as virtual method tables).  Record the ranges in STATIC_BLOCK's
-     addrmap to help ensure it has an accurate map of pc values belonging to
-     this comp unit.  */
-  dwarf2_record_block_ranges (cu->dies, static_block, baseaddr, cu);
+  if (objfile->sect_index_text != -1)
+    {
+      CORE_ADDR baseaddr = objfile->text_section_offset ();
+
+      /* If the comp unit has DW_AT_ranges, it may have discontiguous ranges.
+	 Also, DW_AT_ranges may record ranges not belonging to any child DIEs
+	 (such as virtual method tables).  Record the ranges in STATIC_BLOCK's
+	 addrmap to help ensure it has an accurate map of pc values belonging to
+	 this comp unit.  */
+      dwarf2_record_block_ranges (cu->dies, static_block, baseaddr, cu);
+    }
 
-  cust = cu->get_builder ()->end_symtab_from_static_block (static_block,
-						    SECT_OFF_TEXT (objfile),
+  cust = cu->get_builder ()->end_symtab_from_static_block
+    (static_block, objfile->sect_index_text != -1 ? SECT_OFF_TEXT (objfile) : -1,
 						    0);
 
   if (cust != NULL)
@@ -10845,18 +10886,18 @@  read_file_scope (struct die_info *die, struct dwarf2_cu *cu)
   CORE_ADDR highpc = ((CORE_ADDR) 0);
   struct attribute *attr;
   struct die_info *child_die;
-  CORE_ADDR baseaddr;
 
   prepare_one_comp_unit (cu, die, cu->language);
-  baseaddr = objfile->text_section_offset ();
 
   get_scope_pc_bounds (die, &lowpc, &highpc, cu);
 
-  /* If we didn't find a lowpc, set it to highpc to avoid complaints
-     from finish_block.  */
-  if (lowpc == ((CORE_ADDR) -1))
-    lowpc = highpc;
-  lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr);
+  if (lowpc != ((CORE_ADDR) -1))
+    {
+      CORE_ADDR baseaddr = objfile->text_section_offset ();
+      lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr);
+    }
+  else
+    lowpc = 0;
 
   file_and_directory fnd = find_file_and_directory (die, cu);
 
@@ -20154,8 +20195,7 @@  static void
 dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu,
 		      const int decode_for_pst_p, CORE_ADDR lowpc)
 {
-  const gdb_byte *line_ptr, *extended_end;
-  const gdb_byte *line_end;
+  const gdb_byte *extended_end;
   unsigned int bytes_read, extended_len;
   unsigned char op_code, extended_op;
   CORE_ADDR baseaddr;
@@ -20167,10 +20207,17 @@  dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu,
      the line number program).  */
   bool record_lines_p = !decode_for_pst_p;
 
-  baseaddr = objfile->text_section_offset ();
+  const gdb_byte *line_ptr = lh->statement_program_start;
+  const gdb_byte *line_end = lh->statement_program_end;
+
+  /* It's possible for the object file to have no .text section (which makes
+     calling objfile->text_section_offset below invalid) and a .debug_line
+     section with an empty line number program.  If so, just return early
+     to avoid calling text_section_offset.  */
+  if (line_ptr == line_end)
+    return;
 
-  line_ptr = lh->statement_program_start;
-  line_end = lh->statement_program_end;
+  baseaddr = objfile->text_section_offset ();
 
   /* Read the statement sequences until there's nothing left.  */
   while (line_ptr < line_end)
@@ -20590,13 +20637,10 @@  new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
   const char *name;
   struct attribute *attr = NULL;
   struct attribute *attr2 = NULL;
-  CORE_ADDR baseaddr;
   struct pending **list_to_add = NULL;
 
   int inlined_func = (die->tag == DW_TAG_inlined_subroutine);
 
-  baseaddr = objfile->text_section_offset ();
-
   name = dwarf2_name (die, cu);
   if (name)
     {
@@ -20668,6 +20712,7 @@  new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
 	  if (attr != nullptr)
 	    {
 	      CORE_ADDR addr;
+	      CORE_ADDR baseaddr = objfile->text_section_offset ();
 
 	      addr = attr->value_as_address ();
 	      addr = gdbarch_adjust_dwarf2_addr (gdbarch, addr + baseaddr);
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index 0b47bd0c1e2f..de495c16ec27 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -114,7 +114,8 @@  struct entry_info
   /* The unrelocated value we should use for this objfile entry point.  */
   CORE_ADDR entry_point;
 
-  /* The index of the section in which the entry point appears.  */
+  /* The index of the section in which the entry point appears.  If -1, we
+     don't know / couldn't find the section.  */
   int the_bfd_section_index;
 
   /* Set to 1 iff ENTRY_POINT contains a valid value.  */
diff --git a/gdb/psympriv.h b/gdb/psympriv.h
index 6f0307e05b78..46e546b61e7e 100644
--- a/gdb/psympriv.h
+++ b/gdb/psympriv.h
@@ -158,24 +158,32 @@  struct partial_symtab
   /* Return the raw low text address of this partial_symtab.  */
   CORE_ADDR raw_text_low () const
   {
+    gdb_assert (text_low_valid);
+
     return m_text_low;
   }
 
   /* Return the raw high text address of this partial_symtab.  */
   CORE_ADDR raw_text_high () const
   {
+    gdb_assert (text_high_valid);
+
     return m_text_high;
   }
 
   /* Return the relocated low text address of this partial_symtab.  */
   CORE_ADDR text_low (struct objfile *objfile) const
   {
+    gdb_assert (text_low_valid);
+
     return m_text_low + objfile->text_section_offset ();
   }
 
   /* Return the relocated high text address of this partial_symtab.  */
   CORE_ADDR text_high (struct objfile *objfile) const
   {
+    gdb_assert (text_high_valid);
+
     return m_text_high + objfile->text_section_offset ();
   }
 
@@ -193,6 +201,11 @@  struct partial_symtab
     text_high_valid = 1;
   }
 
+  /* Return true if this partial symtab has some text (code) parts.  */
+  bool has_text () const
+  {
+    return text_low_valid && text_high_valid;
+  }
 
   /* Chain of all existing partial symtabs.  */
 
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 1fce7a398384..3073cccfa364 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -306,7 +306,8 @@  find_pc_sect_psymtab (struct objfile *objfile, CORE_ADDR pc,
      that is not a partial_symtab, which doesn't end well.  */
 
   if (objfile->partial_symtabs->psymtabs != NULL
-      && objfile->partial_symtabs->psymtabs_addrmap != NULL)
+      && objfile->partial_symtabs->psymtabs_addrmap != NULL
+      && objfile->sect_index_text != -1)
     {
       CORE_ADDR baseaddr = objfile->text_section_offset ();
 
@@ -356,7 +357,7 @@  find_pc_sect_psymtab (struct objfile *objfile, CORE_ADDR pc,
      debug info type in single OBJFILE.  */
 
   for (partial_symtab *pst : require_partial_symbols (objfile, true))
-    if (!pst->psymtabs_addrmap_supported
+    if (!pst->psymtabs_addrmap_supported && pst->has_text ()
 	&& pc >= pst->text_low (objfile) && pc < pst->text_high (objfile))
       {
 	struct partial_symtab *best_pst;
@@ -2127,7 +2128,7 @@  maintenance_check_psymtabs (const char *ignore, int from_tty)
 	cust = ps->get_compunit_symtab ();
 
 	/* First do some checks that don't require the associated symtab.  */
-	if (ps->text_high (objfile) < ps->text_low (objfile))
+	if (ps->has_text () && ps->text_high (objfile) < ps->text_low (objfile))
 	  {
 	    printf_filtered ("Psymtab ");
 	    puts_filtered (ps->filename);
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 62ad704f27d3..63db2bc7875e 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -808,7 +808,6 @@  init_entry_point_info (struct objfile *objfile)
     {
       struct obj_section *osect;
       CORE_ADDR entry_point =  ei->entry_point;
-      int found;
 
       /* Make certain that the address points at real code, and not a
 	 function descriptor.  */
@@ -821,8 +820,8 @@  init_entry_point_info (struct objfile *objfile)
 	 symbol table.  */
       ei->entry_point
 	= gdbarch_addr_bits_remove (objfile->arch (), entry_point);
+      ei->the_bfd_section_index = -1;
 
-      found = 0;
       ALL_OBJFILE_OSECTIONS (objfile, osect)
 	{
 	  struct bfd_section *sect = osect->the_bfd_section;
@@ -833,13 +832,9 @@  init_entry_point_info (struct objfile *objfile)
 	    {
 	      ei->the_bfd_section_index
 		= gdb_bfd_section_index (objfile->obfd, sect);
-	      found = 1;
 	      break;
 	    }
 	}
-
-      if (!found)
-	ei->the_bfd_section_index = SECT_OFF_TEXT (objfile);
     }
 }