Home | History | Annotate | Line # | Download | only in dwarf2
      1 /* DWARF aranges handling
      2 
      3    Copyright (C) 1994-2024 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 #include "dwarf2/aranges.h"
     21 #include "dwarf2/read.h"
     22 
     23 /* See aranges.h.  */
     24 
     25 bool
     26 read_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
     27 			   dwarf2_section_info *section,
     28 			   addrmap_mutable *mutable_map,
     29 			   deferred_warnings *warn)
     30 {
     31   /* Caller must ensure that the section has already been read.  */
     32   gdb_assert (section->readin);
     33   if (section->empty ())
     34     return false;
     35 
     36   struct objfile *objfile = per_objfile->objfile;
     37   bfd *abfd = objfile->obfd.get ();
     38   struct gdbarch *gdbarch = objfile->arch ();
     39   dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
     40 
     41   std::unordered_map<sect_offset,
     42 		     dwarf2_per_cu_data *,
     43 		     gdb::hash_enum<sect_offset>>
     44     debug_info_offset_to_per_cu;
     45   for (const auto &per_cu : per_bfd->all_units)
     46     {
     47       /* A TU will not need aranges, and skipping them here is an easy
     48 	 way of ignoring .debug_types -- and possibly seeing a
     49 	 duplicate section offset -- entirely.  The same applies to
     50 	 units coming from a dwz file.  */
     51       if (per_cu->is_debug_types || per_cu->is_dwz)
     52 	continue;
     53 
     54       const auto insertpair
     55 	= debug_info_offset_to_per_cu.emplace (per_cu->sect_off,
     56 					       per_cu.get ());
     57 
     58       /* Assume no duplicate offsets in all_units.  */
     59       gdb_assert (insertpair.second);
     60     }
     61 
     62   std::set<sect_offset> debug_info_offset_seen;
     63   const bfd_endian dwarf5_byte_order = gdbarch_byte_order (gdbarch);
     64   const gdb_byte *addr = section->buffer;
     65   while (addr < section->buffer + section->size)
     66     {
     67       const gdb_byte *const entry_addr = addr;
     68       unsigned int bytes_read;
     69 
     70       const LONGEST entry_length = read_initial_length (abfd, addr,
     71 							&bytes_read);
     72       addr += bytes_read;
     73 
     74       const gdb_byte *const entry_end = addr + entry_length;
     75       const bool dwarf5_is_dwarf64 = bytes_read != 4;
     76       const uint8_t offset_size = dwarf5_is_dwarf64 ? 8 : 4;
     77       if (addr + entry_length > section->buffer + section->size)
     78 	{
     79 	  warn->warn (_("Section .debug_aranges in %s entry at offset %s "
     80 			"length %s exceeds section length %s, "
     81 			"ignoring .debug_aranges."),
     82 		      objfile_name (objfile),
     83 		      plongest (entry_addr - section->buffer),
     84 		      plongest (bytes_read + entry_length),
     85 		      pulongest (section->size));
     86 	  return false;
     87 	}
     88 
     89       /* The version number.  */
     90       const uint16_t version = read_2_bytes (abfd, addr);
     91       addr += 2;
     92       if (version != 2)
     93 	{
     94 	  warn->warn
     95 	    (_("Section .debug_aranges in %s entry at offset %s "
     96 	       "has unsupported version %d, ignoring .debug_aranges."),
     97 	     objfile_name (objfile),
     98 	     plongest (entry_addr - section->buffer), version);
     99 	  return false;
    100 	}
    101 
    102       const uint64_t debug_info_offset
    103 	= extract_unsigned_integer (addr, offset_size, dwarf5_byte_order);
    104       addr += offset_size;
    105       const auto per_cu_it
    106 	= debug_info_offset_to_per_cu.find (sect_offset (debug_info_offset));
    107       if (per_cu_it == debug_info_offset_to_per_cu.cend ())
    108 	{
    109 	  warn->warn (_("Section .debug_aranges in %s entry at offset %s "
    110 			"debug_info_offset %s does not exists, "
    111 			"ignoring .debug_aranges."),
    112 		      objfile_name (objfile),
    113 		      plongest (entry_addr - section->buffer),
    114 		      pulongest (debug_info_offset));
    115 	  return false;
    116 	}
    117       const auto insertpair
    118 	= debug_info_offset_seen.insert (sect_offset (debug_info_offset));
    119       if (!insertpair.second)
    120 	{
    121 	  warn->warn (_("Section .debug_aranges in %s has duplicate "
    122 			"debug_info_offset %s, ignoring .debug_aranges."),
    123 		      objfile_name (objfile),
    124 		      sect_offset_str (sect_offset (debug_info_offset)));
    125 	  return false;
    126 	}
    127       dwarf2_per_cu_data *const per_cu = per_cu_it->second;
    128 
    129       const uint8_t address_size = *addr++;
    130       if (address_size < 1 || address_size > 8)
    131 	{
    132 	  warn->warn
    133 	    (_("Section .debug_aranges in %s entry at offset %s "
    134 	       "address_size %u is invalid, ignoring .debug_aranges."),
    135 	     objfile_name (objfile),
    136 	     plongest (entry_addr - section->buffer), address_size);
    137 	  return false;
    138 	}
    139 
    140       const uint8_t segment_selector_size = *addr++;
    141       if (segment_selector_size != 0)
    142 	{
    143 	  warn->warn (_("Section .debug_aranges in %s entry at offset %s "
    144 			"segment_selector_size %u is not supported, "
    145 			"ignoring .debug_aranges."),
    146 		      objfile_name (objfile),
    147 		      plongest (entry_addr - section->buffer),
    148 		      segment_selector_size);
    149 	  return false;
    150 	}
    151 
    152       /* Must pad to an alignment boundary that is twice the address
    153 	 size.  It is undocumented by the DWARF standard but GCC does
    154 	 use it.  However, not every compiler does this.  We can see
    155 	 whether it has happened by looking at the total length of the
    156 	 contents of the aranges for this CU -- it if isn't a multiple
    157 	 of twice the address size, then we skip any leftover
    158 	 bytes.  */
    159       addr += (entry_end - addr) % (2 * address_size);
    160 
    161       while (addr < entry_end)
    162 	{
    163 	  if (addr + 2 * address_size > entry_end)
    164 	    {
    165 	      warn->warn (_("Section .debug_aranges in %s entry at offset %s "
    166 			    "address list is not properly terminated, "
    167 			    "ignoring .debug_aranges."),
    168 			  objfile_name (objfile),
    169 			  plongest (entry_addr - section->buffer));
    170 	      return false;
    171 	    }
    172 	  ULONGEST start = extract_unsigned_integer (addr, address_size,
    173 						     dwarf5_byte_order);
    174 	  addr += address_size;
    175 	  ULONGEST length = extract_unsigned_integer (addr, address_size,
    176 						      dwarf5_byte_order);
    177 	  addr += address_size;
    178 	  if (start == 0 && length == 0)
    179 	    {
    180 	      /* This can happen on some targets with --gc-sections.
    181 		 This pair of values is also used to mark the end of
    182 		 the entries for a given CU, but we ignore it and
    183 		 instead handle termination using the check at the top
    184 		 of the loop.  */
    185 	      continue;
    186 	    }
    187 	  if (start == 0 && !per_bfd->has_section_at_zero)
    188 	    {
    189 	      /* Symbol was eliminated due to a COMDAT group.  */
    190 	      continue;
    191 	    }
    192 	  ULONGEST end = start + length;
    193 	  mutable_map->set_empty (start, end - 1, per_cu);
    194 	}
    195 
    196       per_cu->addresses_seen = true;
    197     }
    198 
    199   return true;
    200 }
    201