| /* DWARF DIEs | 
 |  | 
 |    Copyright (C) 1994-2023 Free Software Foundation, Inc. | 
 |  | 
 |    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/die.h" | 
 | #include "dwarf2/stringify.h" | 
 |  | 
 | /* See die.h.  */ | 
 |  | 
 | struct die_info * | 
 | die_info::allocate (struct obstack *obstack, int num_attrs) | 
 | { | 
 |   size_t size = sizeof (struct die_info); | 
 |  | 
 |   if (num_attrs > 1) | 
 |     size += (num_attrs - 1) * sizeof (struct attribute); | 
 |  | 
 |   struct die_info *die = (struct die_info *) obstack_alloc (obstack, size); | 
 |   memset (die, 0, size); | 
 |   return die; | 
 | } | 
 |  | 
 | /* See die.h.  */ | 
 |  | 
 | hashval_t | 
 | die_info::hash (const void *item) | 
 | { | 
 |   const struct die_info *die = (const struct die_info *) item; | 
 |  | 
 |   return to_underlying (die->sect_off); | 
 | } | 
 |  | 
 | /* See die.h.  */ | 
 |  | 
 | int | 
 | die_info::eq (const void *item_lhs, const void *item_rhs) | 
 | { | 
 |   const struct die_info *die_lhs = (const struct die_info *) item_lhs; | 
 |   const struct die_info *die_rhs = (const struct die_info *) item_rhs; | 
 |  | 
 |   return die_lhs->sect_off == die_rhs->sect_off; | 
 | } | 
 |  | 
 | static void | 
 | dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) | 
 | { | 
 |   unsigned int i; | 
 |  | 
 |   gdb_printf (f, "%*sDie: %s (abbrev %d, offset %s)\n", | 
 | 	      indent, "", | 
 | 	      dwarf_tag_name (die->tag), die->abbrev, | 
 | 	      sect_offset_str (die->sect_off)); | 
 |  | 
 |   if (die->parent != NULL) | 
 |     gdb_printf (f, "%*s  parent at offset: %s\n", | 
 | 		indent, "", | 
 | 		sect_offset_str (die->parent->sect_off)); | 
 |  | 
 |   gdb_printf (f, "%*s  has children: %s\n", | 
 | 	      indent, "", | 
 | 	      dwarf_bool_name (die->child != NULL)); | 
 |  | 
 |   gdb_printf (f, "%*s  attributes:\n", indent, ""); | 
 |  | 
 |   for (i = 0; i < die->num_attrs; ++i) | 
 |     { | 
 |       gdb_printf (f, "%*s    %s (%s) ", | 
 | 		  indent, "", | 
 | 		  dwarf_attr_name (die->attrs[i].name), | 
 | 		  dwarf_form_name (die->attrs[i].form)); | 
 |  | 
 |       switch (die->attrs[i].form) | 
 | 	{ | 
 | 	case DW_FORM_addr: | 
 | 	case DW_FORM_addrx: | 
 | 	case DW_FORM_GNU_addr_index: | 
 | 	  gdb_printf (f, "address: "); | 
 | 	  gdb_puts (hex_string (die->attrs[i].as_address ()), f); | 
 | 	  break; | 
 | 	case DW_FORM_block2: | 
 | 	case DW_FORM_block4: | 
 | 	case DW_FORM_block: | 
 | 	case DW_FORM_block1: | 
 | 	  gdb_printf (f, "block: size %s", | 
 | 		      pulongest (die->attrs[i].as_block ()->size)); | 
 | 	  break; | 
 | 	case DW_FORM_exprloc: | 
 | 	  gdb_printf (f, "expression: size %s", | 
 | 		      pulongest (die->attrs[i].as_block ()->size)); | 
 | 	  break; | 
 | 	case DW_FORM_data16: | 
 | 	  gdb_printf (f, "constant of 16 bytes"); | 
 | 	  break; | 
 | 	case DW_FORM_ref_addr: | 
 | 	  gdb_printf (f, "ref address: "); | 
 | 	  gdb_puts (hex_string (die->attrs[i].as_unsigned ()), f); | 
 | 	  break; | 
 | 	case DW_FORM_GNU_ref_alt: | 
 | 	  gdb_printf (f, "alt ref address: "); | 
 | 	  gdb_puts (hex_string (die->attrs[i].as_unsigned ()), f); | 
 | 	  break; | 
 | 	case DW_FORM_ref1: | 
 | 	case DW_FORM_ref2: | 
 | 	case DW_FORM_ref4: | 
 | 	case DW_FORM_ref8: | 
 | 	case DW_FORM_ref_udata: | 
 | 	  gdb_printf (f, "constant ref: 0x%lx (adjusted)", | 
 | 		      (long) (die->attrs[i].as_unsigned ())); | 
 | 	  break; | 
 | 	case DW_FORM_data1: | 
 | 	case DW_FORM_data2: | 
 | 	case DW_FORM_data4: | 
 | 	case DW_FORM_data8: | 
 | 	case DW_FORM_udata: | 
 | 	  gdb_printf (f, "constant: %s", | 
 | 		      pulongest (die->attrs[i].as_unsigned ())); | 
 | 	  break; | 
 | 	case DW_FORM_sec_offset: | 
 | 	  gdb_printf (f, "section offset: %s", | 
 | 		      pulongest (die->attrs[i].as_unsigned ())); | 
 | 	  break; | 
 | 	case DW_FORM_ref_sig8: | 
 | 	  gdb_printf (f, "signature: %s", | 
 | 		      hex_string (die->attrs[i].as_signature ())); | 
 | 	  break; | 
 | 	case DW_FORM_string: | 
 | 	case DW_FORM_strp: | 
 | 	case DW_FORM_line_strp: | 
 | 	case DW_FORM_strx: | 
 | 	case DW_FORM_GNU_str_index: | 
 | 	case DW_FORM_GNU_strp_alt: | 
 | 	  gdb_printf (f, "string: \"%s\" (%s canonicalized)", | 
 | 		      die->attrs[i].as_string () | 
 | 		      ? die->attrs[i].as_string () : "", | 
 | 		      die->attrs[i].canonical_string_p () ? "is" : "not"); | 
 | 	  break; | 
 | 	case DW_FORM_flag: | 
 | 	  if (die->attrs[i].as_boolean ()) | 
 | 	    gdb_printf (f, "flag: TRUE"); | 
 | 	  else | 
 | 	    gdb_printf (f, "flag: FALSE"); | 
 | 	  break; | 
 | 	case DW_FORM_flag_present: | 
 | 	  gdb_printf (f, "flag: TRUE"); | 
 | 	  break; | 
 | 	case DW_FORM_indirect: | 
 | 	  /* The reader will have reduced the indirect form to | 
 | 	     the "base form" so this form should not occur.  */ | 
 | 	  gdb_printf (f, | 
 | 		      "unexpected attribute form: DW_FORM_indirect"); | 
 | 	  break; | 
 | 	case DW_FORM_sdata: | 
 | 	case DW_FORM_implicit_const: | 
 | 	  gdb_printf (f, "constant: %s", | 
 | 		      plongest (die->attrs[i].as_signed ())); | 
 | 	  break; | 
 | 	default: | 
 | 	  gdb_printf (f, "unsupported attribute form: %d.", | 
 | 		      die->attrs[i].form); | 
 | 	  break; | 
 | 	} | 
 |       gdb_printf (f, "\n"); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | dump_die_1 (struct ui_file *f, int level, int max_level, struct die_info *die) | 
 | { | 
 |   int indent = level * 4; | 
 |  | 
 |   gdb_assert (die != NULL); | 
 |  | 
 |   if (level >= max_level) | 
 |     return; | 
 |  | 
 |   dump_die_shallow (f, indent, die); | 
 |  | 
 |   if (die->child != NULL) | 
 |     { | 
 |       gdb_printf (f, "%*s  Children:", indent, ""); | 
 |       if (level + 1 < max_level) | 
 | 	{ | 
 | 	  gdb_printf (f, "\n"); | 
 | 	  dump_die_1 (f, level + 1, max_level, die->child); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  gdb_printf (f, | 
 | 		      " [not printed, max nesting level reached]\n"); | 
 | 	} | 
 |     } | 
 |  | 
 |   if (die->sibling != NULL && level > 0) | 
 |     { | 
 |       dump_die_1 (f, level, max_level, die->sibling); | 
 |     } | 
 | } | 
 |  | 
 | /* See die.h.  */ | 
 |  | 
 | void | 
 | die_info::dump (int max_level) | 
 | { | 
 |   dump_die_1 (gdb_stdlog, 0, max_level, this); | 
 | } | 
 |  | 
 | /* See die.h.  */ | 
 |  | 
 | void | 
 | die_info::error_dump () | 
 | { | 
 |   dump_die_shallow (gdb_stderr, 0, this); | 
 | } |