summaryrefslogtreecommitdiff
path: root/libdw
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2018-04-26 11:53:49 +0200
committerMark Wielaard <mark@klomp.org>2018-05-15 11:25:27 +0200
commit6ed8b94952ddf155960c799ef76f3048f033e873 (patch)
treeb9270241542b3575e08f3639829137dee8caaa67 /libdw
parentb9c76ded0f07d270bbb9314fb970bb0afcb71d58 (diff)
downloadelfutils-6ed8b94952ddf155960c799ef76f3048f033e873.tar.gz
readelf: Add DWARF5 .debug_line support.
This only changes the parsing of the directory and file name tables. It does this by sharing the printing of (non-CU based) from data from the .debug_macro code. Adding support for printing strx[1234] form data by sharing the code that detects the correct str_offsets_base in libdw. The header format is also cleaned up a bit so that it better lines out. Testcases adjusted and new ones added. Signed-off-by: Mark Wielaard <mark@klomp.org>
Diffstat (limited to 'libdw')
-rw-r--r--libdw/ChangeLog7
-rw-r--r--libdw/dwarf_formstring.c17
-rw-r--r--libdw/libdwP.h107
3 files changed, 113 insertions, 18 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 86d2b78a..efdd927f 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,10 @@
+2018-05-09 Mark Wielaard <mark@klomp.org>
+
+ * dwarf_formstring.c (__libdw_cu_str_off_base): Moved to...
+ * libdwP.h (__libdw_cu_str_off_base): ...here. Make static inline.
+ (str_offsets_base_off): New internal function that also parses
+ .debug_str_offsets header if necessary.
+
2018-05-11 Mark Wielaard <mark@klomp.org>
* dwarf_siblingof.c (dwarf_siblingof): Don't reference cu till it is
diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c
index c55c7f04..251784df 100644
--- a/libdw/dwarf_formstring.c
+++ b/libdw/dwarf_formstring.c
@@ -177,20 +177,3 @@ dwarf_formstring (Dwarf_Attribute *attrp)
return (const char *) data->d_buf + off;
}
INTDEF(dwarf_formstring)
-
-Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu)
-{
- if (cu->str_off_base == (Dwarf_Off) -1)
- {
- Dwarf_Die cu_die = CUDIE(cu);
- Dwarf_Attribute attr;
- if (dwarf_attr (&cu_die, DW_AT_str_offsets_base, &attr) != NULL)
- {
- Dwarf_Word off;
- if (dwarf_formudata (&attr, &off) == 0)
- cu->str_off_base = off;
- }
- }
-
- return cu->str_off_base;
-}
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 7aa290e5..da0383f4 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -933,8 +933,113 @@ 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);
+/* Gets the .debug_str_offsets base offset to use. static inline to
+ be shared between libdw and eu-readelf. */
+static inline Dwarf_Off
+str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu)
+{
+ /* If we don't have a CU, then find and use the first one in the
+ debug file (when we support .dwp files, we must actually find the
+ one matching our "caller" - aka macro or line). If we (now) have
+ a cu and str_offsets_base attribute, just use that. Otherwise
+ use the first offset. But we might have to parse the header
+ first, but only if this is version 5. Assume if all else fails,
+ this is version 4, without header. */
+
+ if (cu == NULL && dbg != NULL)
+ {
+ Dwarf_CU *first_cu;
+ if (dwarf_get_units (dbg, NULL, &first_cu,
+ NULL, NULL, NULL, NULL) == 0)
+ cu = first_cu;
+ }
+
+ if (cu != NULL)
+ {
+ if (cu->str_off_base == (Dwarf_Off) -1)
+ {
+ Dwarf_Die cu_die = CUDIE(cu);
+ Dwarf_Attribute attr;
+ if (dwarf_attr (&cu_die, DW_AT_str_offsets_base, &attr) != NULL)
+ {
+ Dwarf_Word off;
+ if (dwarf_formudata (&attr, &off) == 0)
+ {
+ cu->str_off_base = off;
+ return cu->str_off_base;
+ }
+ }
+ /* For older DWARF simply assume zero (no header). */
+ if (cu->version < 5)
+ {
+ cu->str_off_base = 0;
+ return cu->str_off_base;
+ }
+ }
+ else
+ return cu->str_off_base;
+ }
+
+ /* No str_offsets_base attribute, we have to assume "zero".
+ But there could be a header first. */
+ Dwarf_Off off = 0;
+ if (dbg == NULL)
+ goto no_header;
+
+ Elf_Data *data = dbg->sectiondata[IDX_debug_str_offsets];
+ if (data == NULL)
+ goto no_header;
+
+ const unsigned char *start;
+ const unsigned char *readp;
+ const unsigned char *readendp;
+ start = readp = (const unsigned char *) data->d_buf;
+ readendp = (const unsigned char *) data->d_buf + data->d_size;
+
+ uint64_t unit_length;
+ uint16_t version;
+
+ unit_length = read_4ubyte_unaligned_inc (dbg, readp);
+ if (unlikely (unit_length == 0xffffffff))
+ {
+ if (unlikely (readendp - readp < 8))
+ goto no_header;
+ unit_length = read_8ubyte_unaligned_inc (dbg, readp);
+ /* In theory the offset size could be different
+ between CU and str_offsets unit. But we just
+ ignore that here. */
+ }
+
+ /* We need at least 2-bytes (version) + 2-bytes (padding) =
+ 4 bytes to complete the header. And this unit cannot go
+ beyond the section data. */
+ if (readendp - readp < 4
+ || unit_length < 4
+ || (uint64_t) (readendp - readp) < unit_length)
+ goto no_header;
+
+ version = read_2ubyte_unaligned_inc (dbg, readp);
+ if (version != 5)
+ goto no_header;
+ /* padding */
+ read_2ubyte_unaligned_inc (dbg, readp);
+
+ off = (Dwarf_Off) (readp - start);
+
+ no_header:
+ if (cu != NULL)
+ cu->str_off_base = off;
+
+ return off;
+}
+
+
/* Get the string offsets base for the CU, fetches it when not yet set. */
-Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu);
+static inline Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu)
+{
+ return str_offsets_base_off (NULL, cu);
+}
+
/* Given a file descriptor, dir and file returns a full path. If the
file is absolute (starts with a /) a copy of file is returned. If