return gdb::optional<ULONGEST> ();
}
- /* Return range lists base of the compile unit, which, if exists, is
- stored either at the attribute DW_AT_rnglists_base or
- DW_AT_GNU_ranges_base. */
- ULONGEST ranges_base ()
+ /* Return the base address of the compile unit into the .debug_ranges section,
+ which, if exists, is stored in the DW_AT_GNU_ranges_base attribute. This
+ value is only relevant in pre-DWARF 5 split-unit scenarios. */
+ ULONGEST gnu_ranges_base ()
{
for (unsigned i = 0; i < num_attrs; ++i)
- if (attrs[i].name == DW_AT_rnglists_base
- || attrs[i].name == DW_AT_GNU_ranges_base)
+ if (attrs[i].name == DW_AT_GNU_ranges_base)
{
if (attrs[i].form_is_unsigned ())
- {
- /* If both exist, just use the first one. */
- return attrs[i].as_unsigned ();
- }
- complaint (_("ranges base attribute (offset %s) as wrong form"),
+ return attrs[i].as_unsigned ();
+
+ complaint (_("ranges base attribute (offset %s) has wrong form"),
sect_offset_str (sect_off));
}
+
return 0;
}
+ /* Return the rnglists base of the compile unit, which, if exists, is stored
+ in the DW_AT_rnglists_base attribute. */
+ ULONGEST rnglists_base ()
+ {
+ for (unsigned i = 0; i < num_attrs; ++i)
+ if (attrs[i].name == DW_AT_rnglists_base)
+ {
+ if (attrs[i].form_is_unsigned ())
+ return attrs[i].as_unsigned ();
+
+ complaint (_("rnglists base attribute (offset %s) has wrong form"),
+ sect_offset_str (sect_off));
+ }
+
+ return 0;
+ }
/* DWARF-2 tag for this DIE. */
ENUM_BITFIELD(dwarf_tag) tag : 16;
Note this value comes from the Fission stub CU/TU's DIE. */
gdb::optional<ULONGEST> addr_base;
- /* The DW_AT_rnglists_base attribute if present.
- Note this value comes from the Fission stub CU/TU's DIE.
- Also note that the value is zero in the non-DWO case so this value can
- be used without needing to know whether DWO files are in use or not.
- N.B. This does not apply to DW_AT_ranges appearing in
- DW_TAG_compile_unit dies. This is a bit of a wart, consider if ever
- DW_AT_ranges appeared in the DW_TAG_compile_unit of DWO DIEs: then
- DW_AT_rnglists_base *would* have to be applied, and we'd have to care
- whether the DW_AT_ranges attribute came from the skeleton or DWO. */
- ULONGEST ranges_base = 0;
+ /* The DW_AT_GNU_ranges_base attribute, if present.
+
+ This is only relevant in the context of pre-DWARF 5 split units. In this
+ context, there is a .debug_ranges section in the linked executable,
+ containing all the ranges data for all the compilation units. Each
+ skeleton/stub unit has (if needed) a DW_AT_GNU_ranges_base attribute that
+ indicates the base of its contribution to that section. The DW_AT_ranges
+ attributes in the split-unit are of the form DW_FORM_sec_offset and point
+ into the .debug_ranges section of the linked file. However, they are not
+ "true" DW_FORM_sec_offset, because they are relative to the base of their
+ compilation unit's contribution, rather than relative to the beginning of
+ the section. The DW_AT_GNU_ranges_base value must be added to it to make
+ it relative to the beginning of the section.
+
+ Note that the value is zero when we are not in a pre-DWARF 5 split-unit
+ case, so this value can be added without needing to know whether we are in
+ this case or not.
+
+ N.B. If a DW_AT_ranges attribute is found on the DW_TAG_compile_unit in the
+ skeleton/stub, it must not have the base added, as it already points to the
+ right place. And since the DW_TAG_compile_unit DIE in the split-unit can't
+ have a DW_AT_ranges attribute, we can use the
+
+ die->tag != DW_AT_compile_unit
+
+ to determine whether the base should be added or not. */
+ ULONGEST gnu_ranges_base = 0;
+
+ /* The DW_AT_rnglists_base attribute, if present.
+
+ This is used when processing attributes of form DW_FORM_rnglistx in
+ non-split units. Attributes of this form found in a split unit don't
+ use it, as split-unit files have their own non-shared .debug_rnglists.dwo
+ section. */
+ ULONGEST rnglists_base = 0;
/* The DW_AT_loclists_base attribute if present. */
ULONGEST loclist_base = 0;
cu->addr_base = stub_comp_unit_die->addr_base ();
- /* There should be a DW_AT_rnglists_base (DW_AT_GNU_ranges_base) attribute
- here (if needed). We need the value before we can process
- DW_AT_ranges. */
- cu->ranges_base = stub_comp_unit_die->ranges_base ();
+ /* There should be a DW_AT_GNU_ranges_base attribute here (if needed).
+ We need the value before we can process DW_AT_ranges values from the
+ DWO. */
+ cu->gnu_ranges_base = stub_comp_unit_die->gnu_ranges_base ();
+
+ /* For DWARF5: record the DW_AT_rnglists_base value from the skeleton. If
+ there are attributes of form DW_FORM_rnglistx in the skeleton, they'll
+ need the rnglists base. Attributes of form DW_FORM_rnglistx in the
+ split unit don't use it, as the DWO has its own .debug_rnglists.dwo
+ section. */
+ cu->rnglists_base = stub_comp_unit_die->rnglists_base ();
}
else if (stub_comp_dir != NULL)
{
attr = dwarf2_attr (die, DW_AT_ranges, cu);
if (attr != nullptr && attr->form_is_unsigned ())
{
- /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
- We take advantage of the fact that DW_AT_ranges does not appear
- in DW_TAG_compile_unit of DWO files.
-
- Attributes of the form DW_FORM_rnglistx have already had their
- value changed by read_rnglist_index and already include
- DW_AT_rnglists_base, so don't need to add the ranges base,
- either. */
- int need_ranges_base = (die->tag != DW_TAG_compile_unit
- && attr->form != DW_FORM_rnglistx);
- unsigned int ranges_offset = (attr->as_unsigned ()
- + (need_ranges_base
- ? cu->ranges_base
- : 0));
+ /* Offset in the .debug_ranges or .debug_rnglist section (depending
+ on DWARF version). */
+ ULONGEST ranges_offset = attr->as_unsigned ();
+
+ /* See dwarf2_cu::gnu_ranges_base's doc for why we might want to add
+ this value. */
+ if (die->tag != DW_TAG_compile_unit)
+ ranges_offset += cu->gnu_ranges_base;
/* Value of the DW_AT_ranges attribute is the offset in the
.debug_ranges section. */
attr = dwarf2_attr (die, DW_AT_ranges, cu);
if (attr != nullptr && attr->form_is_unsigned ())
{
- /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
- We take advantage of the fact that DW_AT_ranges does not appear
- in DW_TAG_compile_unit of DWO files.
-
- Attributes of the form DW_FORM_rnglistx have already had their
- value changed by read_rnglist_index and already include
- DW_AT_rnglists_base, so don't need to add the ranges base,
- either. */
- int need_ranges_base = (die->tag != DW_TAG_compile_unit
- && attr->form != DW_FORM_rnglistx);
+ /* Offset in the .debug_ranges or .debug_rnglist section (depending
+ on DWARF version). */
+ ULONGEST ranges_offset = attr->as_unsigned ();
- /* The value of the DW_AT_ranges attribute is the offset of the
- address range list in the .debug_ranges section. */
- unsigned long offset = (attr->as_unsigned ()
- + (need_ranges_base ? cu->ranges_base : 0));
+ /* See dwarf2_cu::gnu_ranges_base's doc for why we might want to add
+ this value. */
+ if (die->tag != DW_TAG_compile_unit)
+ ranges_offset += cu->gnu_ranges_base;
std::vector<blockrange> blockvec;
- dwarf2_ranges_process (offset, cu, die->tag,
+ dwarf2_ranges_process (ranges_offset, cu, die->tag,
[&] (CORE_ADDR start, CORE_ADDR end)
{
start += baseaddr;
attr = die->attr (DW_AT_rnglists_base);
if (attr != nullptr)
- cu->ranges_base = attr->as_unsigned ();
+ cu->rnglists_base = attr->as_unsigned ();
if (any_need_reprocess)
{
case DW_AT_ranges:
{
- /* DW_AT_rnglists_base does not apply to DIEs from the DWO
- skeleton. We take advantage of the fact the DW_AT_ranges
- does not appear in DW_TAG_compile_unit of DWO files.
-
- Attributes of the form DW_FORM_rnglistx have already had
- their value changed by read_rnglist_index and already
- include DW_AT_rnglists_base, so don't need to add the ranges
- base, either. */
- int need_ranges_base = (tag != DW_TAG_compile_unit
- && attr.form != DW_FORM_rnglistx);
- /* It would be nice to reuse dwarf2_get_pc_bounds here,
- but that requires a full DIE, so instead we just
- reimplement it. */
- unsigned int ranges_offset = (attr.as_unsigned ()
- + (need_ranges_base
- ? cu->ranges_base
- : 0));
-
- /* Value of the DW_AT_ranges attribute is the offset in the
- .debug_ranges section. */
+ /* Offset in the .debug_ranges or .debug_rnglist section (depending
+ on DWARF version). */
+ ULONGEST ranges_offset = attr.as_unsigned ();
+
+ /* See dwarf2_cu::gnu_ranges_base's doc for why we might want to add
+ this value. */
+ if (tag != DW_TAG_compile_unit)
+ ranges_offset += cu->gnu_ranges_base;
+
if (dwarf2_ranges_read (ranges_offset, &lowpc, &highpc, cu,
nullptr, tag))
has_pc_info = 1;
ULONGEST rnglist_header_size =
(cu->header.initial_length_size == 4 ? RNGLIST_HEADER_SIZE32
: RNGLIST_HEADER_SIZE64);
+
+ /* When reading a DW_FORM_rnglistx from a DWO, we read from the DWO's
+ .debug_rnglists.dwo section. The rnglists base given in the skeleton
+ doesn't apply. */
ULONGEST rnglist_base =
- (cu->dwo_unit != nullptr) ? rnglist_header_size : cu->ranges_base;
+ (cu->dwo_unit != nullptr) ? rnglist_header_size : cu->rnglists_base;
/* Offset in .debug_rnglists of the offset for RNGLIST_INDEX. */
ULONGEST start_offset =
set testfile ${testfile}-dw32
}
- # Get the addresses / lengths of func1 and func2.
+ # Get the addresses / lengths of functions.
lassign [function_range func1 $srcdir/$subdir/$srcfile] func1_addr func1_len
lassign [function_range func2 $srcdir/$subdir/$srcfile] func2_addr func2_len
+ lassign [function_range func3 $srcdir/$subdir/$srcfile] func3_addr func3_len
+ lassign [function_range func4 $srcdir/$subdir/$srcfile] func4_addr func4_len
set asm_file [standard_output_file $srcfile2]
Dwarf::assemble $asm_file {
global func1_addr func1_len
global func2_addr func2_len
+ global func3_addr func3_len
+ global func4_addr func4_len
global is_64
declare_labels cu_range_list foo_range_list
version 5
is_64 $is_64
} {
- declare_labels int_type
- declare_labels foo_location_list
+ declare_labels int_type1
+ declare_labels int_type2
+ declare_labels foo_location_list bar_location_list
DW_TAG_compile_unit {
} {
- int_type: DW_TAG_base_type {
+ int_type1: DW_TAG_base_type {
{DW_AT_byte_size 4 DW_FORM_data1}
{DW_AT_encoding @DW_ATE_signed}
{DW_AT_name "int"}
DW_TAG_variable {
{DW_AT_name "foo"}
{DW_AT_location $foo_location_list DW_FORM_sec_offset}
- {DW_AT_type :$int_type}
+ {DW_AT_type :$int_type1}
}
DW_TAG_subprogram {
}
}
+ # This CU uses the DW_FORM_sec_offset form to refer to the
+ # .debug_loclists section, but also has the DW_AT_loclists_base
+ # attribute present. The DW_AT_loclists_base is not used to interpret
+ # the DW_AT_location value, but it should also do no harm.
+ cu {
+ version 5
+ is_64 $is_64
+ } {
+ DW_TAG_compile_unit {
+ {DW_AT_loclists_base cu2_table DW_FORM_sec_offset}
+ } {
+ int_type2: DW_TAG_base_type {
+ {DW_AT_byte_size 4 DW_FORM_data1}
+ {DW_AT_encoding @DW_ATE_signed}
+ {DW_AT_name "int"}
+ }
+
+ DW_TAG_variable {
+ {DW_AT_name "bar"}
+ {DW_AT_location $bar_location_list DW_FORM_sec_offset}
+ {DW_AT_type :$int_type2}
+ }
+
+ DW_TAG_subprogram {
+ {DW_AT_name "func3"}
+ {DW_AT_low_pc $func3_addr}
+ {DW_AT_high_pc $func3_len DW_FORM_udata}
+ }
+
+ DW_TAG_subprogram {
+ {DW_AT_name "func4"}
+ {DW_AT_low_pc $func4_addr}
+ {DW_AT_high_pc $func4_len DW_FORM_udata}
+ }
+ }
+ }
+
loclists -is-64 $is_64 {
# The lists in this table are accessed by direct offset
# (DW_FORM_sec_offset).
}
}
}
+
+ table -post-header-label cu2_table {
+ bar_location_list: list_ {
+ start_length $func3_addr $func3_len {
+ DW_OP_constu 0x345678
+ DW_OP_stack_value
+ }
+
+ start_length $func4_addr $func4_len {
+ DW_OP_constu 0x456789
+ DW_OP_stack_value
+ }
+ }
+ }
}
}
gdb_breakpoint "func1"
gdb_breakpoint "func2"
+ gdb_breakpoint "func3"
+ gdb_breakpoint "func4"
gdb_continue_to_breakpoint "func1"
with_test_prefix "at func1" {
with_test_prefix "at func2" {
gdb_test "print /x foo" " = 0x234567"
}
+
+ gdb_continue_to_breakpoint "func3"
+ with_test_prefix "at func3" {
+ gdb_test "print /x bar" " = 0x345678"
+ }
+
+ gdb_continue_to_breakpoint "func4"
+ with_test_prefix "at func4" {
+ gdb_test "print /x bar" " = 0x456789"
+ }
}