| /* DWARF 2 debugging format support for GDB. | 
 |  | 
 |    Copyright (C) 1994-2021 Free Software Foundation, Inc. | 
 |  | 
 |    Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, | 
 |    Inc.  with support from Florida State University (under contract | 
 |    with the Ada Joint Program Office), and Silicon Graphics, Inc. | 
 |    Initial contribution by Brent Benson, Harris Computer Systems, Inc., | 
 |    based on Fred Fish's (Cygnus Support) implementation of DWARF 1 | 
 |    support. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "defs.h" | 
 | #include "dwarf2/comp-unit-head.h" | 
 | #include "dwarf2/leb.h" | 
 | #include "dwarf2/read.h" | 
 | #include "dwarf2/section.h" | 
 | #include "dwarf2/stringify.h" | 
 |  | 
 | /* See comp-unit-head.h.  */ | 
 |  | 
 | const gdb_byte * | 
 | read_comp_unit_head (struct comp_unit_head *cu_header, | 
 | 		     const gdb_byte *info_ptr, | 
 | 		     struct dwarf2_section_info *section, | 
 | 		     rcuh_kind section_kind) | 
 | { | 
 |   int signed_addr; | 
 |   unsigned int bytes_read; | 
 |   const char *filename = section->get_file_name (); | 
 |   bfd *abfd = section->get_bfd_owner (); | 
 |  | 
 |   cu_header->length = read_initial_length (abfd, info_ptr, &bytes_read); | 
 |   cu_header->initial_length_size = bytes_read; | 
 |   cu_header->offset_size = (bytes_read == 4) ? 4 : 8; | 
 |   info_ptr += bytes_read; | 
 |   unsigned version = read_2_bytes (abfd, info_ptr); | 
 |   if (version < 2 || version > 5) | 
 |     error (_("Dwarf Error: wrong version in compilation unit header " | 
 | 	   "(is %d, should be 2, 3, 4 or 5) [in module %s]"), | 
 | 	   version, filename); | 
 |   cu_header->version = version; | 
 |   info_ptr += 2; | 
 |   if (cu_header->version < 5) | 
 |     switch (section_kind) | 
 |       { | 
 |       case rcuh_kind::COMPILE: | 
 | 	cu_header->unit_type = DW_UT_compile; | 
 | 	break; | 
 |       case rcuh_kind::TYPE: | 
 | 	cu_header->unit_type = DW_UT_type; | 
 | 	break; | 
 |       default: | 
 | 	internal_error (__FILE__, __LINE__, | 
 | 			_("read_comp_unit_head: invalid section_kind")); | 
 |       } | 
 |   else | 
 |     { | 
 |       cu_header->unit_type = static_cast<enum dwarf_unit_type> | 
 | 						 (read_1_byte (abfd, info_ptr)); | 
 |       info_ptr += 1; | 
 |       switch (cu_header->unit_type) | 
 | 	{ | 
 | 	case DW_UT_compile: | 
 | 	case DW_UT_partial: | 
 | 	case DW_UT_skeleton: | 
 | 	case DW_UT_split_compile: | 
 | 	  if (section_kind != rcuh_kind::COMPILE) | 
 | 	    error (_("Dwarf Error: wrong unit_type in compilation unit header " | 
 | 		   "(is %s, should be %s) [in module %s]"), | 
 | 		   dwarf_unit_type_name (cu_header->unit_type), | 
 | 		   dwarf_unit_type_name (DW_UT_type), filename); | 
 | 	  break; | 
 | 	case DW_UT_type: | 
 | 	case DW_UT_split_type: | 
 | 	  section_kind = rcuh_kind::TYPE; | 
 | 	  break; | 
 | 	default: | 
 | 	  error (_("Dwarf Error: wrong unit_type in compilation unit header " | 
 | 		 "(is %#04x, should be one of: %s, %s, %s, %s or %s) " | 
 | 		 "[in module %s]"), cu_header->unit_type, | 
 | 		 dwarf_unit_type_name (DW_UT_compile), | 
 | 		 dwarf_unit_type_name (DW_UT_skeleton), | 
 | 		 dwarf_unit_type_name (DW_UT_split_compile), | 
 | 		 dwarf_unit_type_name (DW_UT_type), | 
 | 		 dwarf_unit_type_name (DW_UT_split_type), filename); | 
 | 	} | 
 |  | 
 |       cu_header->addr_size = read_1_byte (abfd, info_ptr); | 
 |       info_ptr += 1; | 
 |     } | 
 |   cu_header->abbrev_sect_off | 
 |     = (sect_offset) cu_header->read_offset (abfd, info_ptr, &bytes_read); | 
 |   info_ptr += bytes_read; | 
 |   if (cu_header->version < 5) | 
 |     { | 
 |       cu_header->addr_size = read_1_byte (abfd, info_ptr); | 
 |       info_ptr += 1; | 
 |     } | 
 |   signed_addr = bfd_get_sign_extend_vma (abfd); | 
 |   if (signed_addr < 0) | 
 |     internal_error (__FILE__, __LINE__, | 
 | 		    _("read_comp_unit_head: dwarf from non elf file")); | 
 |   cu_header->signed_addr_p = signed_addr; | 
 |  | 
 |   bool header_has_signature = section_kind == rcuh_kind::TYPE | 
 |     || cu_header->unit_type == DW_UT_skeleton | 
 |     || cu_header->unit_type == DW_UT_split_compile; | 
 |  | 
 |   if (header_has_signature) | 
 |     { | 
 |       cu_header->signature = read_8_bytes (abfd, info_ptr); | 
 |       info_ptr += 8; | 
 |     } | 
 |  | 
 |   if (section_kind == rcuh_kind::TYPE) | 
 |     { | 
 |       LONGEST type_offset; | 
 |       type_offset = cu_header->read_offset (abfd, info_ptr, &bytes_read); | 
 |       info_ptr += bytes_read; | 
 |       cu_header->type_cu_offset_in_tu = (cu_offset) type_offset; | 
 |       if (to_underlying (cu_header->type_cu_offset_in_tu) != type_offset) | 
 | 	error (_("Dwarf Error: Too big type_offset in compilation unit " | 
 | 	       "header (is %s) [in module %s]"), plongest (type_offset), | 
 | 	       filename); | 
 |     } | 
 |  | 
 |   return info_ptr; | 
 | } | 
 |  | 
 | /* Subroutine of read_and_check_comp_unit_head and | 
 |    read_and_check_type_unit_head to simplify them. | 
 |    Perform various error checking on the header.  */ | 
 |  | 
 | static void | 
 | error_check_comp_unit_head (dwarf2_per_objfile *per_objfile, | 
 | 			    struct comp_unit_head *header, | 
 | 			    struct dwarf2_section_info *section, | 
 | 			    struct dwarf2_section_info *abbrev_section) | 
 | { | 
 |   const char *filename = section->get_file_name (); | 
 |  | 
 |   if (to_underlying (header->abbrev_sect_off) | 
 |       >= abbrev_section->get_size (per_objfile->objfile)) | 
 |     error (_("Dwarf Error: bad offset (%s) in compilation unit header " | 
 | 	   "(offset %s + 6) [in module %s]"), | 
 | 	   sect_offset_str (header->abbrev_sect_off), | 
 | 	   sect_offset_str (header->sect_off), | 
 | 	   filename); | 
 |  | 
 |   /* Cast to ULONGEST to use 64-bit arithmetic when possible to | 
 |      avoid potential 32-bit overflow.  */ | 
 |   if (((ULONGEST) header->sect_off + header->get_length ()) | 
 |       > section->size) | 
 |     error (_("Dwarf Error: bad length (0x%x) in compilation unit header " | 
 | 	   "(offset %s + 0) [in module %s]"), | 
 | 	   header->length, sect_offset_str (header->sect_off), | 
 | 	   filename); | 
 | } | 
 |  | 
 | /* See comp-unit-head.h.  */ | 
 |  | 
 | const gdb_byte * | 
 | read_and_check_comp_unit_head (dwarf2_per_objfile *per_objfile, | 
 | 			       struct comp_unit_head *header, | 
 | 			       struct dwarf2_section_info *section, | 
 | 			       struct dwarf2_section_info *abbrev_section, | 
 | 			       const gdb_byte *info_ptr, | 
 | 			       rcuh_kind section_kind) | 
 | { | 
 |   const gdb_byte *beg_of_comp_unit = info_ptr; | 
 |  | 
 |   header->sect_off = (sect_offset) (beg_of_comp_unit - section->buffer); | 
 |  | 
 |   info_ptr = read_comp_unit_head (header, info_ptr, section, section_kind); | 
 |  | 
 |   header->first_die_cu_offset = (cu_offset) (info_ptr - beg_of_comp_unit); | 
 |  | 
 |   error_check_comp_unit_head (per_objfile, header, section, abbrev_section); | 
 |  | 
 |   return info_ptr; | 
 | } | 
 |  | 
 | CORE_ADDR | 
 | comp_unit_head::read_address (bfd *abfd, const gdb_byte *buf, | 
 | 			      unsigned int *bytes_read) const | 
 | { | 
 |   CORE_ADDR retval = 0; | 
 |  | 
 |   if (signed_addr_p) | 
 |     { | 
 |       switch (addr_size) | 
 | 	{ | 
 | 	case 2: | 
 | 	  retval = bfd_get_signed_16 (abfd, buf); | 
 | 	  break; | 
 | 	case 4: | 
 | 	  retval = bfd_get_signed_32 (abfd, buf); | 
 | 	  break; | 
 | 	case 8: | 
 | 	  retval = bfd_get_signed_64 (abfd, buf); | 
 | 	  break; | 
 | 	default: | 
 | 	  internal_error (__FILE__, __LINE__, | 
 | 			  _("read_address: bad switch, signed [in module %s]"), | 
 | 			  bfd_get_filename (abfd)); | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       switch (addr_size) | 
 | 	{ | 
 | 	case 2: | 
 | 	  retval = bfd_get_16 (abfd, buf); | 
 | 	  break; | 
 | 	case 4: | 
 | 	  retval = bfd_get_32 (abfd, buf); | 
 | 	  break; | 
 | 	case 8: | 
 | 	  retval = bfd_get_64 (abfd, buf); | 
 | 	  break; | 
 | 	default: | 
 | 	  internal_error (__FILE__, __LINE__, | 
 | 			  _("read_address: bad switch, " | 
 | 			    "unsigned [in module %s]"), | 
 | 			  bfd_get_filename (abfd)); | 
 | 	} | 
 |     } | 
 |  | 
 |   *bytes_read = addr_size; | 
 |   return retval; | 
 | } |