|  | /* DWARF attributes | 
|  |  | 
|  | Copyright (C) 1994-2025 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/>.  */ | 
|  |  | 
|  | #ifndef GDB_DWARF2_ATTRIBUTE_H | 
|  | #define GDB_DWARF2_ATTRIBUTE_H | 
|  |  | 
|  | #include "dwarf2.h" | 
|  | #include "dwarf2/types.h" | 
|  |  | 
|  | /* Blocks are a bunch of untyped bytes.  */ | 
|  | struct dwarf_block | 
|  | { | 
|  | size_t size; | 
|  |  | 
|  | /* Valid only if SIZE is not zero.  */ | 
|  | const gdb_byte *data; | 
|  | }; | 
|  |  | 
|  | /* Attributes have a name and a value.  */ | 
|  | struct attribute | 
|  | { | 
|  | /* Read the given attribute value as an address, taking the | 
|  | attribute's form into account.  */ | 
|  | unrelocated_addr as_address () const; | 
|  |  | 
|  | /* If the attribute has a string form, return the string value; | 
|  | otherwise return NULL.  */ | 
|  | const char *as_string () const; | 
|  |  | 
|  | /* Return the block value.  The attribute must have block form.  */ | 
|  | dwarf_block *as_block () const | 
|  | { | 
|  | gdb_assert (form_is_block ()); | 
|  | return u.blk; | 
|  | } | 
|  |  | 
|  | /* Return the signature.  The attribute must have signature | 
|  | form.  */ | 
|  | ULONGEST as_signature () const | 
|  | { | 
|  | gdb_assert (form == DW_FORM_ref_sig8); | 
|  | return u.signature; | 
|  | } | 
|  |  | 
|  | /* Return the signed value.  The attribute must have the appropriate | 
|  | form.  */ | 
|  | LONGEST as_signed () const | 
|  | { | 
|  | gdb_assert (form_is_strictly_signed ()); | 
|  | return u.snd; | 
|  | } | 
|  |  | 
|  | /* Return the unsigned value, but only for attributes requiring | 
|  | reprocessing.  */ | 
|  | ULONGEST as_unsigned_reprocess () const | 
|  | { | 
|  | gdb_assert (form_requires_reprocessing ()); | 
|  | gdb_assert (requires_reprocessing); | 
|  | return u.unsnd; | 
|  | } | 
|  |  | 
|  | /* Return the unsigned value.  Requires that the form be an unsigned | 
|  | form, and that reprocessing not be needed.  */ | 
|  | ULONGEST as_unsigned () const | 
|  | { | 
|  | gdb_assert (form_is_unsigned ()); | 
|  | gdb_assert (!requires_reprocessing); | 
|  | return u.unsnd; | 
|  | } | 
|  |  | 
|  | /* Return non-zero if ATTR's value is a section offset --- classes | 
|  | lineptr, loclistptr, macptr or rangelistptr --- or zero, otherwise. | 
|  | You may use the as_unsigned method to retrieve such offsets. | 
|  |  | 
|  | Section 7.5.4, "Attribute Encodings", explains that no attribute | 
|  | may have a value that belongs to more than one of these classes; it | 
|  | would be ambiguous if we did, because we use the same forms for all | 
|  | of them.  */ | 
|  |  | 
|  | bool form_is_section_offset () const; | 
|  |  | 
|  | /* Return an unsigned constant value.  This only handles constant | 
|  | forms (i.e., form_is_constant -- and not the extended list of | 
|  | "unsigned" forms) and assumes an unsigned value is desired.  This | 
|  | can be used with DWARF-defined enumerations like DW_CC_* or | 
|  | DW_INL_*, but also in situations where a nonnegative constant | 
|  | integer is specified by DWARF. | 
|  |  | 
|  | If a signed form and negative value is used, or if a non-constant | 
|  | form is used, then complaint is issued and an empty value is | 
|  | returned.  */ | 
|  | std::optional<ULONGEST> unsigned_constant () const; | 
|  |  | 
|  | /* Return a signed constant value.  This only handles constant forms | 
|  | (i.e., form_is_constant -- and not the extended list of | 
|  | "unsigned" forms) and assumes a signed value is desired.  This | 
|  | function will sign-extend DW_FORM_data* values. | 
|  |  | 
|  | If non-constant form is used, then complaint is issued and an | 
|  | empty value is returned.  */ | 
|  | std::optional<LONGEST> signed_constant () const; | 
|  |  | 
|  | /* Return a signed constant value.  However, for narrow forms like | 
|  | DW_FORM_data1, sign extension is not done. | 
|  |  | 
|  | DWARF advises compilers to generally use DW_FORM_[su]data to | 
|  | avoid ambiguity.  However, both GCC and LLVM ignore this for | 
|  | certain attributes.  Furthermore in DWARF, whether a narrower | 
|  | form causes sign-extension depends on the attribute -- for | 
|  | attributes that can only assume non-negative values, sign | 
|  | extension is not done. | 
|  |  | 
|  | Unfortunately, both compilers also emit certain attributes in a | 
|  | "confused" way, using DW_FORM_sdata for signed values, and | 
|  | possibly choosing a narrow form (e.g., DW_FORM_data1) otherwise | 
|  | -- assuming that sign-extension will not be done. | 
|  |  | 
|  | This method should only be called when this "confused" treatment | 
|  | is necessary.  */ | 
|  | std::optional<LONGEST> confused_constant () const; | 
|  |  | 
|  | /* Return non-zero if ATTR's value falls in the 'constant' class, or | 
|  | zero otherwise.  When this function returns true, you can apply | 
|  | the constant_value method to it. | 
|  |  | 
|  | However, note that for some attributes you must check | 
|  | attr_form_is_section_offset before using this test.  DW_FORM_data4 | 
|  | and DW_FORM_data8 are members of both the constant class, and of | 
|  | the classes that contain offsets into other debug sections | 
|  | (lineptr, loclistptr, macptr or rangelistptr).  The DWARF spec says | 
|  | that, if an attribute's can be either a constant or one of the | 
|  | section offset classes, DW_FORM_data4 and DW_FORM_data8 should be | 
|  | taken as section offsets, not constants. | 
|  |  | 
|  | DW_FORM_data16 is not considered as constant_value cannot handle | 
|  | that.  */ | 
|  |  | 
|  | bool form_is_constant () const; | 
|  |  | 
|  | /* The address is always stored already as sect_offset; despite for | 
|  | the forms besides DW_FORM_ref_addr it is stored as cu_offset in | 
|  | the DWARF file.  */ | 
|  |  | 
|  | bool form_is_ref () const | 
|  | { | 
|  | return (form == DW_FORM_ref_addr | 
|  | || form == DW_FORM_ref1 | 
|  | || form == DW_FORM_ref2 | 
|  | || form == DW_FORM_ref4 | 
|  | || form == DW_FORM_ref8 | 
|  | || form == DW_FORM_ref_udata | 
|  | || form == DW_FORM_GNU_ref_alt | 
|  | || form == DW_FORM_ref_sup4 | 
|  | || form == DW_FORM_ref_sup8); | 
|  | } | 
|  |  | 
|  | /* Check if the attribute's form is a DW_FORM_block* | 
|  | if so return true else false.  */ | 
|  |  | 
|  | bool form_is_block () const; | 
|  |  | 
|  | /* Check if the attribute's form is a string form.  */ | 
|  | bool form_is_string () const; | 
|  |  | 
|  | /* Check if the attribute's form is an unsigned integer form.  */ | 
|  | bool form_is_unsigned () const; | 
|  |  | 
|  | /* Check if the attribute's form is a signed integer form.  This | 
|  | only returns true for forms that are strictly signed -- that is, | 
|  | for a context-dependent form like DW_FORM_data1, this returns | 
|  | false.  */ | 
|  | bool form_is_strictly_signed () const; | 
|  |  | 
|  | /* Check if the attribute's form is an unsigned constant form.  This | 
|  | only returns true for forms that are strictly unsigned -- that | 
|  | is, for a context-dependent form like DW_FORM_data1, this returns | 
|  | false.  */ | 
|  | bool form_is_strictly_unsigned () const | 
|  | { | 
|  | return form == DW_FORM_udata; | 
|  | } | 
|  |  | 
|  | /* Check if the attribute's form is a form that requires | 
|  | "reprocessing".  */ | 
|  | bool form_requires_reprocessing () const; | 
|  |  | 
|  | /* Check if attribute's form refers to the separate "dwz" file. | 
|  | This is only useful for references to the .debug_info section, | 
|  | not to the supplementary .debug_str section.  */ | 
|  | bool form_is_alt () const | 
|  | { | 
|  | return (form == DW_FORM_GNU_ref_alt | 
|  | || form == DW_FORM_ref_sup4 | 
|  | || form == DW_FORM_ref_sup8); | 
|  | } | 
|  |  | 
|  | /* Return DIE offset of this attribute.  Return 0 with complaint if | 
|  | the attribute is not of the required kind.  */ | 
|  |  | 
|  | sect_offset get_ref_die_offset () const | 
|  | { | 
|  | if (form_is_ref ()) | 
|  | return (sect_offset) u.unsnd; | 
|  | get_ref_die_offset_complaint (); | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | /* Return the constant value held by this attribute.  Return | 
|  | DEFAULT_VALUE if the value held by the attribute is not | 
|  | constant.  */ | 
|  |  | 
|  | LONGEST constant_value (int default_value) const; | 
|  |  | 
|  | /* Return true if this attribute holds a canonical string.  In some | 
|  | cases, like C++ names, gdb will rewrite the name of a DIE to a | 
|  | canonical form.  This makes lookups robust when a name can be | 
|  | spelled different ways (e.g., "signed" or "signed int").  This | 
|  | flag indicates whether the value has been canonicalized.  */ | 
|  | bool canonical_string_p () const | 
|  | { | 
|  | gdb_assert (form_is_string ()); | 
|  | return string_is_canonical; | 
|  | } | 
|  |  | 
|  | /* Initialize this attribute to hold a non-canonical string | 
|  | value.  */ | 
|  | void set_string_noncanonical (const char *str) | 
|  | { | 
|  | gdb_assert (form_is_string ()); | 
|  | u.str = str; | 
|  | string_is_canonical = 0; | 
|  | requires_reprocessing = 0; | 
|  | } | 
|  |  | 
|  | /* Set the canonical string value for this attribute.  */ | 
|  | void set_string_canonical (const char *str) | 
|  | { | 
|  | gdb_assert (form_is_string ()); | 
|  | u.str = str; | 
|  | string_is_canonical = 1; | 
|  | } | 
|  |  | 
|  | /* Set the block value for this attribute.  */ | 
|  | void set_block (dwarf_block *blk) | 
|  | { | 
|  | gdb_assert (form_is_block ()); | 
|  | u.blk = blk; | 
|  | } | 
|  |  | 
|  | /* Set the signature value for this attribute.  */ | 
|  | void set_signature (ULONGEST signature) | 
|  | { | 
|  | gdb_assert (form == DW_FORM_ref_sig8); | 
|  | u.signature = signature; | 
|  | } | 
|  |  | 
|  | /* Set this attribute to a signed integer.  */ | 
|  | void set_signed (LONGEST snd) | 
|  | { | 
|  | gdb_assert (form == DW_FORM_sdata || form == DW_FORM_implicit_const); | 
|  | u.snd = snd; | 
|  | } | 
|  |  | 
|  | /* Set this attribute to an unsigned integer.  */ | 
|  | void set_unsigned (ULONGEST unsnd) | 
|  | { | 
|  | gdb_assert (form_is_unsigned ()); | 
|  | u.unsnd = unsnd; | 
|  | requires_reprocessing = 0; | 
|  | } | 
|  |  | 
|  | /* Temporarily set this attribute to an unsigned integer.  This is | 
|  | used only for those forms that require reprocessing.  */ | 
|  | void set_unsigned_reprocess (ULONGEST unsnd) | 
|  | { | 
|  | gdb_assert (form_requires_reprocessing ()); | 
|  | u.unsnd = unsnd; | 
|  | requires_reprocessing = 1; | 
|  | } | 
|  |  | 
|  | /* Set this attribute to an address.  */ | 
|  | void set_address (unrelocated_addr addr) | 
|  | { | 
|  | gdb_assert (form == DW_FORM_addr | 
|  | || ((form == DW_FORM_addrx | 
|  | || form == DW_FORM_GNU_addr_index) | 
|  | && requires_reprocessing)); | 
|  | u.addr = addr; | 
|  | requires_reprocessing = 0; | 
|  | } | 
|  |  | 
|  | /* True if this attribute requires reprocessing.  */ | 
|  | bool requires_reprocessing_p () const | 
|  | { | 
|  | return requires_reprocessing; | 
|  | } | 
|  |  | 
|  | /* Return the value as one of the recognized enum | 
|  | dwarf_defaulted_attribute constants according to DWARF5 spec, | 
|  | Table 7.24.  If the value is incorrect, or if this attribute has | 
|  | the wrong form, then a complaint is issued and DW_DEFAULTED_no is | 
|  | returned.  */ | 
|  | dwarf_defaulted_attribute defaulted () const; | 
|  |  | 
|  | /* Return the attribute's value as a dwarf_virtuality_attribute | 
|  | constant according to DWARF spec.  An unrecognized value will | 
|  | issue a complaint and return DW_VIRTUALITY_none.  */ | 
|  | dwarf_virtuality_attribute as_virtuality () const; | 
|  |  | 
|  | /* Return the attribute's value as a boolean.  An unrecognized form | 
|  | will issue a complaint and return false.  */ | 
|  | bool as_boolean () const; | 
|  |  | 
|  | ENUM_BITFIELD(dwarf_attribute) name : 15; | 
|  |  | 
|  | /* A boolean that is used for forms that require reprocessing.  A | 
|  | form may require data not directly available in the attribute. | 
|  | E.g., DW_FORM_strx requires the corresponding | 
|  | DW_AT_str_offsets_base.  In this case, the processing for the | 
|  | attribute must be done in two passes.  In the first past, this | 
|  | flag is set and the value is an unsigned.  In the second pass, | 
|  | the unsigned value is turned into the correct value for the form, | 
|  | and this flag is cleared.  This flag is unused for other | 
|  | forms.  */ | 
|  | unsigned int requires_reprocessing : 1; | 
|  |  | 
|  | ENUM_BITFIELD(dwarf_form) form : 15; | 
|  |  | 
|  | /* Has u.str already been updated by dwarf2_canonicalize_name?  This | 
|  | field should be in u.str but it is kept here for better struct | 
|  | attribute alignment.  */ | 
|  | unsigned int string_is_canonical : 1; | 
|  |  | 
|  | union | 
|  | { | 
|  | const char *str; | 
|  | struct dwarf_block *blk; | 
|  | ULONGEST unsnd; | 
|  | LONGEST snd; | 
|  | unrelocated_addr addr; | 
|  | ULONGEST signature; | 
|  | } | 
|  | u; | 
|  |  | 
|  | private: | 
|  |  | 
|  | /* Used by get_ref_die_offset to issue a complaint.  */ | 
|  |  | 
|  | void get_ref_die_offset_complaint () const; | 
|  | }; | 
|  |  | 
|  | #endif /* GDB_DWARF2_ATTRIBUTE_H */ |