| /* 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 ((CORE_ADDR) 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); | |
| } |