|  | /* DWARF attributes | 
|  |  | 
|  | Copyright (C) 1994-2023 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/attribute.h" | 
|  | #include "dwarf2/stringify.h" | 
|  | #include "complaints.h" | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | unrelocated_addr | 
|  | attribute::as_address () const | 
|  | { | 
|  | unrelocated_addr addr; | 
|  |  | 
|  | gdb_assert (!requires_reprocessing); | 
|  |  | 
|  | if (form != DW_FORM_addr && form != DW_FORM_addrx | 
|  | && form != DW_FORM_GNU_addr_index) | 
|  | { | 
|  | /* Aside from a few clearly defined exceptions, attributes that | 
|  | contain an address must always be in DW_FORM_addr form. | 
|  | Unfortunately, some compilers happen to be violating this | 
|  | requirement by encoding addresses using other forms, such | 
|  | as DW_FORM_data4 for example.  For those broken compilers, | 
|  | we try to do our best, without any guarantee of success, | 
|  | to interpret the address correctly.  It would also be nice | 
|  | to generate a complaint, but that would require us to maintain | 
|  | a list of legitimate cases where a non-address form is allowed, | 
|  | as well as update callers to pass in at least the CU's DWARF | 
|  | version.  This is more overhead than what we're willing to | 
|  | expand for a pretty rare case.  */ | 
|  | addr = (unrelocated_addr) u.unsnd; | 
|  | } | 
|  | else | 
|  | addr = u.addr; | 
|  |  | 
|  | return addr; | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | bool | 
|  | attribute::form_is_string () const | 
|  | { | 
|  | return (form == DW_FORM_strp || form == DW_FORM_line_strp | 
|  | || form == DW_FORM_string | 
|  | || form == DW_FORM_strx | 
|  | || form == DW_FORM_strx1 | 
|  | || form == DW_FORM_strx2 | 
|  | || form == DW_FORM_strx3 | 
|  | || form == DW_FORM_strx4 | 
|  | || form == DW_FORM_GNU_str_index | 
|  | || form == DW_FORM_GNU_strp_alt); | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | const char * | 
|  | attribute::as_string () const | 
|  | { | 
|  | gdb_assert (!requires_reprocessing); | 
|  | if (form_is_string ()) | 
|  | return u.str; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | bool | 
|  | attribute::form_is_block () const | 
|  | { | 
|  | return (form == DW_FORM_block1 | 
|  | || form == DW_FORM_block2 | 
|  | || form == DW_FORM_block4 | 
|  | || form == DW_FORM_block | 
|  | || form == DW_FORM_exprloc | 
|  | || form == DW_FORM_data16); | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | bool | 
|  | attribute::form_is_section_offset () const | 
|  | { | 
|  | return (form == DW_FORM_data4 | 
|  | || form == DW_FORM_data8 | 
|  | || form == DW_FORM_sec_offset | 
|  | || form == DW_FORM_loclistx); | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | bool | 
|  | attribute::form_is_constant () const | 
|  | { | 
|  | switch (form) | 
|  | { | 
|  | case DW_FORM_sdata: | 
|  | case DW_FORM_udata: | 
|  | case DW_FORM_data1: | 
|  | case DW_FORM_data2: | 
|  | case DW_FORM_data4: | 
|  | case DW_FORM_data8: | 
|  | case DW_FORM_implicit_const: | 
|  | return true; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | void | 
|  | attribute::get_ref_die_offset_complaint () const | 
|  | { | 
|  | complaint (_("unsupported die ref attribute form: '%s'"), | 
|  | dwarf_form_name (form)); | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | LONGEST | 
|  | attribute::constant_value (int default_value) const | 
|  | { | 
|  | if (form == DW_FORM_sdata || form == DW_FORM_implicit_const) | 
|  | return u.snd; | 
|  | else if (form == DW_FORM_udata | 
|  | || form == DW_FORM_data1 | 
|  | || form == DW_FORM_data2 | 
|  | || form == DW_FORM_data4 | 
|  | || form == DW_FORM_data8) | 
|  | return u.unsnd; | 
|  | else | 
|  | { | 
|  | /* For DW_FORM_data16 see attribute::form_is_constant.  */ | 
|  | complaint (_("Attribute value is not a constant (%s)"), | 
|  | dwarf_form_name (form)); | 
|  | return default_value; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | bool | 
|  | attribute::form_is_unsigned () const | 
|  | { | 
|  | return (form == DW_FORM_ref_addr | 
|  | || form == DW_FORM_GNU_ref_alt | 
|  | || form == DW_FORM_data2 | 
|  | || form == DW_FORM_data4 | 
|  | || form == DW_FORM_data8 | 
|  | || form == DW_FORM_sec_offset | 
|  | || form == DW_FORM_data1 | 
|  | || form == DW_FORM_flag | 
|  | || form == DW_FORM_flag_present | 
|  | || form == DW_FORM_udata | 
|  | || form == DW_FORM_rnglistx | 
|  | || form == DW_FORM_loclistx | 
|  | || form == DW_FORM_ref1 | 
|  | || form == DW_FORM_ref2 | 
|  | || form == DW_FORM_ref4 | 
|  | || form == DW_FORM_ref8 | 
|  | || form == DW_FORM_ref_udata); | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | bool | 
|  | attribute::form_is_signed () const | 
|  | { | 
|  | return form == DW_FORM_sdata || form == DW_FORM_implicit_const; | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | bool | 
|  | attribute::form_requires_reprocessing () const | 
|  | { | 
|  | return (form == DW_FORM_strx | 
|  | || form == DW_FORM_strx1 | 
|  | || form == DW_FORM_strx2 | 
|  | || form == DW_FORM_strx3 | 
|  | || form == DW_FORM_strx4 | 
|  | || form == DW_FORM_GNU_str_index | 
|  | || form == DW_FORM_addrx | 
|  | || form == DW_FORM_GNU_addr_index | 
|  | || form == DW_FORM_rnglistx | 
|  | || form == DW_FORM_loclistx); | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | dwarf_defaulted_attribute | 
|  | attribute::defaulted () const | 
|  | { | 
|  | LONGEST value = constant_value (-1); | 
|  |  | 
|  | switch (value) | 
|  | { | 
|  | case DW_DEFAULTED_no: | 
|  | case DW_DEFAULTED_in_class: | 
|  | case DW_DEFAULTED_out_of_class: | 
|  | return (dwarf_defaulted_attribute) value; | 
|  | } | 
|  |  | 
|  | /* If the form was not constant, we already complained in | 
|  | constant_value, so there's no need to complain again.  */ | 
|  | if (form_is_constant ()) | 
|  | complaint (_("unrecognized DW_AT_defaulted value (%s)"), | 
|  | plongest (value)); | 
|  | return DW_DEFAULTED_no; | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | dwarf_virtuality_attribute | 
|  | attribute::as_virtuality () const | 
|  | { | 
|  | LONGEST value = constant_value (-1); | 
|  |  | 
|  | switch (value) | 
|  | { | 
|  | case DW_VIRTUALITY_none: | 
|  | case DW_VIRTUALITY_virtual: | 
|  | case DW_VIRTUALITY_pure_virtual: | 
|  | return (dwarf_virtuality_attribute) value; | 
|  | } | 
|  |  | 
|  | /* If the form was not constant, we already complained in | 
|  | constant_value, so there's no need to complain again.  */ | 
|  | if (form_is_constant ()) | 
|  | complaint (_("unrecognized DW_AT_virtuality value (%s)"), | 
|  | plongest (value)); | 
|  | return DW_VIRTUALITY_none; | 
|  | } | 
|  |  | 
|  | /* See attribute.h.  */ | 
|  |  | 
|  | bool | 
|  | attribute::as_boolean () const | 
|  | { | 
|  | if (form == DW_FORM_flag_present) | 
|  | return true; | 
|  | else if (form == DW_FORM_flag) | 
|  | return u.unsnd != 0; | 
|  | return constant_value (0) != 0; | 
|  | } |