From: Caroline Tice <cmtice@google.com>
To: Tom Tromey <tom@tromey.com>
Cc: Caroline Tice via Gdb-patches <gdb-patches@sourceware.org>,
Eric Christopher <echristo@google.com>
Subject: Re: [PATCH] Fix issues with reading rnglists, especially from dwo files, for DWARF v5
Date: Thu, 4 Jun 2020 14:39:46 -0700 [thread overview]
Message-ID: <CABtf2+SZUXnSNHNJpm7LFU2vg1cd=62dzX2_LKfc98yaeQhGDw@mail.gmail.com> (raw)
In-Reply-To: <87h7vsqk5h.fsf@tromey.com>
[-- Attachment #1: Type: text/plain, Size: 3080 bytes --]
I've been playing with running the testsuite with -gdwarf-5
-gsplit-dwarf and using the clang compiler. I did not find any tests
that showed the issues I was running into (but I did discover a small
bug in my patch, which my newer patch fixes). With my fixed patch,
there are no testsuite differences. I have created a new testsuite
test case, which does fail with current ToT and passes with my patch,
but that only works if you compile it with clang -- if you compile it
with GCC it passes in both cases (because GCC is not generating the
DW_FORM_rmglistx that my patch is handling/fixing).
I've updated the patch to include the requested format changes, remove
the pieces that are only used in an upcoming patch, fix the small
issue I found while testing, and I've added the test to the testsuite.
To run the test and see the issue:
$ make check RUNTESTFLAGS="CC_FOR_TARGET=${CLANG_CC}
CXX_FOR_TARGET=${CLANG_CXX} dw5-rnglist-test.exp"
gdb/ChangeLog (updated)
2020-06-04 Caroline Tice <cmtice@google.com>
* dwarf2/read.c (struct dwop_section_names): Add rnglists_dwo.
(dwop_section_names): Add .debug_rnglists.dwo, .zdebug_rnglists.dwo.
(struct dwo_sections): Add rnglists field.
(cu_debug_rnglist_section): New function (decl & definition).
(dwarf2_locate_dwo_sections): Add code to read rnglists_dwo section.
(dwarf2_rnglists_process): Add cases for DW_RLE_base_addressx,
DW_RLE_startx_length, DW_RLE_startx_endx. Also, update to only add
the base address to DW_RLE_offset_pairs (not to all ranges).
(dwarf2_get_pc_bounds): Check for DW_FORM_rnglistx when setting
need_ranges_base.
(dwarf2_record_block_ranges): Check for DW_FORM_rnglistx when setting
need_ranges_base.
(read_full_die_1): Add code to read DW_AT_rnglists_base and assign to
cu->ranges_base.
(partial_die_info::read): Check for DW_FORM_rnglistx when setting
need_ranges_base.
(read_rnglist_index): New function.
(read_attribute_reprocess): Add code for DW_FORM_rnglistx.
(read_attribute_value): Mark DW_FORM_rnglistx with need_reprocess.
gdb/testsuite/ChangeLog:
2020-06-04 Caroline Tice <cmtice@google.com>
* gdb.dwarf2/dw5-rnglist-test.cc: New file.
* gdb.dwarf2/dw5-rnglist-test.exp: New file.
On Wed, Jun 3, 2020 at 7:49 AM Tom Tromey <tom@tromey.com> wrote:
>
> Caroline> $ clang++ -gdwarf-5 -O0 -gsplit-dwarf pre-order.cpp
> Caroline> pre-order-common.cpp -o pre-order
>
> I wonder if the test suite can be run this way.
>
> Caroline> Oh. Those get used in my next upcoming patch (where I update GDB to
> Caroline> handle DWARFv5 .dwp files). I can either leave them in this patch, or
> Caroline> remove them from here and put them in the next one, whichever you
> Caroline> prefer.
>
> I think it's better for patches to be reasonably self-contained when
> possible.
>
> Also, there were other patches for DWARFv5 on the list in "recent" (this
> year) times. I wonder if those are relevant / related.
>
> Tom
[-- Attachment #2: gdb-dwo-rnglists.patch --]
[-- Type: application/octet-stream, Size: 14304 bytes --]
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index e6566f9649..0f904e73e0 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -340,6 +340,7 @@ static const struct dwop_section_names
struct dwarf2_section_names loclists_dwo;
struct dwarf2_section_names macinfo_dwo;
struct dwarf2_section_names macro_dwo;
+ struct dwarf2_section_names rnglists_dwo;
struct dwarf2_section_names str_dwo;
struct dwarf2_section_names str_offsets_dwo;
struct dwarf2_section_names types_dwo;
@@ -355,6 +356,7 @@ dwop_section_names =
{ ".debug_loclists.dwo", ".zdebug_loclists.dwo" },
{ ".debug_macinfo.dwo", ".zdebug_macinfo.dwo" },
{ ".debug_macro.dwo", ".zdebug_macro.dwo" },
+ { ".debug_rnglists.dwo", ".zdebug_rnglists.dwo" },
{ ".debug_str.dwo", ".zdebug_str.dwo" },
{ ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo" },
{ ".debug_types.dwo", ".zdebug_types.dwo" },
@@ -650,6 +652,7 @@ struct dwo_sections
struct dwarf2_section_info loclists;
struct dwarf2_section_info macinfo;
struct dwarf2_section_info macro;
+ struct dwarf2_section_info rnglists;
struct dwarf2_section_info str;
struct dwarf2_section_info str_offsets;
/* In the case of a virtual DWO file, these two are unused. */
@@ -1384,6 +1387,10 @@ static int dwarf2_ranges_read (unsigned, CORE_ADDR *, CORE_ADDR *,
/* Return the .debug_loclists section to use for cu. */
static struct dwarf2_section_info *cu_debug_loc_section (struct dwarf2_cu *cu);
+/* Return the .debug_rnglists section to use for cu. */
+static struct dwarf2_section_info *cu_debug_rnglist_section
+ (struct dwarf2_cu *cu);
+
/* How dwarf2_get_pc_bounds constructed its *LOWPC and *HIGHPC return
values. Keep the items ordered with increasing constraints compliance. */
enum pc_bounds_kind
@@ -12397,6 +12404,11 @@ dwarf2_locate_dwo_sections (bfd *abfd, asection *sectp, void *dwo_sections_ptr)
dwo_sections->macro.s.section = sectp;
dwo_sections->macro.size = bfd_section_size (sectp);
}
+ else if (section_is_p (sectp->name, &names->rnglists_dwo))
+ {
+ dwo_sections->rnglists.s.section = sectp;
+ dwo_sections->rnglists.size = bfd_section_size (sectp);
+ }
else if (section_is_p (sectp->name, &names->str_dwo))
{
dwo_sections->str.s.section = sectp;
@@ -13751,6 +13763,7 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
const gdb_byte *buffer;
CORE_ADDR baseaddr;
bool overflow = false;
+ ULONGEST addr_index;
base = cu->base_address;
@@ -13792,6 +13805,11 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
base = cu->header.read_address (obfd, buffer, &bytes_read);
buffer += bytes_read;
break;
+ case DW_RLE_base_addressx:
+ addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
+ buffer += bytes_read;
+ base = read_addr_index (cu, addr_index);
+ break;
case DW_RLE_start_length:
if (buffer + cu->header.addr_size > buf_end)
{
@@ -13810,6 +13828,19 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
break;
}
break;
+ case DW_RLE_startx_length:
+ addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
+ buffer += bytes_read;
+ range_beginning = read_addr_index (cu, addr_index);
+ if (buffer > buf_end)
+ {
+ overflow = true;
+ break;
+ }
+ range_end = (range_beginning
+ + read_unsigned_leb128 (obfd, buffer, &bytes_read));
+ buffer += bytes_read;
+ break;
case DW_RLE_offset_pair:
range_beginning = read_unsigned_leb128 (obfd, buffer, &bytes_read);
buffer += bytes_read;
@@ -13838,7 +13869,20 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
range_end = cu->header.read_address (obfd, buffer, &bytes_read);
buffer += bytes_read;
break;
- default:
+ case DW_RLE_startx_endx:
+ addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
+ buffer += bytes_read;
+ range_beginning = read_addr_index (cu, addr_index);
+ if (buffer > buf_end)
+ {
+ overflow = true;
+ break;
+ }
+ addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
+ buffer += bytes_read;
+ range_end = read_addr_index (cu, addr_index);
+ break;
+ default:
complaint (_("Invalid .debug_rnglists data (no base address)"));
return false;
}
@@ -13866,8 +13910,12 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
if (range_beginning == range_end)
continue;
- range_beginning += *base;
- range_end += *base;
+ /* Only DW_RLE_offset_pair needs the base address added. */
+ if (rlet == DW_RLE_offset_pair)
+ {
+ range_beginning += *base;
+ range_end += *base;
+ }
/* A not-uncommon case of bad debug info.
Don't pollute the addrmap with bad data. */
@@ -14105,7 +14153,8 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
/* 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. */
- int need_ranges_base = die->tag != DW_TAG_compile_unit;
+ int need_ranges_base = (die->tag != DW_TAG_compile_unit
+ && attr->form != DW_FORM_rnglistx);
unsigned int ranges_offset = (DW_UNSND (attr)
+ (need_ranges_base
? cu->ranges_base
@@ -14276,7 +14325,8 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block,
/* 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. */
- int need_ranges_base = die->tag != DW_TAG_compile_unit;
+ int need_ranges_base = (die->tag != DW_TAG_compile_unit
+ && attr->form != DW_FORM_rnglistx);
/* The value of the DW_AT_ranges attribute is the offset of the
address range list in the .debug_ranges section. */
@@ -18115,6 +18165,11 @@ read_full_die_1 (const struct die_reader_specs *reader,
auto maybe_addr_base = die->addr_base ();
if (maybe_addr_base.has_value ())
cu->addr_base = *maybe_addr_base;
+
+ attr = die->attr (DW_AT_rnglists_base);
+ if (attr != nullptr)
+ cu->ranges_base = DW_UNSND (attr);
+
for (int index : indexes_that_need_reprocess)
read_attribute_reprocess (reader, &die->attrs[index]);
*diep = die;
@@ -18633,7 +18688,8 @@ partial_die_info::read (const struct die_reader_specs *reader,
/* It would be nice to reuse dwarf2_get_pc_bounds here,
but that requires a full DIE, so instead we just
reimplement it. */
- int need_ranges_base = tag != DW_TAG_compile_unit;
+ int need_ranges_base = (tag != DW_TAG_compile_unit
+ && attr.form != DW_FORM_rnglistx);
unsigned int ranges_offset = (DW_UNSND (&attr)
+ (need_ranges_base
? cu->ranges_base
@@ -19043,6 +19099,49 @@ read_loclist_index (struct dwarf2_cu *cu, ULONGEST loclist_index)
return bfd_get_64 (abfd, info_ptr) + loclist_base;
}
+/* Given a DW_FORM_rnglistx value rnglist_index, fetch the offset from the
+ array of offsets in the .debug_rnglists section. */
+static CORE_ADDR
+read_rnglist_index (struct dwarf2_cu *cu, ULONGEST rnglist_index)
+{
+ struct dwarf2_per_objfile *dwarf2_per_objfile = cu->per_objfile;
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ bfd *abfd = objfile->obfd;
+ ULONGEST rnglist_header_size =
+ (cu->header.initial_length_size == 4 ? LOCLIST_HEADER_SIZE32
+ : LOCLIST_HEADER_SIZE64);
+ ULONGEST rnglist_base =
+ (cu->dwo_unit) ? rnglist_header_size : cu->ranges_base;
+
+ struct dwarf2_section_info *section = cu_debug_rnglist_section (cu);
+ if (section == nullptr)
+ error(_("Cannot find .debug_rnglists section [in module %s]"),
+ objfile_name(objfile));
+ section->read (objfile);
+ if (section->buffer == NULL)
+ error(_("DW_FORM_rnglistx used without .debug_rnglists section "
+ "[in module %s]"),
+ objfile_name (objfile));
+ struct loclist_header header;
+ read_loclist_header (&header, section);
+ if (rnglist_index >= header.offset_entry_count)
+ error(_("DW_FORM_rnglistx index pointing outside of "
+ ".debug_rnglists offset array [in module %s]"),
+ objfile_name(objfile));
+ if (rnglist_base + rnglist_index * cu->header.offset_size
+ >= section->size)
+ error(_("DW_FORM_rnglistx pointing outside of "
+ ".debug_rnglists section [in module %s]"),
+ objfile_name(objfile));
+ const gdb_byte *info_ptr
+ = section->buffer + rnglist_base + rnglist_index * cu->header.offset_size;
+
+ if (cu->header.offset_size == 4)
+ return read_4_bytes (abfd, info_ptr) + rnglist_base;
+ else
+ return read_8_bytes (abfd, info_ptr) + rnglist_base;
+}
+
/* Process the attributes that had to be skipped in the first round. These
attributes are the ones that need str_offsets_base or addr_base attributes.
They could not have been processed in the first round, because at the time
@@ -19061,6 +19160,9 @@ read_attribute_reprocess (const struct die_reader_specs *reader,
case DW_FORM_loclistx:
DW_UNSND (attr) = read_loclist_index (cu, DW_UNSND (attr));
break;
+ case DW_FORM_rnglistx:
+ DW_UNSND (attr) = read_rnglist_index (cu, DW_UNSND (attr));
+ break;
case DW_FORM_strx:
case DW_FORM_strx1:
case DW_FORM_strx2:
@@ -19242,8 +19344,10 @@ read_attribute_value (const struct die_reader_specs *reader,
DW_SND (attr) = read_signed_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
break;
- case DW_FORM_udata:
case DW_FORM_rnglistx:
+ *need_reprocess = true;
+ /* FALLTHROUGH */
+ case DW_FORM_udata:
DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
break;
@@ -23332,6 +23436,25 @@ cu_debug_loc_section (struct dwarf2_cu *cu)
: &per_objfile->per_bfd->loc);
}
+/* Return the .debug_rnglists section to use for CU. */
+static struct dwarf2_section_info *
+cu_debug_rnglist_section (struct dwarf2_cu *cu)
+{
+ if (cu->header.version < 5)
+ error (_(".debug_rnglists section cannot be used in DWARF %d"),
+ cu->header.version);
+ struct dwarf2_per_objfile *dwarf2_per_objfile = cu->per_objfile;
+
+ if (cu->dwo_unit)
+ {
+ struct dwo_sections *sections = &cu->dwo_unit->dwo_file->sections;
+
+ if (sections->rnglists.size > 0)
+ return §ions->rnglists;
+ }
+ return &dwarf2_per_objfile->per_bfd->rnglists;
+}
+
/* A helper function that fills in a dwarf2_loclist_baton. */
static void
diff --git a/testsuite/gdb.dwarf2/dw5-rnglist-test.cc b/testsuite/gdb.dwarf2/dw5-rnglist-test.cc
new file mode 100644
index 0000000..4d650e1279
--- /dev/null
+++ b/testsuite/gdb.dwarf2/dw5-rnglist-test.cc
@@ -0,0 +1,71 @@
+#include <iostream>
+#include <vector>
+
+struct node {
+ int id;
+ node *left;
+ node *right;
+ bool visited;
+};
+
+node node_array[50];
+unsigned int CUR_IDX = 0;
+
+node * make_node (int val)
+{
+ node *new_node = &(node_array[CUR_IDX++]);
+ new_node->left = NULL;
+ new_node->right = NULL;
+ new_node->id = val;
+ new_node->visited = false;
+
+ return new_node;
+}
+
+void tree_insert (node *root, int val)
+{
+ if (val < root->id)
+ {
+ if (root->left)
+ tree_insert (root->left, val);
+ else
+ root->left = make_node(val);
+ }
+ else if (val > root->id)
+ {
+ if (root->right)
+ tree_insert (root->right, val);
+ else
+ root->right = make_node(val);
+ }
+}
+
+void inorder(node *root) {
+ std::vector<node *> todo;
+ todo.push_back(root);
+ while (!todo.empty()){
+ node *curr = todo.back();
+ todo.pop_back(); /* break-here */
+ if (curr->visited) {
+ std::cout << curr->id << " ";
+ } else {
+ curr->visited = true;
+ if (curr->right) { todo.push_back(curr->right); }
+ todo.push_back(curr);
+ if (curr->left) { todo.push_back(curr->left); }
+ }
+ }
+}
+
+int main (int argc, char **argv)
+{
+ node *root = make_node (35);
+
+ tree_insert (root, 28);
+ tree_insert (root, 20);
+ tree_insert (root, 60);
+
+ inorder (root);
+
+ return 0;
+}
diff --git a/testsuite/gdb.dwarf2/dw5-rnglist-test.exp b/testsuite/gdb.dwarf2/dw5-rnglist-test.exp
new file mode 100644
index 0000000..b5c6c3bfe3
--- /dev/null
+++ b/testsuite/gdb.dwarf2/dw5-rnglist-test.exp
@@ -0,0 +1,40 @@
+# Copyright 2011-2020 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/>.
+
+# Check that GDB can find the variables in a lexical block with a
+# DW_FORM_rnglistx DW_AT_ranges field. This test is intended for DWARF-5,
+# compiled with clang++.
+
+standard_testfile .cc
+
+# This test is intended for targets which support DWARF-5.
+# Since we pass an explicit -gdwarf-5 to the compiler,
+# we let that be the test of whether the target supports it.
+
+if { [prepare_for_testing "failed to prepare" "${testfile}" \
+ $srcfile {debug c++ additional_flags=-gdwarf-5 \
+ additional_flags=-O0}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+gdb_test "print curr" "\\\(node \\\*\\\) $hex <node_array>"
+gdb_test "print *curr" "= {id = 35, left = $hex <node_array\\+$decimal>, right = $hex <node_array\\+$decimal>, visited = false}"
next prev parent reply other threads:[~2020-06-04 21:39 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-06-01 17:16 Caroline Tice
2020-06-01 20:33 ` Tom Tromey
2020-06-02 17:04 ` Caroline Tice
2020-06-03 14:49 ` Tom Tromey
2020-06-04 21:39 ` Caroline Tice [this message]
2020-06-09 23:32 ` Caroline Tice
2020-06-16 15:37 ` Caroline Tice
2020-06-18 20:27 ` Tom Tromey
2020-06-23 19:04 ` Caroline Tice
2020-07-01 0:09 ` Caroline Tice
2020-07-01 0:34 ` Simon Marchi
2020-07-01 0:36 ` Simon Marchi
2020-07-01 19:57 ` Caroline Tice
2020-07-02 5:41 ` Simon Marchi
2020-07-03 22:47 ` [PATCH V3] " Caroline Tice
2020-07-04 5:11 ` Simon Marchi
2020-07-09 15:48 ` [PATCH V4] " Caroline Tice
2020-07-11 17:54 ` Simon Marchi
2020-07-14 15:47 ` [PATCH V5] " Caroline Tice
2020-07-15 2:04 ` Simon Marchi
2020-07-15 3:15 ` Simon Marchi
2020-07-15 16:57 ` Caroline Tice
2020-07-15 17:04 ` H.J. Lu
2020-07-15 22:35 ` Caroline Tice
2020-07-16 2:34 ` Simon Marchi
2020-07-16 4:46 ` Caroline Tice
2020-07-16 15:41 ` Simon Marchi
2020-07-16 15:46 ` Caroline Tice
2020-07-16 16:09 ` Simon Marchi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CABtf2+SZUXnSNHNJpm7LFU2vg1cd=62dzX2_LKfc98yaeQhGDw@mail.gmail.com' \
--to=cmtice@google.com \
--cc=echristo@google.com \
--cc=gdb-patches@sourceware.org \
--cc=tom@tromey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).