aboutsummaryrefslogtreecommitdiff
path: root/libdw
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2018-05-20 23:30:01 +0200
committerMark Wielaard <mark@klomp.org>2018-05-25 15:07:58 +0200
commit6e3d2521a2b5a3b436901f52cfb9785887a7c961 (patch)
tree649d9c157ac680e9f99b61df772e429883602bf5 /libdw
parent184fd30d1a453dc165ffc187b22dec6d196522ad (diff)
downloadelfutils-6e3d2521a2b5a3b436901f52cfb9785887a7c961.tar.gz
libdw: Support DW_OP_addrx/constx and split DWARF addrx/constx support.
DW_OP_addrx/constx and GNU DebugFission DW_OP_GNU_addr/const_index take as argument an index into the .debug_addr section for the associated CU. This index gets resolved through dwarf_getlocation_attr. A new fake addr CU is created per Dwarf for use with this new attribute. For split DWARF files, the IDX_debug_addr gets replaced with the skeleton section and the addr base is resolved immediately when constructing the split DWARF CU. Move __libdw_cu_addr_base to libdwP.h to share with eu-readelf. Also make it possible to resolve addrx[1234]/GNU_addr_index also as constant indexes to (also) show when displaying these attributes in eu-readelf. A new varlocs tests is added to test the resolving for both the DWARF4 and DWARF5 DW_OP variants. And now that addrx forms are resolved in split DWARF files add the new DIEs with "single ranges" (those DIEs that have a lowpc/highpc attribute pair) to run-all-dwarf-ranges.sh. Signed-off-by: Mark Wielaard <mark@klomp.org>
Diffstat (limited to 'libdw')
-rw-r--r--libdw/ChangeLog19
-rw-r--r--libdw/dwarf_begin_elf.c27
-rw-r--r--libdw/dwarf_end.c12
-rw-r--r--libdw/dwarf_formaddr.c18
-rw-r--r--libdw/dwarf_formudata.c33
-rw-r--r--libdw/dwarf_getlocation_attr.c31
-rw-r--r--libdw/libdwP.h24
-rw-r--r--libdw/libdw_find_split_unit.c14
8 files changed, 158 insertions, 20 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 08c8f7be..f5689632 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,22 @@
+2018-05-21 Mark Wielaard <mark@klomp.org>
+
+ * dwarf_begin_elf.c (valid_p): Add a fake_addr_cu to the result.
+ * dwarf_end.c (cu_free): Disconnect the fake_addr_cu from the split
+ dwarf if shared with skeleton.
+ (dwarf_end): release fake_addr_cu.
+ * dwarf_formaddr.c (__libdw_cu_addr_base): Move to...
+ * libdwP.h (__libdw_cu_addr_base): ... here.
+ (struct Dwarf): Add fake_addr_cu field.
+ * dwarf_formudata.c (dwarf_formudata): Handle
+ DW_FORM_GNU_addr_index and DW_FORM_addrx[1234].
+ * dwarf_getlocation_attr.c (addr_valp): New static function.
+ (dwarf_getlocation_attr): Create attribute for values of
+ DW_OP_GNU_const_index, DW_OP_constx and DW_OP_GNU_addr_index and
+ DW_OP_addrx.
+ * libdw_find_split_unit.c (__libdw_find_split_unit): Connect
+ IDX_debug_addr sectiondata and fake_addr_cu between split and
+ skeleton.
+
2018-05-20 Mark Wielaard <mark@klomp.org>
* dwarf_cu_info.c: New file.
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 0e435c57..5d8e79e3 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -246,6 +246,33 @@ valid_p (Dwarf *result)
}
}
+ /* For DW_OP_constx/GNU_const_index and DW_OP_addrx/GNU_addr_index
+ the dwarf_location_attr () will need a "fake" address CU to
+ indicate where the attribute data comes from. This is a just
+ inside the .debug_addr section, if it exists. */
+ if (result != NULL && result->sectiondata[IDX_debug_addr] != NULL)
+ {
+ result->fake_addr_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+ if (unlikely (result->fake_addr_cu == NULL))
+ {
+ Dwarf_Sig8_Hash_free (&result->sig8_hash);
+ __libdw_seterrno (DWARF_E_NOMEM);
+ free (result->fake_loc_cu);
+ free (result);
+ result = NULL;
+ }
+ else
+ {
+ result->fake_addr_cu->sec_idx = IDX_debug_addr;
+ result->fake_addr_cu->dbg = result;
+ result->fake_addr_cu->startp
+ = result->sectiondata[IDX_debug_addr]->d_buf;
+ result->fake_addr_cu->endp
+ = (result->sectiondata[IDX_debug_addr]->d_buf
+ + result->sectiondata[IDX_debug_addr]->d_size);
+ }
+ }
+
if (result != NULL)
result->debugdir = __libdw_debugdir (result->elf->fildes);
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index 4702f1b1..19546741 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -59,7 +59,12 @@ cu_free (void *arg)
/* Free split dwarf one way (from skeleton to split). */
if (p->unit_type == DW_UT_skeleton
&& p->split != NULL && p->split != (void *)-1)
- INTUSE(dwarf_end) (p->split->dbg);
+ {
+ /* The fake_addr_cu might be shared, only release one. */
+ if (p->dbg->fake_addr_cu == p->split->dbg->fake_addr_cu)
+ p->split->dbg->fake_addr_cu = NULL;
+ INTUSE(dwarf_end) (p->split->dbg);
+ }
}
@@ -108,6 +113,11 @@ dwarf_end (Dwarf *dwarf)
cu_free (dwarf->fake_loc_cu);
free (dwarf->fake_loc_cu);
}
+ if (dwarf->fake_addr_cu != NULL)
+ {
+ cu_free (dwarf->fake_addr_cu);
+ free (dwarf->fake_addr_cu);
+ }
/* Did we find and allocate the alt Dwarf ourselves? */
if (dwarf->alt_fd != -1)
diff --git a/libdw/dwarf_formaddr.c b/libdw/dwarf_formaddr.c
index c917deac..3c89a5d2 100644
--- a/libdw/dwarf_formaddr.c
+++ b/libdw/dwarf_formaddr.c
@@ -136,21 +136,3 @@ dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr)
return 0;
}
INTDEF(dwarf_formaddr)
-
-Dwarf_Off __libdw_cu_addr_base (Dwarf_CU *cu)
-{
- if (cu->addr_base == (Dwarf_Off) -1)
- {
- Dwarf_Die cu_die = CUDIE(cu);
- Dwarf_Attribute attr;
- if (dwarf_attr (&cu_die, DW_AT_GNU_addr_base, &attr) != NULL
- || dwarf_attr (&cu_die, DW_AT_addr_base, &attr) != NULL)
- {
- Dwarf_Word off;
- if (dwarf_formudata (&attr, &off) == 0)
- cu->addr_base = off;
- }
- }
-
- return cu->addr_base;
-}
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
index 316ad865..d56e7dc1 100644
--- a/libdw/dwarf_formudata.c
+++ b/libdw/dwarf_formudata.c
@@ -288,6 +288,39 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
get_sleb128_unchecked (*return_uval, datap);
break;
+ /* These are indexes into the .debug_addr section, normally resolved
+ with dwarf_formaddr. Here treat as constants. */
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_addrx:
+ if (datap >= endp)
+ goto invalid;
+ get_uleb128 (*return_uval, datap, endp);
+ break;
+
+ case DW_FORM_addrx1:
+ if (datap >= endp - 1)
+ goto invalid;
+ *return_uval = *datap;
+ break;
+
+ case DW_FORM_addrx2:
+ if (datap >= endp - 2)
+ goto invalid;
+ *return_uval = read_2ubyte_unaligned (attr->cu->dbg, datap);
+ break;
+
+ case DW_FORM_addrx3:
+ if (datap >= endp - 3)
+ goto invalid;
+ *return_uval = read_3ubyte_unaligned (attr->cu->dbg, datap);
+ break;
+
+ case DW_FORM_addrx4:
+ if (datap >= endp - 4)
+ goto invalid;
+ *return_uval = read_4ubyte_unaligned (attr->cu->dbg, datap);
+ break;
+
default:
__libdw_seterrno (DWARF_E_NO_CONSTANT);
return -1;
diff --git a/libdw/dwarf_getlocation_attr.c b/libdw/dwarf_getlocation_attr.c
index 162330f6..62ef47ab 100644
--- a/libdw/dwarf_getlocation_attr.c
+++ b/libdw/dwarf_getlocation_attr.c
@@ -52,6 +52,18 @@ attr_form_cu (Dwarf_Attribute *attr)
}
}
+static unsigned char *
+addr_valp (Dwarf_CU *cu, Dwarf_Word index)
+{
+ Elf_Data *debug_addr = cu->dbg->sectiondata[IDX_debug_addr];
+ Dwarf_Word offset = __libdw_cu_addr_base (cu) + (index * cu->address_size);
+ if (debug_addr == NULL)
+ /* This is really an error, will trigger with dwarf_formaddr. */
+ return (unsigned char *) offset;
+
+ return (unsigned char *) debug_addr->d_buf + offset;
+}
+
int
dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribute *result)
{
@@ -83,6 +95,25 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu
result->cu = attr_form_cu (attr);
break;
+ case DW_OP_GNU_const_index:
+ case DW_OP_constx:
+ result->code = DW_AT_const_value;
+ if (attr->cu->address_size == 4)
+ result->form = DW_FORM_data4;
+ else
+ result->form = DW_FORM_data8;
+ result->valp = addr_valp (attr->cu, op->number);
+ result->cu = attr->cu->dbg->fake_addr_cu;
+ break;
+
+ case DW_OP_GNU_addr_index:
+ case DW_OP_addrx:
+ result->code = DW_AT_low_pc;
+ result->form = DW_FORM_addr;
+ result->valp = addr_valp (attr->cu, op->number);
+ result->cu = attr->cu->dbg->fake_addr_cu;
+ break;
+
case DW_OP_call2:
case DW_OP_call4:
case DW_OP_call_ref:
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 2b5b5ead..82ee5d03 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -204,6 +204,9 @@ struct Dwarf
came from a location list entry in dwarf_getlocation_attr. */
struct Dwarf_CU *fake_loc_cu;
+ /* Similar for addrx/constx, which will come from .debug_addr section. */
+ struct Dwarf_CU *fake_addr_cu;
+
/* Internal memory handling. This is basically a simplified
reimplementation of obstacks. Unfortunately the standard obstack
implementation is not usable in libraries. */
@@ -947,7 +950,26 @@ const char *__libdw_getcompdir (Dwarf_Die *cudie);
Dwarf_Addr __libdw_cu_base_address (Dwarf_CU *cu);
/* Get the address base for the CU, fetches it when not yet set. */
-Dwarf_Off __libdw_cu_addr_base (Dwarf_CU *cu);
+static inline Dwarf_Off
+__libdw_cu_addr_base (Dwarf_CU *cu)
+{
+ if (cu->addr_base == (Dwarf_Off) -1)
+ {
+ Dwarf_Die cu_die = CUDIE(cu);
+ Dwarf_Attribute attr;
+ Dwarf_Off offset = 0;
+ if (dwarf_attr (&cu_die, DW_AT_GNU_addr_base, &attr) != NULL
+ || dwarf_attr (&cu_die, DW_AT_addr_base, &attr) != NULL)
+ {
+ Dwarf_Word off;
+ if (dwarf_formudata (&attr, &off) == 0)
+ offset = off;
+ }
+ cu->addr_base = offset;
+ }
+
+ return cu->addr_base;
+}
/* Gets the .debug_str_offsets base offset to use. static inline to
be shared between libdw and eu-readelf. */
diff --git a/libdw/libdw_find_split_unit.c b/libdw/libdw_find_split_unit.c
index bd48b9e5..78c9a2a5 100644
--- a/libdw/libdw_find_split_unit.c
+++ b/libdw/libdw_find_split_unit.c
@@ -88,6 +88,20 @@ __libdw_find_split_unit (Dwarf_CU *cu)
cu->split = split;
split->split = cu;
+ /* Get .debug_addr and addr_base greedy.
+ We also need it for the fake addr cu.
+ There is only one per split debug. */
+ Dwarf *dbg = cu->dbg;
+ Dwarf *sdbg = split->dbg;
+ if (sdbg->sectiondata[IDX_debug_addr] == NULL
+ && dbg->sectiondata[IDX_debug_addr] != NULL)
+ {
+ sdbg->sectiondata[IDX_debug_addr]
+ = dbg->sectiondata[IDX_debug_addr];
+ split->addr_base = __libdw_cu_addr_base (cu);
+ sdbg->fake_addr_cu = dbg->fake_addr_cu;
+ }
+
/* We have everything we need from this
ELF file. And we are going to close
the fd to not run out of file