[Bug backends/31142] New: riscv pass_by_flattened_arg not implemented

2023-12-11 Thread mark at klomp dot org
https://sourceware.org/bugzilla/show_bug.cgi?id=31142

Bug ID: 31142
   Summary: riscv pass_by_flattened_arg not implemented
   Product: elfutils
   Version: unspecified
Status: NEW
  Severity: normal
  Priority: P2
 Component: backends
  Assignee: unassigned at sourceware dot org
  Reporter: mark at klomp dot org
CC: elfutils-devel at sourceware dot org
  Target Milestone: ---

dwfl_module_return_value_location will fail for functions that return a struct
because that need pass_by_flattened_arg in backends/riscv_retval.c which is
currently:

static int
pass_by_flattened_arg (const Dwarf_Op **locp __attribute__ ((unused)),
   Dwarf_Word size __attribute__ ((unused)),
   Dwarf_Die *arg0 __attribute__ ((unused)),
   Dwarf_Die *arg1 __attribute__ ((unused)))
{
  /* ??? */
  return -2;
}

This happens for example with the glibc div function which returns:

typedef struct
  {
int quot;   /* Quotient.  */
int rem;/* Remainder.  */
  } div_t;

-- 
You are receiving this mail because:
You are on the CC list for the bug.

[PATCH v2] dwarf_getaranges: Build aranges list from CUs instead of .debug_aranges

2023-12-11 Thread Aaron Merey
No longer use .debug_aranges to build the aranges list since it could be
absent or incomplete.

Instead build the aranges list by iterating over each CU and recording
each address range.

https://sourceware.org/bugzilla/show_bug.cgi?id=22288
https://sourceware.org/bugzilla/show_bug.cgi?id=30948

Signed-off-by: Aaron Merey 
---

v2 adds a test for generating aranges from a binary with no
.debug_aranges.

This patch's method of building the aranges list is slower than simply
reading .debug_aranges.  On my machine, running eu-stack on a 2.9G
firefox core file takes about 8.7 seconds with this patch applied,
compared to about 3.3 seconds without this patch.

Ideally we could assume that .debug_aranges is complete if it is present
and build the aranges list via CU iteration only when .debug_aranges
is absent.  This would let us save time on gcc-compiled binaries, which
include complete .debug_aranges by default.

However the DWARF spec appears to permit partially complete
.debug_aranges [1].  We could improve performance by starting with a
potentially incomplete list built from .debug_aranges.  If a lookup
fails then search the CUs for missing aranges and add to the list
when found.

This approach would complicate the dwarf_get_aranges interface.  The
list it initially provides could no longer be assumed to be complete.
The number of elements in the list could change during calls to
dwarf_getarange{info, _addr}.  This would invalidate the naranges value
set by dwarf_getaranges.  The current API doesn't include a way to
communicate to the caller when narages changes and by how much.

Due to these complications I think it's better to simply ignore
.debug_aranges altogether and build the aranges table via CU iteration,
as is done in this patch.

[1] https://sourceware.org/bugzilla/show_bug.cgi?id=22288#c5

 libdw/dwarf_getaranges.c | 215 ++-
 tests/run-get-aranges.sh |  48 +
 2 files changed, 100 insertions(+), 163 deletions(-)

diff --git a/libdw/dwarf_getaranges.c b/libdw/dwarf_getaranges.c
index 27439d37..8676f93b 100644
--- a/libdw/dwarf_getaranges.c
+++ b/libdw/dwarf_getaranges.c
@@ -33,7 +33,6 @@
 #endif
 
 #include 
-#include 
 #include "libdwP.h"
 #include 
 
@@ -68,174 +67,51 @@ dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, 
size_t *naranges)
   return 0;
 }
 
-  if (dbg->sectiondata[IDX_debug_aranges] == NULL)
-{
-  /* No such section.  */
-  *aranges = NULL;
-  if (naranges != NULL)
-   *naranges = 0;
-  return 0;
-}
-
-  if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
-return -1;
-
   struct arangelist *arangelist = NULL;
   unsigned int narangelist = 0;
 
-  const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf;
-  const unsigned char *readendp
-= readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
-
-  while (readp < readendp)
+  Dwarf_CU *cu = NULL;
+  while (INTUSE(dwarf_get_units) (dbg, cu, &cu, NULL, NULL, NULL, NULL) == 0)
 {
-  const unsigned char *hdrstart = readp;
-
-  /* Each entry starts with a header:
-
-1. A 4-byte or 12-byte length containing the length of the
-set of entries for this compilation unit, not including the
-length field itself. [...]
-
-2. A 2-byte version identifier containing the value 2 for
-DWARF Version 2.1.
-
-3. A 4-byte or 8-byte offset into the .debug_info section. [...]
-
-4. A 1-byte unsigned integer containing the size in bytes of
-an address (or the offset portion of an address for segmented
-addressing) on the target system.
-
-5. A 1-byte unsigned integer containing the size in bytes of
-a segment descriptor on the target system.  */
-  if (unlikely (readp + 4 > readendp))
-   goto invalid;
-
-  Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
-  unsigned int length_bytes = 4;
-  if (length == DWARF3_LENGTH_64_BIT)
-   {
- if (unlikely (readp + 8 > readendp))
-   goto invalid;
-
- length = read_8ubyte_unaligned_inc (dbg, readp);
- length_bytes = 8;
-   }
-  else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
-&& length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
-   goto invalid;
-
-  const unsigned char *endp = readp + length;
-  if (unlikely (endp > readendp))
-   goto invalid;
-
-  if (unlikely (readp + 2 > readendp))
-   goto invalid;
-
-  unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
-  if (version != 2)
-   {
-   invalid:
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
-   fail:
- while (arangelist != NULL)
-   {
- struct arangelist *next = arangelist->next;
- free (arangelist);
- arangelist = next;
-   }
- return -1;
-   }
-
-  Dwarf_Word offset = 0;
-  if (__libdw_read_offset_inc (dbg,
-