diff options
Diffstat (limited to 'gdb')
35 files changed, 749 insertions, 369 deletions
diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 77e03e4..285a00b 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -492,7 +492,6 @@ SELFTESTS_SRCS = \ unittests/ui-file-selftests.c \ unittests/unique_xmalloc_ptr_char.c \ unittests/unpack-selftests.c \ - unittests/utils-selftests.c \ unittests/vec-utils-selftests.c \ unittests/xml-utils-selftests.c diff --git a/gdb/auto-load.c b/gdb/auto-load.c index 4fc5b08..f33a8d0 100644 --- a/gdb/auto-load.c +++ b/gdb/auto-load.c @@ -41,6 +41,7 @@ #include <algorithm> #include "gdbsupport/pathstuff.h" #include "cli/cli-style.h" +#include "gdbsupport/selftest.h" /* The section to look in for auto-loaded scripts (in file formats that support sections). @@ -162,6 +163,67 @@ show_auto_load_dir (struct ui_file *file, int from_tty, value); } +/* Substitute all occurrences of string FROM by string TO in STRING. + STRING will be updated in place as needed. FROM needs to be + delimited by IS_DIR_SEPARATOR or DIRNAME_SEPARATOR (or be located + at the start or end of STRING. */ + +static void +substitute_path_component (std::string &string, std::string_view from, + std::string_view to) +{ + for (size_t s = 0;;) + { + s = string.find (from, s); + if (s == std::string::npos) + break; + + if ((s == 0 || IS_DIR_SEPARATOR (string[s - 1]) + || string[s - 1] == DIRNAME_SEPARATOR) + && (s + from.size () == string.size () + || IS_DIR_SEPARATOR (string[s + from.size ()]) + || string[s + from.size ()] == DIRNAME_SEPARATOR)) + { + string.replace (s, from.size (), to); + s += to.size (); + } + else + s++; + } +} + +#if GDB_SELF_TEST + +namespace selftests { +namespace subst_path { + +static void +test_substitute_path_component () +{ + auto test = [] (std::string s, const char *from, const char *to, + const char *expected) + { + substitute_path_component (s, from, to); + SELF_CHECK (s == expected); + }; + + test ("/abc/$def/g", "abc", "xyz", "/xyz/$def/g"); + test ("abc/$def/g", "abc", "xyz", "xyz/$def/g"); + test ("/abc/$def/g", "$def", "xyz", "/abc/xyz/g"); + test ("/abc/$def/g", "g", "xyz", "/abc/$def/xyz"); + test ("/abc/$def/g", "ab", "xyz", "/abc/$def/g"); + test ("/abc/$def/g", "def", "xyz", "/abc/$def/g"); + test ("/abc/$def/g", "abc", "abc", "/abc/$def/g"); + test ("/abc/$def/g", "abc", "", "//$def/g"); + test ("/abc/$def/g", "abc/$def", "xyz", "/xyz/g"); + test ("/abc/$def/abc", "abc", "xyz", "/xyz/$def/xyz"); +} + +} +} + +#endif /* GDB_SELF_TEST */ + /* Directory list safe to hold auto-loaded files. It is not checked for absolute paths but they are strongly recommended. It is initialized by _initialize_auto_load. */ @@ -178,16 +240,15 @@ static std::vector<gdb::unique_xmalloc_ptr<char>> auto_load_safe_path_vec; static std::vector<gdb::unique_xmalloc_ptr<char>> auto_load_expand_dir_vars (const char *string) { - char *s = xstrdup (string); - substitute_path_component (&s, "$datadir", gdb_datadir.c_str ()); - substitute_path_component (&s, "$debugdir", debug_file_directory.c_str ()); + std::string s = string; + substitute_path_component (s, "$datadir", gdb_datadir.c_str ()); + substitute_path_component (s, "$debugdir", debug_file_directory.c_str ()); - if (debug_auto_load && strcmp (s, string) != 0) - auto_load_debug_printf ("Expanded $-variables to \"%s\".", s); + if (debug_auto_load && s != string) + auto_load_debug_printf ("Expanded $-variables to \"%s\".", s.c_str ()); std::vector<gdb::unique_xmalloc_ptr<char>> dir_vec - = dirnames_to_char_ptr_vec (s); - xfree(s); + = dirnames_to_char_ptr_vec (s.c_str ()); return dir_vec; } @@ -1650,4 +1711,9 @@ When non-zero, debugging output for files of 'set auto-load ...'\n\ is displayed."), NULL, show_debug_auto_load, &setdebuglist, &showdebuglist); + +#if GDB_SELF_TEST + selftests::register_test ("substitute_path_component", + selftests::subst_path::test_substitute_path_component); +#endif } diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y index e7317b7..d4ab98c 100644 --- a/gdb/cp-name-parser.y +++ b/gdb/cp-name-parser.y @@ -2047,9 +2047,11 @@ cp_demangled_name_to_comp (const char *demangled_name, auto result = std::make_unique<demangle_parse_info> (); cpname_state state (demangled_name, result.get ()); - scoped_restore restore_yydebug = make_scoped_restore (&yydebug, - parser_debug); - + /* Note that we can't set yydebug here, as is done in the other + parsers. Bison implements yydebug as a global, even with a pure + parser, and this parser is run from worker threads. So, changing + yydebug causes TSan reports. If you need to debug this parser, + debug gdb and set the global from the outer gdb. */ if (yyparse (&state)) { if (state.global_errmsg && errmsg) diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi index c6808ef..c6d889f 100644 --- a/gdb/doc/guile.texi +++ b/gdb/doc/guile.texi @@ -3899,6 +3899,9 @@ Return string to change terminal's color to this. If @var{is_foreground} is @code{#t}, then the returned sequence will change foreground color. Otherwise, the returned sequence will change background color. + +If styling is currently disabled (@pxref{Output Styling,,@kbd{set style +enabled}}), then this procedure will return an empty string. @end deffn When color is initialized, its color space must be specified. The diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index afbd62f..7bb6503 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -7101,6 +7101,9 @@ Returns string to change terminal's color to this. If @var{is_foreground} is @code{True}, then the returned sequence will change foreground color. Otherwise, the returned sequence will change background color. + +If styling is currently disabled (@pxref{Output Styling,,@kbd{set style +enabled}}), then this method will return an empty string. @end defun When color is initialized, its color space must be specified. The diff --git a/gdb/dwarf2/cu.h b/gdb/dwarf2/cu.h index 5338dfe..9f76789 100644 --- a/gdb/dwarf2/cu.h +++ b/gdb/dwarf2/cu.h @@ -27,6 +27,8 @@ #include "gdbsupport/unordered_set.h" #include "dwarf2/die.h" +struct field_info; + /* Type used for delaying computation of method physnames. See comments for compute_delayed_physnames. */ struct delayed_method_info @@ -399,6 +401,15 @@ public: .debug_str_offsets section (8 or 4, depending on the address size). */ std::optional<ULONGEST> str_offsets_base; + /* We may encounter a DIE where a property refers to a field in some + outer type. For example, in Ada, an array length may depend on a + field in some outer record. In this case, we need to be able to + stash a pointer to the 'struct field' into the appropriate + dynamic property baton. However, the fields aren't created until + the type has been fully processed, so we need a temporary + back-link to this object. */ + struct field_info *field_info = nullptr; + /* Mark used when releasing cached dies. */ bool m_mark : 1; diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c index e1a5fdd..fa1b4eb 100644 --- a/gdb/dwarf2/loc.c +++ b/gdb/dwarf2/loc.c @@ -1732,11 +1732,10 @@ dwarf2_evaluate_property (const dynamic_prop *prop, *value = prop->const_val (); return true; - case PROP_ADDR_OFFSET: + case PROP_FIELD: { const dwarf2_property_baton *baton = prop->baton (); const struct property_addr_info *pinfo; - struct value *val; for (pinfo = addr_stack; pinfo != NULL; pinfo = pinfo->next) { @@ -1747,14 +1746,40 @@ dwarf2_evaluate_property (const dynamic_prop *prop, } if (pinfo == NULL) error (_("cannot find reference address for offset property")); - if (pinfo->valaddr.data () != NULL) - val = value_from_contents - (baton->offset_info.type, - pinfo->valaddr.data () + baton->offset_info.offset); - else - val = value_at (baton->offset_info.type, - pinfo->addr + baton->offset_info.offset); - *value = value_as_address (val); + + struct field resolved_field = *baton->field; + resolve_dynamic_field (resolved_field, pinfo, initial_frame); + + /* Storage for memory if we need to read it. */ + gdb::byte_vector memory; + const gdb_byte *bytes = pinfo->valaddr.data (); + if (bytes == nullptr) + { + int bitpos = resolved_field.loc_bitpos (); + int bitsize = resolved_field.bitsize (); + if (bitsize == 0) + bitsize = check_typedef (resolved_field.type ())->length () * 8; + + /* Read just the minimum number of bytes needed to satisfy + unpack_field_as_long. So, update the resolved field's + starting offset to remove any unnecessary leading + bytes. */ + int byte_offset = bitpos / 8; + + bitpos %= 8; + resolved_field.set_loc_bitpos (bitpos); + + /* Make sure to include any remaining bit offset in the + size computation, in case the value straddles a + byte. */ + int byte_length = align_up (bitsize + bitpos, 8) / 8; + memory.resize (byte_length); + + read_memory (pinfo->addr + byte_offset, memory.data (), + byte_length); + bytes = memory.data (); + } + *value = unpack_field_as_long (bytes, &resolved_field); return true; } diff --git a/gdb/dwarf2/loc.h b/gdb/dwarf2/loc.h index 30c528b..ebe5c31 100644 --- a/gdb/dwarf2/loc.h +++ b/gdb/dwarf2/loc.h @@ -99,7 +99,7 @@ struct property_addr_info /* If not NULL, a pointer to the info for the object containing the object described by this node. */ - struct property_addr_info *next; + const property_addr_info *next; }; /* Converts a dynamic property into a static one. FRAME is the frame in which @@ -167,6 +167,9 @@ struct dwarf2_locexpr_baton directly. */ bool is_reference; + /* True if this object is actually a dwarf2_field_location_baton. */ + bool is_field_location; + /* The objfile that was used when creating this. */ dwarf2_per_objfile *per_objfile; @@ -175,6 +178,23 @@ struct dwarf2_locexpr_baton dwarf2_per_cu *per_cu; }; +/* If the DWARF location for a field used DW_AT_bit_size, then an + object of this type is created to represent the field location. + This is then used to apply the bit offset after computing the + field's byte offset. Objects of this type always set the + 'is_field_location' member in dwarf2_locexpr_baton. See also + apply_bit_offset_to_field. */ + +struct dwarf2_field_location_baton : public dwarf2_locexpr_baton +{ + /* The bit offset, coming from DW_AT_bit_offset. */ + LONGEST bit_offset; + + /* The DW_AT_byte_size of the field. If no explicit byte size was + specified, this is 0. */ + LONGEST explicit_byte_size; +}; + struct dwarf2_loclist_baton { /* The initial base address for the location list, based on the compilation @@ -202,23 +222,6 @@ struct dwarf2_loclist_baton unsigned char dwarf_version; }; -/* The baton used when a dynamic property is an offset to a parent - type. This can be used, for instance, then the bound of an array - inside a record is determined by the value of another field inside - that record. */ - -struct dwarf2_offset_baton -{ - /* The offset from the parent type where the value of the property - is stored. In the example provided above, this would be the offset - of the field being used as the array bound. */ - LONGEST offset; - - /* The type of the object whose property is dynamic. In the example - provided above, this would the array's index type. */ - struct type *type; -}; - /* A dynamic property is either expressed as a single location expression or a location list. If the property is an indirection, pointing to another die, keep track of the targeted type in PROPERTY_TYPE. @@ -241,8 +244,8 @@ struct dwarf2_property_baton /* Location list to be evaluated in the context of PROPERTY_TYPE. */ struct dwarf2_loclist_baton loclist; - /* The location is an offset to PROPERTY_TYPE. */ - struct dwarf2_offset_baton offset_info; + /* The location is stored in a field of PROPERTY_TYPE. */ + struct field *field; }; }; diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 6848f63..71fa793 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -698,6 +698,12 @@ struct field_info we're reading. */ std::vector<variant_part_builder> variant_parts; + /* All the field batons that must be updated. This is only used + when a type's property depends on a field of this structure; for + example in Ada when an array's length may come from a field of an + enclosing record. */ + gdb::unordered_map<dwarf2_property_baton *, sect_offset> field_batons; + /* Return the total number of fields (including baseclasses). */ int nfields () const { @@ -8738,7 +8744,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) struct dwarf2_locexpr_baton *dlbaton; struct dwarf_block *block = attr->as_block (); - dlbaton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_locexpr_baton); + dlbaton = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_locexpr_baton); dlbaton->data = block->data; dlbaton->size = block->size; dlbaton->per_objfile = per_objfile; @@ -9861,54 +9868,6 @@ dwarf2_access_attribute (struct die_info *die, struct dwarf2_cu *cu) } } -/* Look for DW_AT_data_member_location or DW_AT_data_bit_offset. Set - *OFFSET to the byte offset. If the attribute was not found return - 0, otherwise return 1. If it was found but could not properly be - handled, set *OFFSET to 0. */ - -static int -handle_member_location (struct die_info *die, struct dwarf2_cu *cu, - LONGEST *offset) -{ - struct attribute *attr; - - attr = dwarf2_attr (die, DW_AT_data_member_location, cu); - if (attr != NULL) - { - *offset = 0; - CORE_ADDR temp; - - /* Note that we do not check for a section offset first here. - This is because DW_AT_data_member_location is new in DWARF 4, - so if we see it, we can assume that a constant form is really - a constant and not a section offset. */ - if (attr->form_is_constant ()) - *offset = attr->unsigned_constant ().value_or (0); - else if (attr->form_is_section_offset ()) - dwarf2_complex_location_expr_complaint (); - else if (attr->form_is_block () - && decode_locdesc (attr->as_block (), cu, &temp)) - { - *offset = temp; - } - else - dwarf2_complex_location_expr_complaint (); - - return 1; - } - else - { - attr = dwarf2_attr (die, DW_AT_data_bit_offset, cu); - if (attr != nullptr) - { - *offset = attr->unsigned_constant ().value_or (0); - return 1; - } - } - - return 0; -} - /* Look for DW_AT_data_member_location or DW_AT_data_bit_offset and store the results in FIELD. */ @@ -9921,6 +9880,25 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, attr = dwarf2_attr (die, DW_AT_data_member_location, cu); if (attr != NULL) { + bool has_bit_offset = false; + LONGEST bit_offset = 0; + LONGEST anonymous_size = 0; + + attribute *attr2 = dwarf2_attr (die, DW_AT_bit_offset, cu); + if (attr2 != nullptr && attr2->form_is_constant ()) + { + has_bit_offset = true; + bit_offset = attr2->unsigned_constant ().value_or (0); + attr2 = dwarf2_attr (die, DW_AT_byte_size, cu); + if (attr2 != nullptr && attr2->form_is_constant ()) + { + /* The size of the anonymous object containing + the bit field is explicit, so use the + indicated size (in bytes). */ + anonymous_size = attr2->unsigned_constant ().value_or (0); + } + } + if (attr->form_is_constant ()) { LONGEST offset = attr->unsigned_constant ().value_or (0); @@ -9938,9 +9916,9 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, } field->set_loc_bitpos (offset * bits_per_byte); + if (has_bit_offset) + apply_bit_offset_to_field (*field, bit_offset, anonymous_size); } - else if (attr->form_is_section_offset ()) - dwarf2_complex_location_expr_complaint (); else if (attr->form_is_block ()) { CORE_ADDR offset; @@ -9950,9 +9928,20 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, { dwarf2_per_objfile *per_objfile = cu->per_objfile; struct objfile *objfile = per_objfile->objfile; - struct dwarf2_locexpr_baton *dlbaton - = XOBNEW (&objfile->objfile_obstack, - struct dwarf2_locexpr_baton); + struct dwarf2_locexpr_baton *dlbaton; + if (has_bit_offset) + { + dwarf2_field_location_baton *flbaton + = OBSTACK_ZALLOC (&objfile->objfile_obstack, + dwarf2_field_location_baton); + flbaton->is_field_location = true; + flbaton->bit_offset = bit_offset; + flbaton->explicit_byte_size = anonymous_size; + dlbaton = flbaton; + } + else + dlbaton = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_locexpr_baton); dlbaton->data = attr->as_block ()->data; dlbaton->size = attr->as_block ()->size; /* When using this baton, we want to compute the address @@ -9966,7 +9955,8 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, } } else - dwarf2_complex_location_expr_complaint (); + complaint (_("Unsupported form %s for DW_AT_data_member_location"), + dwarf_form_name (attr->form)); } else { @@ -9982,8 +9972,6 @@ static void dwarf2_add_field (struct field_info *fip, struct die_info *die, struct dwarf2_cu *cu) { - struct objfile *objfile = cu->per_objfile->objfile; - struct gdbarch *gdbarch = objfile->arch (); struct nextfield *new_field; struct attribute *attr; struct field *fp; @@ -10047,50 +10035,6 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, /* Get bit offset of field. */ handle_member_location (die, cu, fp); - attr = dwarf2_attr (die, DW_AT_bit_offset, cu); - if (attr != nullptr && attr->form_is_constant ()) - { - ULONGEST bit_offset = attr->unsigned_constant ().value_or (0); - if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) - { - /* For big endian bits, the DW_AT_bit_offset gives the - additional bit offset from the MSB of the containing - anonymous object to the MSB of the field. We don't - have to do anything special since we don't need to - know the size of the anonymous object. */ - fp->set_loc_bitpos (fp->loc_bitpos () + bit_offset); - } - else - { - /* For little endian bits, compute the bit offset to the - MSB of the anonymous object, subtract off the number of - bits from the MSB of the field to the MSB of the - object, and then subtract off the number of bits of - the field itself. The result is the bit offset of - the LSB of the field. */ - int anonymous_size; - - attr = dwarf2_attr (die, DW_AT_byte_size, cu); - if (attr != nullptr && attr->form_is_constant ()) - { - /* The size of the anonymous object containing - the bit field is explicit, so use the - indicated size (in bytes). */ - anonymous_size = attr->unsigned_constant ().value_or (0); - } - else - { - /* The size of the anonymous object containing - the bit field must be inferred from the type - attribute of the data member containing the - bit field. */ - anonymous_size = fp->type ()->length (); - } - fp->set_loc_bitpos (fp->loc_bitpos () - + anonymous_size * bits_per_byte - - bit_offset - fp->bitsize ()); - } - } /* Get name of field. */ fieldname = dwarf2_name (die, cu); @@ -11269,6 +11213,56 @@ handle_struct_member_die (struct die_info *child_die, struct type *type, handle_variant (child_die, type, fi, template_args, cu); } +/* Create a property baton for a field of the struct type currently + being processed. OFFSET is the DIE offset of the field in the + structure. If OFFSET is found among the fields that have already + been seen, then a new property baton is allocated on the objfile + obstack and returned. The baton isn't fully filled in -- it will + be post-processed once the fields are finally created; see + update_field_batons. If OFFSET is not found, NULL is returned. */ + +static dwarf2_property_baton * +find_field_create_baton (dwarf2_cu *cu, sect_offset offset) +{ + field_info *fi = cu->field_info; + /* Defensive programming in case we see unusual DWARF. */ + if (fi == nullptr) + return nullptr; + for (const auto &fld : fi->fields) + if (fld.offset == offset) + { + dwarf2_property_baton *result + = XOBNEW (&cu->per_objfile->objfile->objfile_obstack, + struct dwarf2_property_baton); + fi->field_batons[result] = offset; + return result; + } + return nullptr; +} + +/* Update all the stored field property batons. FI is the field info + for the structure being created. TYPE is the corresponding struct + type with its fields already filled in. This fills in the correct + field for each baton that was stored while processing this + type. */ + +static void +update_field_batons (field_info *fi, struct type *type) +{ + int n_bases = fi->baseclasses.size (); + for (auto &[baton, offset] : fi->field_batons) + { + for (int i = 0; i < fi->fields.size (); ++i) + { + if (fi->fields[i].offset == offset) + { + baton->field = &type->field (n_bases + i); + break; + } + } + } +} + /* Finish creating a structure or union type, including filling in its members and creating a symbol for it. This function also handles Fortran namelist variables, their items or members and creating a symbol for @@ -11290,6 +11284,9 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu) struct field_info fi; std::vector<struct symbol *> template_args; + scoped_restore save_field_info + = make_scoped_restore (&cu->field_info, &fi); + for (die_info *child_die : die->children ()) handle_struct_member_die (child_die, type, &fi, &template_args, cu); @@ -11311,7 +11308,11 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu) /* Attach fields and member functions to the type. */ if (fi.nfields () > 0) - dwarf2_attach_fields_to_type (&fi, type, cu); + { + dwarf2_attach_fields_to_type (&fi, type, cu); + update_field_batons (&fi, type); + } + if (!fi.fnfieldlists.empty ()) { dwarf2_attach_fn_fields_to_type (&fi, type, cu); @@ -12262,7 +12263,8 @@ mark_common_block_symbol_computed (struct symbol *sym, gdb_assert (member_loc->form_is_block () || member_loc->form_is_constant ()); - baton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_locexpr_baton); + baton = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_locexpr_baton); baton->per_objfile = per_objfile; baton->per_cu = cu->per_cu; gdb_assert (baton->per_cu); @@ -13165,7 +13167,7 @@ read_typedef (struct die_info *die, struct dwarf2_cu *cu) a given gmp_mpz given an attribute. */ static void -get_mpz (struct dwarf2_cu *cu, gdb_mpz *value, struct attribute *attr) +get_mpz_for_rational (dwarf2_cu *cu, gdb_mpz *value, attribute *attr) { /* GCC will sometimes emit a 16-byte constant value as a DWARF location expression that pushes an implicit value. */ @@ -13199,10 +13201,11 @@ get_mpz (struct dwarf2_cu *cu, gdb_mpz *value, struct attribute *attr) ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE, true); } - else if (attr->form_is_strictly_unsigned ()) - *value = gdb_mpz (attr->as_unsigned ()); else - *value = gdb_mpz (attr->signed_constant ().value_or (1)); + { + /* Rational constants for Ada are always unsigned. */ + *value = gdb_mpz (attr->unsigned_constant ().value_or (1)); + } } /* Assuming DIE is a rational DW_TAG_constant, read the DIE's @@ -13231,8 +13234,8 @@ get_dwarf2_rational_constant (struct die_info *die, struct dwarf2_cu *cu, if (num_attr == nullptr || denom_attr == nullptr) return; - get_mpz (cu, numerator, num_attr); - get_mpz (cu, denominator, denom_attr); + get_mpz_for_rational (cu, numerator, num_attr); + get_mpz_for_rational (cu, denominator, denom_attr); } /* Same as get_dwarf2_rational_constant, but extracting an unsigned @@ -13924,17 +13927,14 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die, case DW_AT_data_member_location: case DW_AT_data_bit_offset: { - LONGEST offset; - - if (!handle_member_location (target_die, target_cu, &offset)) + baton = find_field_create_baton (cu, target_die->sect_off); + if (baton == nullptr) return 0; - baton = XOBNEW (obstack, struct dwarf2_property_baton); baton->property_type = read_type_die (target_die->parent, - target_cu); - baton->offset_info.offset = offset; - baton->offset_info.type = die_type (target_die, target_cu); - prop->set_addr_offset (baton); + target_cu); + baton->field = nullptr; + prop->set_field (baton); break; } } @@ -17234,7 +17234,7 @@ dwarf2_const_value_attr (const struct attribute *attr, struct type *type, /* Symbols of this form are reasonably rare, so we just piggyback on the existing location code rather than writing a new implementation of symbol_computed_ops. */ - *baton = XOBNEW (obstack, struct dwarf2_locexpr_baton); + *baton = OBSTACK_ZALLOC (obstack, struct dwarf2_locexpr_baton); (*baton)->per_objfile = per_objfile; (*baton)->per_cu = cu->per_cu; gdb_assert ((*baton)->per_cu); @@ -19185,7 +19185,8 @@ dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym, { struct dwarf2_locexpr_baton *baton; - baton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_locexpr_baton); + baton = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_locexpr_baton); baton->per_objfile = per_objfile; baton->per_cu = cu->per_cu; gdb_assert (baton->per_cu); diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 5713eac..a241223 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -902,7 +902,7 @@ operator== (const dynamic_prop &l, const dynamic_prop &r) return true; case PROP_CONST: return l.const_val () == r.const_val (); - case PROP_ADDR_OFFSET: + case PROP_FIELD: case PROP_LOCEXPR: case PROP_LOCLIST: return l.baton () == r.baton (); @@ -2146,7 +2146,7 @@ is_dynamic_type (struct type *type) } static struct type *resolve_dynamic_type_internal - (struct type *type, struct property_addr_info *addr_stack, + (struct type *type, const property_addr_info *addr_stack, const frame_info_ptr &frame, bool top_level); /* Given a dynamic range type (dyn_range_type) and a stack of @@ -2167,7 +2167,7 @@ static struct type *resolve_dynamic_type_internal static struct type * resolve_dynamic_range (struct type *dyn_range_type, - struct property_addr_info *addr_stack, + const property_addr_info *addr_stack, const frame_info_ptr &frame, int rank, bool resolve_p = true) { @@ -2269,7 +2269,7 @@ resolve_dynamic_range (struct type *dyn_range_type, static struct type * resolve_dynamic_array_or_string_1 (struct type *type, - struct property_addr_info *addr_stack, + const property_addr_info *addr_stack, const frame_info_ptr &frame, int rank, bool resolve_p) { @@ -2397,7 +2397,7 @@ resolve_dynamic_array_or_string_1 (struct type *type, static struct type * resolve_dynamic_array_or_string (struct type *type, - struct property_addr_info *addr_stack, + const property_addr_info *addr_stack, const frame_info_ptr &frame) { CORE_ADDR value; @@ -2490,7 +2490,7 @@ resolve_dynamic_array_or_string (struct type *type, static struct type * resolve_dynamic_union (struct type *type, - struct property_addr_info *addr_stack, + const property_addr_info *addr_stack, const frame_info_ptr &frame) { struct type *resolved_type; @@ -2534,7 +2534,7 @@ variant::matches (ULONGEST value, bool is_unsigned) const static void compute_variant_fields_inner (struct type *type, - struct property_addr_info *addr_stack, + const property_addr_info *addr_stack, const variant_part &part, std::vector<bool> &flags); @@ -2549,7 +2549,7 @@ compute_variant_fields_inner (struct type *type, static void compute_variant_fields_recurse (struct type *type, - struct property_addr_info *addr_stack, + const property_addr_info *addr_stack, const variant &variant, std::vector<bool> &flags, bool enabled) @@ -2581,7 +2581,7 @@ compute_variant_fields_recurse (struct type *type, static void compute_variant_fields_inner (struct type *type, - struct property_addr_info *addr_stack, + const property_addr_info *addr_stack, const variant_part &part, std::vector<bool> &flags) { @@ -2650,7 +2650,7 @@ compute_variant_fields_inner (struct type *type, static void compute_variant_fields (struct type *type, struct type *resolved_type, - struct property_addr_info *addr_stack, + const property_addr_info *addr_stack, const gdb::array_view<variant_part> &parts) { /* Assume all fields are included by default. */ @@ -2676,13 +2676,113 @@ compute_variant_fields (struct type *type, } } +/* See gdbtypes.h. */ + +void +apply_bit_offset_to_field (struct field &field, LONGEST bit_offset, + LONGEST explicit_byte_size) +{ + struct type *field_type = field.type (); + struct gdbarch *gdbarch = field_type->arch (); + LONGEST current_bitpos = field.loc_bitpos (); + + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + { + /* For big endian bits, the DW_AT_bit_offset gives the + additional bit offset from the MSB of the containing + anonymous object to the MSB of the field. We don't + have to do anything special since we don't need to + know the size of the anonymous object. */ + field.set_loc_bitpos (current_bitpos + bit_offset); + } + else + { + /* For little endian bits, compute the bit offset to the + MSB of the anonymous object, subtract off the number of + bits from the MSB of the field to the MSB of the + object, and then subtract off the number of bits of + the field itself. The result is the bit offset of + the LSB of the field. */ + LONGEST object_size = explicit_byte_size; + if (object_size == 0) + object_size = field_type->length (); + + field.set_loc_bitpos (current_bitpos + + 8 * object_size + - bit_offset + - field.bitsize ()); + } +} + +/* See gdbtypes.h. */ + +void +resolve_dynamic_field (struct field &field, + const property_addr_info *addr_stack, + const frame_info_ptr &frame) +{ + gdb_assert (!field.is_static ()); + + if (field.loc_kind () == FIELD_LOC_KIND_DWARF_BLOCK) + { + dwarf2_locexpr_baton *field_loc + = field.loc_dwarf_block (); + + struct dwarf2_property_baton baton; + baton.property_type = lookup_pointer_type (field.type ()); + baton.locexpr = *field_loc; + + struct dynamic_prop prop; + prop.set_locexpr (&baton); + + CORE_ADDR vals[1] = {addr_stack->addr}; + CORE_ADDR addr; + if (dwarf2_evaluate_property (&prop, frame, addr_stack, &addr, vals)) + { + field.set_loc_bitpos (TARGET_CHAR_BIT * (addr - addr_stack->addr)); + + if (field_loc->is_field_location) + { + dwarf2_field_location_baton *fl_baton + = static_cast<dwarf2_field_location_baton *> (field_loc); + apply_bit_offset_to_field (field, fl_baton->bit_offset, + fl_baton->explicit_byte_size); + } + } + } + + /* As we know this field is not a static field, the field's + field_loc_kind should be FIELD_LOC_KIND_BITPOS. Verify + this is the case, but only trigger a simple error rather + than an internal error if that fails. While failing + that verification indicates a bug in our code, the error + is not severe enough to suggest to the user he stops + his debugging session because of it. */ + if (field.loc_kind () != FIELD_LOC_KIND_BITPOS) + error (_("Cannot determine struct field location" + " (invalid location kind)")); + + struct property_addr_info pinfo; + pinfo.type = check_typedef (field.type ()); + size_t offset = field.loc_bitpos () / TARGET_CHAR_BIT; + pinfo.valaddr = addr_stack->valaddr; + if (!pinfo.valaddr.empty ()) + pinfo.valaddr = pinfo.valaddr.slice (offset); + pinfo.addr = addr_stack->addr + offset; + pinfo.next = addr_stack; + + field.set_type (resolve_dynamic_type_internal (field.type (), + &pinfo, frame, false)); + gdb_assert (field.loc_kind () == FIELD_LOC_KIND_BITPOS); +} + /* Resolve dynamic bounds of members of the struct TYPE to static bounds. ADDR_STACK is a stack of struct property_addr_info to be used if needed during the dynamic resolution. */ static struct type * resolve_dynamic_struct (struct type *type, - struct property_addr_info *addr_stack, + const property_addr_info *addr_stack, const frame_info_ptr &frame) { struct type *resolved_type; @@ -2710,52 +2810,11 @@ resolve_dynamic_struct (struct type *type, for (i = 0; i < resolved_type->num_fields (); ++i) { unsigned new_bit_length; - struct property_addr_info pinfo; if (resolved_type->field (i).is_static ()) continue; - if (resolved_type->field (i).loc_kind () == FIELD_LOC_KIND_DWARF_BLOCK) - { - struct dwarf2_property_baton baton; - baton.property_type - = lookup_pointer_type (resolved_type->field (i).type ()); - baton.locexpr = *resolved_type->field (i).loc_dwarf_block (); - - struct dynamic_prop prop; - prop.set_locexpr (&baton); - - CORE_ADDR addr; - if (dwarf2_evaluate_property (&prop, frame, addr_stack, &addr, - {addr_stack->addr})) - resolved_type->field (i).set_loc_bitpos - (TARGET_CHAR_BIT * (addr - addr_stack->addr)); - } - - /* As we know this field is not a static field, the field's - field_loc_kind should be FIELD_LOC_KIND_BITPOS. Verify - this is the case, but only trigger a simple error rather - than an internal error if that fails. While failing - that verification indicates a bug in our code, the error - is not severe enough to suggest to the user he stops - his debugging session because of it. */ - if (resolved_type->field (i).loc_kind () != FIELD_LOC_KIND_BITPOS) - error (_("Cannot determine struct field location" - " (invalid location kind)")); - - pinfo.type = check_typedef (resolved_type->field (i).type ()); - size_t offset = resolved_type->field (i).loc_bitpos () / TARGET_CHAR_BIT; - pinfo.valaddr = addr_stack->valaddr; - if (!pinfo.valaddr.empty ()) - pinfo.valaddr = pinfo.valaddr.slice (offset); - pinfo.addr = addr_stack->addr + offset; - pinfo.next = addr_stack; - - resolved_type->field (i).set_type - (resolve_dynamic_type_internal (resolved_type->field (i).type (), - &pinfo, frame, false)); - gdb_assert (resolved_type->field (i).loc_kind () - == FIELD_LOC_KIND_BITPOS); + resolve_dynamic_field (resolved_type->field (i), addr_stack, frame); new_bit_length = resolved_type->field (i).loc_bitpos (); if (resolved_type->field (i).bitsize () != 0) @@ -2797,7 +2856,7 @@ resolve_dynamic_struct (struct type *type, static struct type * resolve_dynamic_type_internal (struct type *type, - struct property_addr_info *addr_stack, + const property_addr_info *addr_stack, const frame_info_ptr &frame, bool top_level) { diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 5ee9deb..67b4bf0 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -259,7 +259,7 @@ enum dynamic_prop_kind { PROP_UNDEFINED, /* Not defined. */ PROP_CONST, /* Constant. */ - PROP_ADDR_OFFSET, /* Address offset. */ + PROP_FIELD, /* Field of a type. */ PROP_LOCEXPR, /* Location expression. */ PROP_LOCLIST, /* Location list. */ PROP_VARIANT_PARTS, /* Variant parts. */ @@ -347,7 +347,7 @@ struct dynamic_prop { gdb_assert (m_kind == PROP_LOCEXPR || m_kind == PROP_LOCLIST - || m_kind == PROP_ADDR_OFFSET); + || m_kind == PROP_FIELD); return m_data.baton; } @@ -364,9 +364,9 @@ struct dynamic_prop m_data.baton = baton; } - void set_addr_offset (const dwarf2_property_baton *baton) + void set_field (const dwarf2_property_baton *baton) { - m_kind = PROP_ADDR_OFFSET; + m_kind = PROP_FIELD; m_data.baton = baton; } @@ -2629,6 +2629,41 @@ extern struct type *resolve_dynamic_type "dynamic". */ extern bool is_dynamic_type (struct type *type); +/* Resolve any dynamic components of FIELD. FIELD is updated. + ADDR_STACK and FRAME are used where necessary to supply information + for the resolution process; see resolve_dynamic_type. + Specifically, after calling this, the field's bit position will be + a constant, and the field's type will not have dynamic properties. + + This function assumes that FIELD is not a static field. */ + +extern void resolve_dynamic_field (struct field &field, + const struct property_addr_info *addr_stack, + const frame_info_ptr &frame); + +/* A helper function that handles the DWARF semantics for + DW_AT_bit_offset. + + DWARF 3 specified DW_AT_bit_offset in a funny way, making it simple + to use on big-endian targets but somewhat difficult for + little-endian. This function handles the logic here. + + While DW_AT_bit_offset was deprecated in DWARF 4 (and removed + entirely from DWARF 5), it is still useful because it is the only + way to describe a field that appears at a non-constant bit + offset. + + FIELD is updated in-place. It is assumed that FIELD already has a + constant bit position. BIT_OFFSET is the value of the + DW_AT_bit_offset attribute, and EXPLICIT_BYTE_SIZE is either the + value of a DW_AT_byte_size from the field's DIE -- indicating an + explicit size of the enclosing anonymous object -- or it may be 0, + indicating that the field's type size should be used. */ + +extern void apply_bit_offset_to_field (struct field &field, + LONGEST bit_offset, + LONGEST explicit_byte_size); + extern struct type *check_typedef (struct type *); extern void check_stub_method_group (struct type *, int); diff --git a/gdb/guile/scm-color.c b/gdb/guile/scm-color.c index 4850575..cde22e5 100644 --- a/gdb/guile/scm-color.c +++ b/gdb/guile/scm-color.c @@ -24,6 +24,7 @@ #include "language.h" #include "arch-utils.h" #include "guile-internal.h" +#include "cli/cli-style.h" /* A GDB color. */ @@ -354,8 +355,14 @@ gdbscm_color_escape_sequence (SCM self, SCM is_fg_scm) const ui_file_style::color &color = coscm_get_color (self); SCM_ASSERT_TYPE (gdbscm_is_bool (is_fg_scm), is_fg_scm, SCM_ARG2, FUNC_NAME, _("boolean")); - bool is_fg = gdbscm_is_true (is_fg_scm); - std::string s = color.to_ansi (is_fg); + + std::string s; + if (term_cli_styling ()) + { + bool is_fg = gdbscm_is_true (is_fg_scm); + s = color.to_ansi (is_fg); + } + return gdbscm_scm_from_host_string (s.c_str (), s.size ()); } diff --git a/gdb/python/py-color.c b/gdb/python/py-color.c index e208506..3bbd22d 100644 --- a/gdb/python/py-color.c +++ b/gdb/python/py-color.c @@ -21,6 +21,7 @@ #include "python-internal.h" #include "py-color.h" #include "cli/cli-decode.h" +#include "cli/cli-style.h" /* Colorspace constants and their values. */ static struct { @@ -152,8 +153,12 @@ colorpy_escape_sequence (PyObject *self, PyObject *args, PyObject *kwargs) /* The argument parsing ensures we have a bool. */ gdb_assert (PyBool_Check (is_fg_obj)); - bool is_fg = is_fg_obj == Py_True; - std::string s = gdbpy_get_color (self).to_ansi (is_fg); + std::string s; + if (term_cli_styling ()) + { + bool is_fg = is_fg_obj == Py_True; + s = gdbpy_get_color (self).to_ansi (is_fg); + } return host_string_to_python_string (s.c_str ()).release (); } diff --git a/gdb/testsuite/gdb.ada/dyn-bit-offset.exp b/gdb/testsuite/gdb.ada/dyn-bit-offset.exp new file mode 100644 index 0000000..19d16b1 --- /dev/null +++ b/gdb/testsuite/gdb.ada/dyn-bit-offset.exp @@ -0,0 +1,46 @@ +# Copyright 2025 Free Software Foundation, Inc. +# +# 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/>. + +load_lib "ada.exp" + +require allow_ada_tests + +standard_ada_testfile exam + +set flags {debug} +if {[ada_minimal_encodings]} { + lappend flags additional_flags=-fgnat-encodings=minimal +} + +if {[gdb_compile_ada "${srcfile}" "${binfile}" executable $flags] != ""} { + return -1 +} + +clean_restart ${testfile} + +set bp_location [gdb_get_line_number "STOP" ${testdir}/exam.adb] +runto "exam.adb:$bp_location" + +gdb_test_multiple "print spr" "" { + -re -wrap " = \\(discr => 3, array_field => \\(-5, -6, -7\\), field => -4, another_field => -6\\)" { + pass $gdb_test_name + } + -re -wrap " = \\(discr => 3, array_field => \\(-5, -6, -7\\), field => -4, another_field => -4\\)" { + # A known GCC bug. + xfail $gdb_test_name + } +} + +gdb_test "print spr.field" " = -4" diff --git a/gdb/testsuite/gdb.ada/dyn-bit-offset/exam.adb b/gdb/testsuite/gdb.ada/dyn-bit-offset/exam.adb new file mode 100644 index 0000000..a882afd --- /dev/null +++ b/gdb/testsuite/gdb.ada/dyn-bit-offset/exam.adb @@ -0,0 +1,45 @@ +-- Copyright 2025 Free Software Foundation, Inc. +-- +-- 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/>. + +procedure Exam is + type Small is range -7 .. -4; + for Small'Size use 2; + + type Packed_Array is array (Integer range <>) of Small; + pragma pack (Packed_Array); + + subtype Range_Int is Natural range 0 .. 7; + + type Some_Packed_Record (Discr : Range_Int := 3) is record + Array_Field : Packed_Array (1 .. Discr); + Field: Small; + case Discr is + when 3 => + Another_Field : Small; + when others => + null; + end case; + end record; + pragma Pack (Some_Packed_Record); + pragma No_Component_Reordering (Some_Packed_Record); + + SPR : Some_Packed_Record := (Discr => 3, + Field => -4, + Another_Field => -6, + Array_Field => (-5, -6, -7)); + +begin + null; -- STOP +end Exam; diff --git a/gdb/testsuite/gdb.ada/fixed_points.exp b/gdb/testsuite/gdb.ada/fixed_points.exp index 8bb9e10..0e65004 100644 --- a/gdb/testsuite/gdb.ada/fixed_points.exp +++ b/gdb/testsuite/gdb.ada/fixed_points.exp @@ -90,6 +90,10 @@ foreach_gnat_encoding scenario flags {all minimal} { # This only started working in GCC 11. if {$scenario == "minimal" && [gnat_version_compare >= 11]} { gdb_test "print fp5_var" " = 3e-19" + + gdb_test "print Float(Object_Fixed) = Float(Semicircle_Delta * 5)" \ + " = true" \ + "examine object_fixed" } # This failed before GCC 10. diff --git a/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb b/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb index adab614..94a41b9 100644 --- a/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb +++ b/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb @@ -64,6 +64,12 @@ procedure Fixed_Points is for Another_Type'size use 64; Another_Fixed : Another_Type := Another_Delta * 5; + Semicircle_Delta : constant := 1.0/(2**31); + type Semicircle_Type is delta Semicircle_Delta range -1.0 .. (1.0 - Semicircle_Delta); + for Semicircle_Type'small use Semicircle_Delta; + for Semicircle_Type'size use 32; + Object_Fixed : Semicircle_Type := Semicircle_Delta * 5; + begin Base_Object := 1.0/16.0; -- Set breakpoint here Subtype_Object := 1.0/16.0; @@ -75,4 +81,5 @@ begin Do_Nothing (FP4_Var'Address); Do_Nothing (FP5_Var'Address); Do_Nothing (Another_Fixed'Address); + Do_Nothing (Object_Fixed'Address); end Fixed_Points; diff --git a/gdb/testsuite/gdb.ada/packed_record_2.exp b/gdb/testsuite/gdb.ada/packed_record_2.exp new file mode 100644 index 0000000..d0bcdbd --- /dev/null +++ b/gdb/testsuite/gdb.ada/packed_record_2.exp @@ -0,0 +1,61 @@ +# Copyright 2025 Free Software Foundation, Inc. +# +# 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/>. + +load_lib "ada.exp" + +require allow_ada_tests + +standard_ada_testfile exam + +set flags {debug} +if {[ada_minimal_encodings]} { + lappend flags additional_flags=-fgnat-encodings=minimal +} + +if {[gdb_compile_ada "${srcfile}" "${binfile}" executable $flags] != ""} { + return -1 +} + +clean_restart ${testfile} + +set bp_location [gdb_get_line_number "STOP" ${testdir}/exam.adb] +runto "exam.adb:$bp_location" + +set spr_contents "discr => 3, field => -4, array_field => \\(-5, -6, -7\\)" + +gdb_test "print spr" " = \\($spr_contents\\)" + +gdb_test "print spr.discr" " = 3" + +# See PR ada/32880 -- gdb should probably print array (1 .. 3) here, +# but instead shows array (<>). However as this isn't totally +# relevant to this test, we just accept it. +gdb_test "ptype spr" \ + [multi_line \ + "type = tagged record" \ + " discr: range 1 .. 8;" \ + " field: range -7 .. -4;" \ + " array_field: array \\(<>\\) of exam.small <packed: 2-bit elements>;" \ + "end record"] + +gdb_test_multiple "print sc" "" { + -re " \\($spr_contents, outer => 2, another_array => \\(-7, -6\\)\\)" { + pass $gdb_test_name + } + -re " \\($spr_contents, outer => $decimal, another_array => \\(.*\\)\\)" { + # Other output is a known GCC bug. + xfail $gdb_test_name + } +} diff --git a/gdb/testsuite/gdb.ada/packed_record_2/exam.adb b/gdb/testsuite/gdb.ada/packed_record_2/exam.adb new file mode 100644 index 0000000..e528ecf --- /dev/null +++ b/gdb/testsuite/gdb.ada/packed_record_2/exam.adb @@ -0,0 +1,51 @@ +-- Copyright 2025 Free Software Foundation, Inc. +-- +-- 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/>. + +procedure Exam is + type Small is range -7 .. -4; + for Small'Size use 2; + + type Range_Int is range 1 .. 8; + for Range_Int'Size use 3; + + type Packed_Array is array (Range_Int range <>) of Small; + pragma pack (Packed_Array); + + type Some_Packed_Record (Discr : Range_Int) is tagged record + Field: Small; + Array_Field : Packed_Array (1 .. Discr); + end record; + pragma Pack (Some_Packed_Record); + + type Sub_Class (Inner, Outer : Range_Int) + is new Some_Packed_Record (Inner) with + record + Another_Array : Packed_Array (1 .. Outer); + end record; + pragma Pack (Sub_Class); + + SPR : Some_Packed_Record := (Discr => 3, + Field => -4, + Array_Field => (-5, -6, -7)); + + SC : Sub_Class := (Inner => 3, + Outer => 2, + Field => -4, + Array_Field => (-5, -6, -7), + Another_Array => (-7, -6)); + +begin + null; -- STOP +end Exam; diff --git a/gdb/testsuite/gdb.ada/task_switch_in_core.exp b/gdb/testsuite/gdb.ada/task_switch_in_core.exp index 3aafc2b..bded377 100644 --- a/gdb/testsuite/gdb.ada/task_switch_in_core.exp +++ b/gdb/testsuite/gdb.ada/task_switch_in_core.exp @@ -15,7 +15,7 @@ load_lib "ada.exp" -require allow_ada_tests +require allow_ada_tests gcore_cmd_available standard_ada_testfile crash diff --git a/gdb/testsuite/gdb.base/coredump-filter-build-id.exp b/gdb/testsuite/gdb.base/coredump-filter-build-id.exp index 7594cc2..eb5b489 100644 --- a/gdb/testsuite/gdb.base/coredump-filter-build-id.exp +++ b/gdb/testsuite/gdb.base/coredump-filter-build-id.exp @@ -28,7 +28,7 @@ if { ![istarget *-*-linux*] } { untested "$testfile.exp" return -1 } -require is_x86_64_m64_target +require is_x86_64_m64_target gcore_cmd_available if { [prepare_for_testing "failed to prepare" $testfile $srcfile {debug build-id}] } { return -1 diff --git a/gdb/testsuite/gdb.base/gcore.exp b/gdb/testsuite/gdb.base/gcore.exp index 5251e3f..0a9f099 100644 --- a/gdb/testsuite/gdb.base/gcore.exp +++ b/gdb/testsuite/gdb.base/gcore.exp @@ -16,6 +16,7 @@ # This file was written by Michael Snyder (msnyder@redhat.com) # This is a test for the gdb command "generate-core-file". +require gcore_cmd_available standard_testfile diff --git a/gdb/testsuite/gdb.base/print-symbol-loading.exp b/gdb/testsuite/gdb.base/print-symbol-loading.exp index 15f2c19..c9e2480 100644 --- a/gdb/testsuite/gdb.base/print-symbol-loading.exp +++ b/gdb/testsuite/gdb.base/print-symbol-loading.exp @@ -15,7 +15,7 @@ # Test the "print symbol-loading" option. -require allow_shlib_tests +require allow_shlib_tests gcore_cmd_available standard_testfile print-symbol-loading-main.c set libfile print-symbol-loading-lib diff --git a/gdb/testsuite/gdb.base/solib-search.exp b/gdb/testsuite/gdb.base/solib-search.exp index 2efad18..35b0314 100644 --- a/gdb/testsuite/gdb.base/solib-search.exp +++ b/gdb/testsuite/gdb.base/solib-search.exp @@ -16,7 +16,7 @@ # Test solib-search-path, and in the case of solib-svr4.c whether l_addr_p # is properly reset when the path is changed. -require allow_shlib_tests +require allow_shlib_tests gcore_cmd_available require {!is_remote target} # Build "wrong" and "right" versions of the libraries in separate directories. diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp index 74e4a92..52d0229 100644 --- a/gdb/testsuite/gdb.cp/templates.exp +++ b/gdb/testsuite/gdb.cp/templates.exp @@ -58,9 +58,9 @@ proc test_ptype_of_templates {} { xfail "ptype T5<int> (obsolescent gcc or gdb)" } -re "type = class T5<int> \{${ws}public:${ws}static int X;${ws}int x;${ws}int val;${ws}void T5\\(int\\);${ws}void T5\\((T5<int> const|const T5<int>) ?&\\);${ws}~T5\\(\\);${ws}static void \\* operator new\\((size_t|unsigned( int| long|))\\);${ws}static void operator delete\\(void ?\\*\\);${ws}int value\\((void|)\\);${ws}\}\r\n$gdb_prompt $" { - # This also triggers gdb/1113... - kfail "gdb/1111" "ptype T5<int>" - # Add here a PASS case when PR gdb/1111 gets fixed. + # This also triggers gdb/8218... + kfail "gdb/8216" "ptype T5<int>" + # Add here a PASS case when PR gdb/8216 gets fixed. # These are really: # http://sourceware.org/bugzilla/show_bug.cgi?id=8216 # http://sourceware.org/bugzilla/show_bug.cgi?id=8218 @@ -98,9 +98,9 @@ proc test_ptype_of_templates {} { xfail "ptype t5i (obsolescent gcc or gdb) -- without size_t" } -re "type = class T5<int> \{${ws}public:${ws}static int X;${ws}int x;${ws}int val;${ws}void T5\\(int\\);${ws}void T5\\((T5<int> const|const T5<int>) ?&\\);${ws}~T5\\(\\);${ws}static void \\* operator new\\((size_t|unsigned( int| long|))\\);${ws}static void operator delete\\(void ?\\*\\);${ws}int value\\((void|)\\);${ws}\}\r\n$gdb_prompt $" { - # This also triggers gdb/1113... - kfail "gdb/1111" "ptype t5i" - # Add here a PASS case when PR gdb/1111 gets fixed. + # This also triggers gdb/8218... + kfail "gdb/8216" "ptype t5i" + # Add here a PASS case when PR gdb/8216 gets fixed. # These are really: # http://sourceware.org/bugzilla/show_bug.cgi?id=8216 # http://sourceware.org/bugzilla/show_bug.cgi?id=8218 @@ -132,7 +132,7 @@ proc test_template_breakpoints {} { "constructor breakpoint" } -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. T5 at .*\[\r\n\]*.3. T5 at .*\[\r\n\]*> $" { - setup_kfail "gdb/1062" "*-*-*" + setup_kfail "gdb/8167" "*-*-*" gdb_test "0" \ "nonsense intended to insure that this test fails" \ "constructor breakpoint" @@ -151,7 +151,7 @@ proc test_template_breakpoints {} { } -re "the class `T5<int>' does not have destructor defined\r\nHint: try 'T5<int>::~T5<TAB> or 'T5<int>::~T5<ESC-\\?>\r\n\\(Note leading single quote.\\)\r\n$gdb_prompt $" { - kfail "gdb/1112" "destructor breakpoint" + kfail "gdb/8217" "destructor breakpoint" } } @@ -307,7 +307,7 @@ gdb_test_multiple "ptype/r Foo" "ptype Foo" { } -re "type = class Foo<int> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int foo\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" { # GCC 3.1, DWARF-2 output. - kfail "gdb/57" "ptype Foo" + kfail "gdb/7162" "ptype Foo" } -re "No symbol \"Foo\" in current context.\r\n$gdb_prompt $" { # GCC 2.95.3, stabs+ output. @@ -342,28 +342,25 @@ gdb_test_multiple "ptype/r fchar" "ptype fchar" { # ptype Foo<volatile char *> gdb_test_multiple "ptype/r fvpchar" "ptype fvpchar" { - -re "type = (class |)Foo<volatile char ?\\*> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*.*char.*\\*t;\r\n\r\n\[ \t\]*.*char \\* foo\\(int,.*char.*\\*\\);\r\n\\}\r\n$gdb_prompt $" { - pass "ptype fvpchar" - } - -re "type = (class |)Foo<volatile char ?\\*> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*.*char.*\\*t;\r\n\r\n\[ \t\]*.*char \\* foo\\(int,.*char.*\\*\\);.*\r\n\\}\r\n$gdb_prompt $" { + -re "type = class Foo<char volatile\\*> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*volatile char \\*t;\r\n\r\n\[ \t\]*volatile char \\* foo\\(int, volatile char \\*\\);.*\r\n\\}\r\n$gdb_prompt $" { pass "ptype fvpchar" } -re "type = (class |)Foo<char volatile ?\\*> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*.*char.*\\*t;\r\n\r\n\[ \t\]*.*char \\* foo\\(int,.*char.*\\*\\);\r\n\\}\r\n$gdb_prompt $" { - kfail "gdb/1512" "ptype fvpchar" + kfail "gdb/8617" "ptype fvpchar" } } # print a function from Foo<volatile char *> # This test is sensitive to whitespace matching, so we'll do it twice, -# varying the spacing, because of PR gdb/33. +# varying the spacing, because of PR gdb/7138. gdb_test_multiple "print Foo<volatile char *>::foo" "print Foo<volatile char *>::foo" { -re "\\$\[0-9\]* = \\{.*char \\*\\((class |)Foo<(volatile char|char volatile) ?\\*> \\*(| const), int, .*char \\*\\)\\} $hex <Foo<.*char.*\\*>::foo\\(int, .*char.*\\*\\)>\r\n$gdb_prompt $" { pass "print Foo<volatile char *>::foo" } -re "No symbol \"Foo<volatile char \\*>\" in current context.\r\n$gdb_prompt $" { - # This used to be a kfail gdb/33 and then kfail gdb/931. + # This used to be a kfail gdb/7138 and then kfail gdb/8036. fail "print Foo<volatile char *>::foo" } } @@ -373,7 +370,7 @@ gdb_test_multiple "print Foo<volatile char*>::foo" "print Foo<volatile char*>::f pass "print Foo<volatile char*>::foo" } -re "No symbol \"Foo<volatile char\\*>\" in current context.\r\n$gdb_prompt $" { - # This used to be a kfail gdb/33 and then kfail gdb/931. + # This used to be a kfail gdb/7138 and then kfail gdb/8036. fail "print Foo<volatile char*>::foo" } } @@ -390,7 +387,7 @@ gdb_test_multiple "ptype/r Bar" "ptype Bar" { } -re "ptype Bar\r\ntype = class Bar<int, ?33> {\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int bar\\(int, int\\);\r\n}\r\n$gdb_prompt $" { # GCC 3.1, DWARF-2 output. - kfail "gdb/57" "ptype Bar" + kfail "gdb/7162" "ptype Bar" } -re "No symbol \"Bar\" in current context.\r\n$gdb_prompt $" { # GCC 2.95.3, stabs+ output. @@ -433,11 +430,11 @@ gdb_test_multiple "ptype/r Baz" "ptype Baz" { } -re "type = class Baz<int, ?'s'> {\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int baz\\(int, int\\);\r\n}\r\n$gdb_prompt $" { # GCC 3.1, DWARF-2 output. - kfail "gdb/57" "ptype Baz" + kfail "gdb/7162" "ptype Baz" } -re "type = class Baz<int, ?(\\(char\\))?115> {\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int baz\\(int, int\\);\r\n}\r\n$gdb_prompt $" { - # GCC 3.x, DWARF-2 output, running into gdb/57 and gdb/1512. - kfail "gdb/57" "ptype Baz" + # GCC 3.x, DWARF-2 output, running into gdb/7162 and gdb/8617. + kfail "gdb/7162" "ptype Baz" } -re "No symbol \"Baz\" in current context.\r\n$gdb_prompt $" { # GCC 2.95.3, stabs+ output. @@ -479,11 +476,11 @@ gdb_test_multiple "ptype/r Qux" "ptype Qux" { } -re "type = class Qux<char, ?&string> {\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*char t;\r\n\r\n\[ \t\]*char qux\\(int, char\\);\r\n}\r\n$gdb_prompt $" { # GCC 3.1, DWARF-2 output. - kfail "gdb/57" "ptype Qux" + kfail "gdb/7162" "ptype Qux" } -re "type = class Qux<char, ?&\\(string\\)> {\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*char t;\r\n\r\n\[ \t\]*char qux\\(int, char\\);\r\n}\r\n$gdb_prompt $" { - # GCC 3.x, DWARF-2 output; gdb/57 + gdb/1512. - kfail "gdb/57" "ptype Qux" + # GCC 3.x, DWARF-2 output; gdb/7162 + gdb/8617. + kfail "gdb/7162" "ptype Qux" } -re "No symbol \"Qux\" in current context.\r\n$gdb_prompt $" { # GCC 2.95.3, stabs+ output. @@ -507,7 +504,7 @@ gdb_test_multiple "ptype/r quxint" "ptype quxint" { pass "ptype quxint" } -re "type = class Qux<int, ?& ?\\(string\\)> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int qux\\(int, int\\);.*\r\n\\}\r\n$gdb_prompt $" { - kfail "gdb/1512" "ptype quxint" + kfail "gdb/8617" "ptype quxint" } } @@ -524,7 +521,7 @@ gdb_test_multiple "ptype/r Spec" "ptype Spec" { } -re "type = class Spec<int, ?char> {\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\r\n\[ \t\]*int spec\\(char\\);\r\n}\r\n$gdb_prompt $" { # GCC 3.1, DWARF-2 output. - kfail "gdb/57" "ptype Spec" + kfail "gdb/7162" "ptype Spec" } -re "No symbol \"Spec\" in current context.\r\n$gdb_prompt $" { # GCC 2.95.3, stabs+ output. diff --git a/gdb/testsuite/gdb.guile/scm-color.exp b/gdb/testsuite/gdb.guile/scm-color.exp index bbc9e71..578f712 100644 --- a/gdb/testsuite/gdb.guile/scm-color.exp +++ b/gdb/testsuite/gdb.guile/scm-color.exp @@ -20,7 +20,10 @@ load_lib gdb-guile.exp require allow_guile_tests -clean_restart +# Start GDB with styling support. +with_ansi_styling_terminal { + clean_restart +} gdb_install_guile_utils gdb_install_guile_module @@ -108,3 +111,8 @@ gdb_test [concat "guile " \ "\033\\\[31m\033\\\[42mred on green\033\\\[49m red on default\033\\\[39m" \ "escape sequences" +# Ensure that turning styling off means no escape sequences. +gdb_test_no_output "set style enabled off" +gdb_test_no_output "guile (display (color-escape-sequence c_red #t))" +gdb_test_no_output "guile (display (color-escape-sequence c_red #f))" +gdb_test_no_output "set style enabled on" diff --git a/gdb/testsuite/gdb.python/py-color.exp b/gdb/testsuite/gdb.python/py-color.exp index 3563d22..2601cf3 100644 --- a/gdb/testsuite/gdb.python/py-color.exp +++ b/gdb/testsuite/gdb.python/py-color.exp @@ -19,8 +19,10 @@ load_lib gdb-python.exp require allow_python_tests -# Start with a fresh gdb. -clean_restart +# Start with a fresh GDB, but enable color support. +with_ansi_styling_terminal { + clean_restart +} gdb_test_no_output "python get_color_attrs = lambda c: \"%s %s %s %s %s\" % (str(c), c.colorspace, c.is_none, c.is_indexed, c.is_direct)" \ "get_color_attrs helper" @@ -115,6 +117,12 @@ gdb_test [concat "python print (c_red.escape_sequence (is_foreground = True) + " "\033\\\[31m\033\\\[42mred on green\033\\\[49m red on default\033\\\[39m" \ "escape sequences using keyword arguments" +# Ensure that turning styling off means no escape sequences. +gdb_test_no_output "set style enabled off" +gdb_test_no_output "python print (c_red.escape_sequence (True), end='')" +gdb_test_no_output "python print (c_red.escape_sequence (False), end='')" +gdb_test_no_output "set style enabled on" + gdb_test_multiline "Try to sub-class gdb.Color" \ "python" "" \ "class my_color(gdb.Color):" "" \ diff --git a/gdb/testsuite/gdb.rocm/mi-attach.exp b/gdb/testsuite/gdb.rocm/mi-attach.exp index 2ca610c..37ce92a 100644 --- a/gdb/testsuite/gdb.rocm/mi-attach.exp +++ b/gdb/testsuite/gdb.rocm/mi-attach.exp @@ -13,10 +13,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +load_lib rocm.exp load_lib mi-support.exp set MIFLAGS "-i=mi" -require can_spawn_for_attach +require can_spawn_for_attach allow_hipcc_tests standard_testfile .cpp diff --git a/gdb/testsuite/gdb.tui/corefile-run.exp b/gdb/testsuite/gdb.tui/corefile-run.exp index 89a48b5..657fc83 100644 --- a/gdb/testsuite/gdb.tui/corefile-run.exp +++ b/gdb/testsuite/gdb.tui/corefile-run.exp @@ -18,6 +18,8 @@ # # Ref.: https://bugzilla.redhat.com/show_bug.cgi?id=1765117 +require gcore_cmd_available + tuiterm_env standard_testfile tui-layout.c diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index ead14bd..2a5d37c 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -7007,6 +7007,24 @@ proc gdb_load_cmd { args } { return -1 } +# Return non-zero if 'gcore' command is available. +gdb_caching_proc gcore_cmd_available { } { + gdb_exit + gdb_start + + # Does this gdb support gcore? + gdb_test_multiple "help gcore" "" { + -re -wrap "Undefined command: .*" { + return 0 + } + -re -wrap "Save a core file .*" { + return 1 + } + } + + return 0 +} + # Invoke "gcore". CORE is the name of the core file to write. TEST # is the name of the test case. This will return 1 if the core file # was created, 0 otherwise. If this fails to make a core file because diff --git a/gdb/unittests/utils-selftests.c b/gdb/unittests/utils-selftests.c deleted file mode 100644 index b1c457c..0000000 --- a/gdb/unittests/utils-selftests.c +++ /dev/null @@ -1,59 +0,0 @@ -/* Unit tests for the utils.c file. - - Copyright (C) 2018-2025 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 "utils.h" -#include "gdbsupport/selftest.h" - -namespace selftests { -namespace utils { - -static void -test_substitute_path_component () -{ - auto test = [] (std::string s, const char *from, const char *to, - const char *expected) - { - char *temp = xstrdup (s.c_str ()); - substitute_path_component (&temp, from, to); - SELF_CHECK (strcmp (temp, expected) == 0); - xfree (temp); - }; - - test ("/abc/$def/g", "abc", "xyz", "/xyz/$def/g"); - test ("abc/$def/g", "abc", "xyz", "xyz/$def/g"); - test ("/abc/$def/g", "$def", "xyz", "/abc/xyz/g"); - test ("/abc/$def/g", "g", "xyz", "/abc/$def/xyz"); - test ("/abc/$def/g", "ab", "xyz", "/abc/$def/g"); - test ("/abc/$def/g", "def", "xyz", "/abc/$def/g"); - test ("/abc/$def/g", "abc", "abc", "/abc/$def/g"); - test ("/abc/$def/g", "abc", "", "//$def/g"); - test ("/abc/$def/g", "abc/$def", "xyz", "/xyz/g"); - test ("/abc/$def/abc", "abc", "xyz", "/xyz/$def/xyz"); -} - -} -} - -void _initialize_utils_selftests (); -void -_initialize_utils_selftests () -{ - selftests::register_test ("substitute_path_component", - selftests::utils::test_substitute_path_component); -} diff --git a/gdb/utils.c b/gdb/utils.c index 6cdc3f4..7b0c812 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -3375,51 +3375,6 @@ parse_pid_to_attach (const char *args) return pid; } -/* Substitute all occurrences of string FROM by string TO in *STRINGP. *STRINGP - must come from xrealloc-compatible allocator and it may be updated. FROM - needs to be delimited by IS_DIR_SEPARATOR or DIRNAME_SEPARATOR (or be - located at the start or end of *STRINGP. */ - -void -substitute_path_component (char **stringp, const char *from, const char *to) -{ - char *string = *stringp, *s; - const size_t from_len = strlen (from); - const size_t to_len = strlen (to); - - for (s = string;;) - { - s = strstr (s, from); - if (s == NULL) - break; - - if ((s == string || IS_DIR_SEPARATOR (s[-1]) - || s[-1] == DIRNAME_SEPARATOR) - && (s[from_len] == '\0' || IS_DIR_SEPARATOR (s[from_len]) - || s[from_len] == DIRNAME_SEPARATOR)) - { - char *string_new; - - string_new - = (char *) xrealloc (string, (strlen (string) + to_len + 1)); - - /* Relocate the current S pointer. */ - s = s - string + string_new; - string = string_new; - - /* Replace from by to. */ - memmove (&s[to_len], &s[from_len], strlen (&s[from_len]) + 1); - memcpy (s, to, to_len); - - s += to_len; - } - else - s++; - } - - *stringp = string; -} - #ifdef HAVE_WAITPID #ifdef SIGALRM diff --git a/gdb/utils.h b/gdb/utils.h index bc8c2ef..a8834cf 100644 --- a/gdb/utils.h +++ b/gdb/utils.h @@ -133,9 +133,6 @@ private: extern int gdb_filename_fnmatch (const char *pattern, const char *string, int flags); -extern void substitute_path_component (char **stringp, const char *from, - const char *to); - std::string ldirname (const char *filename); extern int count_path_elements (const char *path); diff --git a/gdb/value.c b/gdb/value.c index 0f1be2e..41dce77 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -3266,6 +3266,9 @@ unpack_bits_as_long (struct type *field_type, const gdb_byte *valaddr, } } + if (field_type->code () == TYPE_CODE_RANGE) + val += field_type->bounds ()->bias; + return val; } @@ -3296,21 +3299,28 @@ unpack_value_field_as_long (struct type *type, const gdb_byte *valaddr, return 1; } -/* Unpack a field FIELDNO of the specified TYPE, from the anonymous - object at VALADDR. See unpack_bits_as_long for more details. */ +/* See value.h. */ LONGEST -unpack_field_as_long (struct type *type, const gdb_byte *valaddr, int fieldno) +unpack_field_as_long (const gdb_byte *valaddr, struct field *field) { - int bitpos = type->field (fieldno).loc_bitpos (); - int bitsize = type->field (fieldno).bitsize (); - struct type *field_type = type->field (fieldno).type (); + int bitpos = field->loc_bitpos (); + int bitsize = field->bitsize (); + struct type *field_type = field->type (); return unpack_bits_as_long (field_type, valaddr, bitpos, bitsize); } /* See value.h. */ +LONGEST +unpack_field_as_long (struct type *type, const gdb_byte *valaddr, int fieldno) +{ + return unpack_field_as_long (valaddr, &type->field (fieldno)); +} + +/* See value.h. */ + void value::unpack_bitfield (struct value *dest_val, LONGEST bitpos, LONGEST bitsize, diff --git a/gdb/value.h b/gdb/value.h index 71d0ba1..0c7c785 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -1058,10 +1058,19 @@ extern gdb_mpz value_as_mpz (struct value *val); extern LONGEST unpack_long (struct type *type, const gdb_byte *valaddr); extern CORE_ADDR unpack_pointer (struct type *type, const gdb_byte *valaddr); +/* Unpack a field FIELDNO of the specified TYPE, from the anonymous + object at VALADDR. See unpack_bits_as_long for more details. */ + extern LONGEST unpack_field_as_long (struct type *type, const gdb_byte *valaddr, int fieldno); +/* Unpack a field, FIELD, from the anonymous object at VALADDR. See + unpack_bits_as_long for more details. */ + +extern LONGEST unpack_field_as_long (const gdb_byte *valaddr, + struct field *field); + /* Unpack a bitfield of the specified FIELD_TYPE, from the object at VALADDR, and store the result in *RESULT. The bitfield starts at BITPOS bits and contains BITSIZE bits; if |