[COMMITTED] tests: run-deleted.sh unset VALGRIND_CMD before running deleted.
by Mark Wielaard
We don't want to run the deleted test process under valgrind then
eu-stack will see the valgrind process backtrace.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
tests/ChangeLog | 4 ++++
tests/run-deleted.sh | 8 ++++++++
2 files changed, 12 insertions(+)
diff --git a/tests/ChangeLog b/tests/ChangeLog
index a6111af..6b76248 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,5 +1,9 @@
2014-10-02 Mark Wielaard <mjw(a)redhat.com>
+ * run-deleted.sh: Unset VALGRIND_CMD before running deleted.
+
+2014-10-02 Mark Wielaard <mjw(a)redhat.com>
+
* Makefile.am (check_PROGRAMS): Add aggregate_size.c.
(TESTS): Add run-aggregate-size.sh.
(EXTRA_DIST): Add run-aggregate-size.sh, testfile-sizes1.o.bz2
diff --git a/tests/run-deleted.sh b/tests/run-deleted.sh
index b3f17ff..8c4d928 100755
--- a/tests/run-deleted.sh
+++ b/tests/run-deleted.sh
@@ -19,10 +19,18 @@
tempfiles deleted deleted-lib.so
cp -p ${abs_builddir}/deleted ${abs_builddir}/deleted-lib.so .
+
+# We don't want to run the deleted process under valgrind then
+# stack will see the valgrind process backtrace.
+OLD_VALGRIND_CMD="$VALGRIND_CMD"
+unset VALGRIND_CMD
+
pid=$(testrun ${abs_builddir}/deleted)
sleep 1
rm -f deleted deleted-lib.so
tempfiles bt
+
+set VALGRIND_CMD="$OLD_VALGRIND_CMD"
# It may have non-zero exit code with:
# .../elfutils/src/stack: dwfl_thread_getframes tid 26376 at 0x4006c8 in .../elfutils/tests/deleted: no matching address range
testrun ${abs_top_builddir}/src/stack -p $pid >bt || true
--
1.8.3.1
9 years, 6 months
dwarf_aggregate_size() seems to fall over on pointer types
by Conrad Rad
Hi all,
First, I'm not super familiar with DWARF, and perhaps this is a bug in
the DWARF information emitted by Clang (3.4). It's definitely a
difference between GCC and Clang DWARF output.
I've been fiddling with a pahole-alike tool[0] that sits directly on
elfutils (as opposed to libdwarves, which hasn't been updated for some
time and doesn't handle some of the tags Clang emits). I've observed
that dwarf_aggregate_size() doesn't seem to like types that are
pointers or arrays of pointers[1].
I've compiled a small example program, repro, and output[2]:
http://pastie.org/9610702
dwarf_aggregate_size() has no trouble with most member types, or even
pointer types on the output from GCC. However, it returns an error on
Clang's output.
Perhaps Clang is just eliding pointer size information, assuming
consumers will consult the Elf machine class and infer?
Am I missing something? Is this a Clang bug or an elfutils bug?
Thanks much,
Conrad
[0]: https://github.com/cemeyer/structhole/
[1]: https://github.com/cemeyer/structhole/issues/1
[2]: http://pastie.org/9610702
9 years, 6 months
[PATCH][v2] Support .debug_macro
by Petr Machata
Hi there,
in comparison with the previous version, this doesn't invent custom
bounds-checking primitives and just does what the rest of libdw does.
It also uses the read_addr_unaligned_inc that I introduced in the
other patch that I posted for review.
Thanks,
PM
---8<-------------------------------------------------------------
- This code is based on the following proposal:
http://www.dwarfstd.org/ShowIssue.php?issue=110722.1
- dwarf_getmacros is left to support only .debug_macinfo. The only
problematic opcode really is DW_MACINFO_vendor_ext, that the new
standard lacks, and that could in theory be misinterpreted by extant
code as whatever operand a vendor decides to map to 0xff.
- Instead, two principial iteration interfaces are provided for access
to new-style sections: dwarf_getmacros_die and dwarf_getmacros_off.
And a suite of new helper interfaces for analysis of individual
opcodes: dwarf_macro_version, dwarf_macro_line_offset,
dwarf_macro_getparamcnt, dwarf_macro_param.
- The existing interfaces dwarf_macro_opcode, dwarf_macro_param1 and
dwarf_macro_param2 remain operational for old- as well as new-style
Dwarf macro sections, if applicable.
Signed-off-by: Petr Machata <pmachata(a)redhat.com>
---
libdw/ChangeLog | 32 +++
libdw/Makefile.am | 8 +-
libdw/dwarf_end.c | 1 +
libdw/dwarf_error.c | 3 +-
libdw/dwarf_getmacros.c | 496 ++++++++++++++++++++++++++++++++-------
libdw/dwarf_macro_getparamcnt.c | 43 ++++
libdw/dwarf_macro_line_offset.c | 45 ++++
libdw/dwarf_macro_param.c | 46 ++++
libdw/dwarf_macro_param1.c | 8 +-
libdw/dwarf_macro_param2.c | 18 +-
libdw/dwarf_macro_version.c | 44 ++++
libdw/libdw.h | 87 +++++++-
libdw/libdw.map | 11 +-
libdw/libdwP.h | 54 ++++-
14 files changed, 785 insertions(+), 111 deletions(-)
create mode 100644 libdw/dwarf_macro_getparamcnt.c
create mode 100644 libdw/dwarf_macro_line_offset.c
create mode 100644 libdw/dwarf_macro_param.c
create mode 100644 libdw/dwarf_macro_version.c
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 410b31a..a9d2166 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,35 @@
+2014-09-10 Petr Machata <pmachata(a)redhat.com>
+
+ * dwarf_macro_getparamcnt.c: New file.
+ * dwarf_macro_line_offset.c: New file.
+ * dwarf_macro_param.c: New file.
+ * dwarf_macro_version.c: New file.
+ * Makefile.am (libdw_a_SOURCES): Add the new files.
+ * libdwP.h (DWARF_E_INVALID_OPCODE): New enumerator.
+ (struct Dwarf): New field macro_ops.
+ (Dwarf_Macro_Op_Proto, Dwarf_Macro_Op_Table): New structures for
+ keeping macro opcode prototypes in.
+ (Dwarf_Macro_s): Drop all fields, add new ones.
+ * dwarf_error.c (errmsgs): Add a message for
+ DWARF_E_INVALID_OPCODE.
+ * dwarf_end.c (dwarf_end): Destroy it here.
+ * libdw.h (dwarf_getmacros_die, dwarf_getmacros_off)
+ (dwarf_macro_version, dwarf_macro_line_offset)
+ (dwarf_macro_getparamcnt)
+ (dwarf_macro_param): New public interfaces.
+ * dwarf_getmacros.c: Implement them here.
+ (get_offset_from, macro_op_compare, build_table)
+ (init_macinfo_table, get_macinfo_table, get_table_for_offset)
+ (read_macros, gnu_macros_getmacros_off)
+ (macro_info_getmacros_off): Helpers.
+ (dwarf_getmacros): Adjust to dispatch to the new interfaces.
+ * dwarf_macro_param1.c (dwarf_macro_param1): Adjust to dispatch to
+ the new interfaces.
+ * dwarf_macro_param2.c (dwarf_macro_param2): Likewise.
+ * libdw.map (ELFUTILS_0.161): New. Add dwarf_getmacros_die,
+ dwarf_getmacros_off, dwarf_macro_version, dwarf_macro_getparamcnt,
+ dwarf_macro_param.
+
2014-09-12 Petr Machata <pmachata(a)redhat.com>
* memory-access.h (read_ubyte_unaligned_inc): Allow only 4- and
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 2e42a37..51b6a0c 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -71,9 +71,11 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
dwarf_getlocation.c dwarf_getstring.c dwarf_offabbrev.c \
dwarf_getaranges.c dwarf_onearange.c dwarf_getarangeinfo.c \
dwarf_getarange_addr.c dwarf_getattrs.c dwarf_formflag.c \
- dwarf_getmacros.c dwarf_macro_opcode.c dwarf_macro_param1.c \
- dwarf_macro_param2.c dwarf_addrdie.c \
- dwarf_getfuncs.c \
+ dwarf_getmacros.c dwarf_macro_getparamcnt.c \
+ dwarf_macro_line_offset.c dwarf_macro_opcode.c \
+ dwarf_macro_param.c dwarf_macro_param1.c \
+ dwarf_macro_param2.c dwarf_macro_version.c \
+ dwarf_addrdie.c dwarf_getfuncs.c \
dwarf_decl_file.c dwarf_decl_line.c dwarf_decl_column.c \
dwarf_func_inline.c dwarf_getsrc_file.c \
libdw_findcu.c libdw_form.c libdw_alloc.c \
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index 241a257..26c38cb 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -92,6 +92,7 @@ dwarf_end (dwarf)
to be handled. */
tdestroy (dwarf->cu_tree, cu_free);
tdestroy (dwarf->tu_tree, cu_free);
+ tdestroy (dwarf->macro_ops, noop_free);
struct libdw_memblock *memp = dwarf->mem_tail;
/* The first block is allocated together with the Dwarf object. */
diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c
index 2292914..08b691a 100644
--- a/libdw/dwarf_error.c
+++ b/libdw/dwarf_error.c
@@ -1,5 +1,5 @@
/* Retrieve ELF descriptor used for DWARF access.
- Copyright (C) 2002, 2003, 2004, 2005, 2009 Red Hat, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2009, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2002.
@@ -92,6 +92,7 @@ static const char *errmsgs[] =
[DWARF_E_NO_DEBUG_RANGES] = N_(".debug_ranges section missing"),
[DWARF_E_INVALID_CFI] = N_("invalid CFI section"),
[DWARF_E_NO_ALT_DEBUGLINK] = N_("no alternative debug link found"),
+ [DWARF_E_INVALID_OPCODE] = N_("invalid opcode"),
};
#define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0]))
diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c
index a3d2c81..52ba512 100644
--- a/libdw/dwarf_getmacros.c
+++ b/libdw/dwarf_getmacros.c
@@ -1,5 +1,5 @@
/* Get macro information.
- Copyright (C) 2002-2009 Red Hat, Inc.
+ Copyright (C) 2002-2009, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2002.
@@ -33,112 +33,446 @@
#include <dwarf.h>
#include <string.h>
+#include <search.h>
#include <libdwP.h>
+#include <stdio.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <stdlib.h>
-ptrdiff_t
-dwarf_getmacros (die, callback, arg, offset)
- Dwarf_Die *die;
- int (*callback) (Dwarf_Macro *, void *);
- void *arg;
- ptrdiff_t offset;
+static int
+get_offset_from (Dwarf_Die *die, int name, Dwarf_Word *retp)
{
- if (die == NULL)
+ /* Get the appropriate attribute. */
+ Dwarf_Attribute attr;
+ if (INTUSE(dwarf_attr) (die, name, &attr) == NULL)
+ return -1;
+
+ /* Offset into the corresponding section. */
+ return INTUSE(dwarf_formudata) (&attr, retp);
+}
+
+static int
+macro_op_compare (const void *p1, const void *p2)
+{
+ const Dwarf_Macro_Op_Table *t1 = (const Dwarf_Macro_Op_Table *) p1;
+ const Dwarf_Macro_Op_Table *t2 = (const Dwarf_Macro_Op_Table *) p2;
+
+ if (t1->offset < t2->offset)
return -1;
+ if (t1->offset > t2->offset + t2->read)
+ return 1;
+
+ return 0;
+}
+
+static void
+build_table (Dwarf_Macro_Op_Table *table,
+ Dwarf_Macro_Op_Proto op_protos[static 255])
+{
+ unsigned ct = 0;
+ for (unsigned i = 1; i < 256; ++i)
+ if (op_protos[i - 1].forms != NULL)
+ table->table[table->opcodes[i - 1] = ct++] = op_protos[i - 1];
+ else
+ table->opcodes[i] = 0xff;
+}
+
+#define MACRO_PROTO(NAME, ...) \
+ Dwarf_Macro_Op_Proto NAME = ({ \
+ static const uint8_t proto[] = {__VA_ARGS__}; \
+ (Dwarf_Macro_Op_Proto) {sizeof proto, proto}; \
+ })
+
+static Dwarf_Macro_Op_Table *
+init_macinfo_table (void)
+{
+ MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
+ MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
+ MACRO_PROTO (p_none);
+
+ Dwarf_Macro_Op_Proto op_protos[255] =
+ {
+ [DW_MACINFO_define - 1] = p_udata_str,
+ [DW_MACINFO_undef - 1] = p_udata_str,
+ [DW_MACINFO_vendor_ext - 1] = p_udata_str,
+ [DW_MACINFO_start_file - 1] = p_udata_udata,
+ [DW_MACINFO_end_file - 1] = p_none,
+ };
+
+ static Dwarf_Macro_Op_Table table;
+ memset (&table, 0, sizeof table);
+
+ build_table (&table, op_protos);
+ return &table;
+}
+
+static inline Dwarf_Macro_Op_Table *
+get_macinfo_table (void)
+{
+ static Dwarf_Macro_Op_Table *ret = NULL;
+ if (unlikely (ret == NULL))
+ ret = init_macinfo_table ();
+ return ret;
+}
+
+static Dwarf_Macro_Op_Table *
+get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff,
+ const unsigned char *readp,
+ const unsigned char *const endp)
+{
+ Dwarf_Macro_Op_Table fake = { .offset = macoff };
+ Dwarf_Macro_Op_Table **found = tfind (&fake, &dbg->macro_ops,
+ macro_op_compare);
+ if (found != NULL)
+ return *found;
+
+ const unsigned char *startp = readp;
+
+ /* Request at least 3 bytes for header. */
+ if (readp + 3 > endp)
+ {
+ invalid_dwarf:
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return NULL;
+ }
- Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_macinfo];
- if (unlikely (d == NULL) || unlikely (d->d_buf == NULL))
+ uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
+ if (version != 4)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_VERSION);
+ return NULL;
+ }
+
+ uint8_t flags = *readp++;
+ bool is_64bit = (flags & 0x1) != 0;
+
+ Dwarf_Off line_offset = (Dwarf_Off) -1;
+ if ((flags & 0x2) != 0)
+ {
+ line_offset = read_addr_unaligned_inc (is_64bit ? 8 : 4, dbg, readp);
+ if (readp > endp)
+ goto invalid_dwarf;
+ }
+
+ /* """The macinfo entry types defined in this standard may, but
+ might not, be described in the table""".
+
+ I.e. these may be present. It's tempting to simply skip them,
+ but it's probably more correct to tolerate that a producer tweaks
+ the way certain opcodes are encoded, for whatever reasons. */
+
+ MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
+ MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp);
+ MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
+ MACRO_PROTO (p_secoffset, DW_FORM_sec_offset);
+ MACRO_PROTO (p_none);
+
+ Dwarf_Macro_Op_Proto op_protos[255] =
+ {
+ [DW_MACRO_GNU_define - 1] = p_udata_str,
+ [DW_MACRO_GNU_undef - 1] = p_udata_str,
+ [DW_MACRO_GNU_define_indirect - 1] = p_udata_strp,
+ [DW_MACRO_GNU_undef_indirect - 1] = p_udata_strp,
+ [DW_MACRO_GNU_start_file - 1] = p_udata_udata,
+ [DW_MACRO_GNU_end_file - 1] = p_none,
+ [DW_MACRO_GNU_transparent_include - 1] = p_secoffset,
+ /* N.B. DW_MACRO_undef_indirectx, DW_MACRO_define_indirectx
+ should be added when 130313.1 is supported. */
+ };
+
+ if ((flags & 0x4) != 0)
+ {
+ unsigned count = *readp++;
+ for (unsigned i = 0; i < count; ++i)
+ {
+ unsigned opcode = *readp++;
+
+ Dwarf_Macro_Op_Proto e;
+ get_uleb128 (e.nforms, readp); // XXX checking
+ e.forms = readp;
+ op_protos[opcode] = e;
+
+ readp += e.nforms;
+ if (readp > endp)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return NULL;
+ }
+ }
+ }
+
+ size_t ct = 0;
+ for (unsigned i = 1; i < 256; ++i)
+ if (op_protos[i - 1].forms != NULL)
+ ++ct;
+
+ /* We support at most 0xfe opcodes defined in the table, as 0xff is
+ a value that means that given opcode is not stored at all. But
+ that should be fine, as opcode 0 is not allocated. */
+ assert (ct < 0xff);
+
+ size_t macop_table_size = offsetof (Dwarf_Macro_Op_Table, table[ct]);
+
+ Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
+ macop_table_size, 1);
+
+ *table = (Dwarf_Macro_Op_Table) {
+ .offset = macoff,
+ .line_offset = line_offset,
+ .header_len = readp - startp,
+ .version = version,
+ .is_64bit = is_64bit,
+ };
+ build_table (table, op_protos);
+
+ Dwarf_Macro_Op_Table **ret = tsearch (table, &dbg->macro_ops,
+ macro_op_compare);
+ if (unlikely (ret == NULL))
+ {
+ __libdw_seterrno (DWARF_E_NOMEM);
+ return NULL;
+ }
+
+ return *ret;
+}
+
+static ptrdiff_t
+read_macros (Dwarf *dbg, Dwarf_Macro_Op_Table *table, int secindex,
+ Dwarf_Off macoff, int (*callback) (Dwarf_Macro *, void *),
+ void *arg, ptrdiff_t offset)
+{
+ Elf_Data *d = dbg->sectiondata[secindex];
+ if (unlikely (d == NULL || d->d_buf == NULL))
{
__libdw_seterrno (DWARF_E_NO_ENTRY);
return -1;
}
- if (offset == 0)
+ if (unlikely (macoff >= d->d_size))
{
- /* Get the appropriate attribute. */
- Dwarf_Attribute attr;
- if (INTUSE(dwarf_attr) (die, DW_AT_macro_info, &attr) == NULL)
- return -1;
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
- /* Offset into the .debug_macinfo section. */
- Dwarf_Word macoff;
- if (INTUSE(dwarf_formudata) (&attr, &macoff) != 0)
- return -1;
+ const unsigned char *const startp = d->d_buf + macoff;
+ const unsigned char *const endp = d->d_buf + d->d_size;
- offset = macoff;
+ if (table == NULL)
+ {
+ table = get_table_for_offset (dbg, macoff, startp, endp);
+ if (table == NULL)
+ return -1;
}
- if (unlikely (offset > (ptrdiff_t) d->d_size))
- goto invalid;
- const unsigned char *readp = d->d_buf + offset;
- const unsigned char *readendp = d->d_buf + d->d_size;
+ if (offset == 0)
+ offset = table->header_len;
- if (readp == readendp)
- return 0;
+ assert (offset >= 0);
+ assert (offset < endp - startp);
+ const unsigned char *readp = startp + offset;
- while (readp < readendp)
+ while (readp < endp)
{
unsigned int opcode = *readp++;
- unsigned int u128;
- unsigned int u128_2 = 0;
- const char *str = NULL;
- const unsigned char *endp;
+ if (opcode == 0)
+ /* Nothing more to do. */
+ return 0;
+
+ unsigned int idx = table->opcodes[opcode - 1];
+ if (idx == 0xff)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_OPCODE);
+ return -1;
+ }
+
+ Dwarf_Macro_Op_Proto *proto = &table->table[idx];
- switch (opcode)
+ /* A fake CU with bare minimum data to fool dwarf_formX into
+ doing the right thing with the attributes that we put
+ out. */
+ Dwarf_CU fake_cu = {
+ .dbg = dbg,
+ .version = 4,
+ .offset_size = table->is_64bit ? 8 : 4,
+ };
+
+ Dwarf_Attribute attributes[proto->nforms];
+ for (Dwarf_Word i = 0; i < proto->nforms; ++i)
{
- case DW_MACINFO_define:
- case DW_MACINFO_undef:
- case DW_MACINFO_vendor_ext:
- /* For the first two opcodes the parameters are
- line, string
- For the latter
- number, string.
- We can treat these cases together. */
- get_uleb128 (u128, readp);
-
- endp = memchr (readp, '\0', readendp - readp);
- if (endp == NULL)
- goto invalid;
-
- str = (char *) readp;
- readp = endp + 1;
- break;
-
- case DW_MACINFO_start_file:
- /* The two parameters are line and file index. */
- get_uleb128 (u128, readp);
- get_uleb128 (u128_2, readp);
- break;
-
- case DW_MACINFO_end_file:
- /* No parameters for this one. */
- u128 = 0;
- break;
-
- case 0:
- /* Nothing more to do. */
- return 0;
-
- default:
- goto invalid;
+ /* We pretend this is a DW_AT_GNU_macros attribute so that
+ DW_FORM_sec_offset forms get correctly interpreted as
+ offset into .debug_macro. */
+ attributes[i].code = DW_AT_GNU_macros;
+ attributes[i].form = proto->forms[i];
+ attributes[i].valp = (void *) readp;
+ attributes[i].cu = &fake_cu;
+
+ readp += __libdw_form_val_len (dbg, &fake_cu,
+ proto->forms[i], readp);
}
- Dwarf_Macro mac;
- mac.opcode = opcode;
- mac.param1 = u128;
- if (str == NULL)
- mac.param2.u = u128_2;
- else
- mac.param2.s = str;
+ Dwarf_Macro macro = {
+ .line_offset = table->line_offset,
+ .version = table->version,
+ .opcode = opcode,
+ .nargs = proto->nforms,
+ .attributes = attributes,
+ };
+
+ Dwarf_Off nread = readp - startp;
+ if (nread > table->read)
+ table->read = nread;
+
+ if (callback (¯o, arg) != DWARF_CB_OK)
+ return readp - startp;
+ }
+
+ return 0;
+}
+
+static ptrdiff_t
+gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
+ int (*callback) (Dwarf_Macro *, void *),
+ void *arg, ptrdiff_t token)
+{
+ assert (token <= 0);
- if (callback (&mac, arg) != DWARF_CB_OK)
- return readp - (const unsigned char *) d->d_buf;
+ ptrdiff_t ret = read_macros (dbg, NULL, IDX_debug_macro,
+ macoff, callback, arg, -token);
+ if (ret == -1)
+ return -1;
+ else
+ return -ret;
+}
+
+static ptrdiff_t
+macro_info_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
+ int (*callback) (Dwarf_Macro *, void *),
+ void *arg, ptrdiff_t token)
+{
+ assert (token >= 0);
+
+ Dwarf_Macro_Op_Table *table = get_macinfo_table ();
+ assert (table != NULL);
+
+ return read_macros (dbg, table, IDX_debug_macinfo,
+ macoff, callback, arg, token);
+}
+
+ptrdiff_t
+dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
+ int (*callback) (Dwarf_Macro *, void *),
+ void *arg, ptrdiff_t token)
+{
+ if (dbg == NULL)
+ {
+ __libdw_seterrno (DWARF_E_NO_DWARF);
+ return -1;
+ }
+
+ /* We use token values > 0 for iteration through .debug_macinfo and
+ values < 0 for iteration through .debug_macro. Return value of
+ -1 also signifies an error, but that's fine, because .debug_macro
+ always contains at least three bytes of headers and after
+ iterating one opcode, we should never see anything above -4. */
+
+ if (token > 0)
+ /* A continuation call from DW_AT_macro_info iteration. */
+ return macro_info_getmacros_off (dbg, macoff, callback, arg, token);
+
+ /* Either a DW_AT_GNU_macros continuation, or a fresh start
+ thereof. */
+ return gnu_macros_getmacros_off (dbg, macoff, callback, arg, token);
+}
+
+ptrdiff_t
+dwarf_getmacros_die (Dwarf_Die *cudie, Dwarf_Off *macoffp,
+ int (*callback) (Dwarf_Macro *, void *),
+ void *arg, ptrdiff_t token)
+{
+ if (cudie == NULL)
+ {
+ __libdw_seterrno (DWARF_E_NO_DWARF);
+ return -1;
+ }
+
+ if (token > 0 && macoffp != NULL)
+ /* A continuation call from DW_AT_macro_info iteration, meaning
+ *MACOFF contains previously-cached offset. */
+ return macro_info_getmacros_off (cudie->cu->dbg, *macoffp,
+ callback, arg, token);
+
+ /* A fresh start of DW_AT_macro_info iteration, or a continuation
+ thereof without a cache. */
+ if (token > 0
+ || (token == 0 && dwarf_hasattr (cudie, DW_AT_macro_info)))
+ {
+ Dwarf_Word macoff;
+ if (macoffp == NULL)
+ macoffp = &macoff;
+ if (get_offset_from (cudie, DW_AT_macro_info, macoffp) != 0)
+ return -1;
+ return macro_info_getmacros_off (cudie->cu->dbg, *macoffp,
+ callback, arg, token);
+ }
+
+ if (token < 0 && macoffp != NULL)
+ /* A continuation call from DW_AT_GNU_macros iteration. */
+ return gnu_macros_getmacros_off (cudie->cu->dbg, *macoffp,
+ callback, arg, token);
+
+ /* Likewise without cache, or iteration start. */
+ Dwarf_Word macoff;
+ if (macoffp == NULL)
+ macoffp = &macoff;
+ if (get_offset_from (cudie, DW_AT_GNU_macros, macoffp) != 0)
+ return -1;
+ return gnu_macros_getmacros_off (cudie->cu->dbg, *macoffp,
+ callback, arg, token);
+}
+
+ptrdiff_t
+dwarf_getmacros (die, callback, arg, offset)
+ Dwarf_Die *die;
+ int (*callback) (Dwarf_Macro *, void *);
+ void *arg;
+ ptrdiff_t offset;
+{
+ if (die == NULL)
+ return -1;
+
+ if (offset == 0)
+ {
+ /* We can't support .debug_macro transparently by
+ dwarf_getmacros, because extant callers would think that the
+ returned macro opcodes come from DW_MACINFO_* domain and be
+ confused. */
+ if (unlikely (! dwarf_hasattr (die, DW_AT_macro_info)))
+ {
+ __libdw_seterrno (DWARF_E_NO_ENTRY);
+ return -1;
+ }
+
+ /* DIE's with both DW_AT_GNU_macros and DW_AT_macro_info are
+ disallowed by the proposal that DW_AT_GNU_macros support is
+ based on, and this attribute would derail us above, so check
+ for it now. */
+ if (unlikely (dwarf_hasattr (die, DW_AT_GNU_macros)))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
}
+ else
+ /* If non-zero, this ought to be a continuation from previous
+ DW_AT_macro_info iteration, meaning offset can't be
+ negative. */
+ assert (offset > 0);
- /* If we come here the termination of the data for the CU is not
- present. */
- invalid:
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return -1;
+ /* At this point we can safely piggy-back on existing new-style
+ interfaces. */
+ return dwarf_getmacros_die (die, NULL, callback, arg, offset);
}
diff --git a/libdw/dwarf_macro_getparamcnt.c b/libdw/dwarf_macro_getparamcnt.c
new file mode 100644
index 0000000..294134d
--- /dev/null
+++ b/libdw/dwarf_macro_getparamcnt.c
@@ -0,0 +1,43 @@
+/* Return number of parameters of a macro.
+ Copyright (C) 2014 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils 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 copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+int
+dwarf_macro_getparamcnt (Dwarf_Macro *macro, size_t *paramcntp)
+{
+ if (macro == NULL)
+ return -1;
+
+ *paramcntp = macro->nargs;
+ return 0;
+}
diff --git a/libdw/dwarf_macro_line_offset.c b/libdw/dwarf_macro_line_offset.c
new file mode 100644
index 0000000..531085c
--- /dev/null
+++ b/libdw/dwarf_macro_line_offset.c
@@ -0,0 +1,45 @@
+/* Return .debug_line offset associated with given macro.
+ Copyright (C) 2014 Red Hat, Inc.
+ This file is part of elfutils.
+ Written by Ulrich Drepper <drepper(a)redhat.com>, 2005.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils 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 copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_macro_line_offset (Dwarf_Macro *macro, Dwarf_Off *offp)
+{
+ if (macro == NULL)
+ return -1;
+
+ *offp = macro->line_offset;
+ return 0;
+}
diff --git a/libdw/dwarf_macro_param.c b/libdw/dwarf_macro_param.c
new file mode 100644
index 0000000..b66b8ac
--- /dev/null
+++ b/libdw/dwarf_macro_param.c
@@ -0,0 +1,46 @@
+/* Return a given parameter of a macro.
+ Copyright (C) 2014 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils 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 copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+int
+dwarf_macro_param (Dwarf_Macro *macro, size_t idx, Dwarf_Attribute *ret)
+{
+ if (macro == NULL)
+ return -1;
+
+ if (idx >= macro->nargs)
+ return -1;
+
+ *ret = macro->attributes[idx];
+ return 0;
+}
diff --git a/libdw/dwarf_macro_param1.c b/libdw/dwarf_macro_param1.c
index 35d4a71..337ad6f 100644
--- a/libdw/dwarf_macro_param1.c
+++ b/libdw/dwarf_macro_param1.c
@@ -1,5 +1,5 @@
/* Return first macro parameter.
- Copyright (C) 2005 Red Hat, Inc.
+ Copyright (C) 2005, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2005.
@@ -40,7 +40,9 @@ dwarf_macro_param1 (Dwarf_Macro *macro, Dwarf_Word *paramp)
if (macro == NULL)
return -1;
- *paramp = macro->param1;
+ Dwarf_Attribute param;
+ if (dwarf_macro_param (macro, 1, ¶m) != 0)
+ return -1;
- return 0;
+ return dwarf_formudata (¶m, paramp);
}
diff --git a/libdw/dwarf_macro_param2.c b/libdw/dwarf_macro_param2.c
index b49e60e..cc902c9 100644
--- a/libdw/dwarf_macro_param2.c
+++ b/libdw/dwarf_macro_param2.c
@@ -1,5 +1,5 @@
/* Return second macro parameter.
- Copyright (C) 2005 Red Hat, Inc.
+ Copyright (C) 2005, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2005.
@@ -40,10 +40,16 @@ dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp, const char **strp)
if (macro == NULL)
return -1;
- if (paramp != NULL)
- *paramp = macro->param2.u;
- if (strp != NULL)
- *strp = macro->param2.s;
+ Dwarf_Attribute param;
+ if (dwarf_macro_param (macro, 1, ¶m) != 0)
+ return -1;
- return 0;
+ if (param.form == DW_FORM_string
+ || param.form == DW_FORM_strp)
+ {
+ *strp = dwarf_formstring (¶m);
+ return 0;
+ }
+ else
+ return dwarf_formudata (¶m, paramp);
}
diff --git a/libdw/dwarf_macro_version.c b/libdw/dwarf_macro_version.c
new file mode 100644
index 0000000..0b4b189
--- /dev/null
+++ b/libdw/dwarf_macro_version.c
@@ -0,0 +1,44 @@
+/* Return a version of a macro.
+ Copyright (C) 2014 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils 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 copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+int
+dwarf_macro_version (Dwarf_Macro *macro, unsigned int *versionp)
+{
+ if (macro == NULL)
+ return -1;
+
+ *versionp = macro->version;
+
+ return 0;
+}
diff --git a/libdw/libdw.h b/libdw/libdw.h
index 196d54a..bd5a0c6 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -827,25 +827,98 @@ extern int dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts);
/* Call callback function for each of the macro information entry for
- the CU. */
+ the CU. Similar in operation to dwarf_getmacros_die, but only
+ works for .debug_macinfo style macro entries (those where
+ dwarf_macro_version returns 0.) */
extern ptrdiff_t dwarf_getmacros (Dwarf_Die *cudie,
int (*callback) (Dwarf_Macro *, void *),
- void *arg, ptrdiff_t offset)
- __nonnull_attribute__ (2);
+ void *arg, ptrdiff_t token)
+ __nonnull_attribute__ (2);
+
+/* Iterate through the macro section referenced by CUDIE and call
+ CALLBACK for each macro information entry. Keeps iterating while
+ CALLBACK returns DWARF_CB_OK. If the callback returns
+ DWARF_CB_ABORT, it stops iterating and returns a continuation
+ token, which can be used to restart the iteration at the point
+ where it ended. Returns -1 for errors or 0 if there are no more
+ macro entries.
+
+ If MACOFFP is non-NULL, offset to macro section referenced by CUDIE
+ is stored to *MACOFFP. That can later be passed together with a
+ continuation token to dwarf_getmacros_off.
+
+ If this is called with non-0 TOKEN (i.e. it is a continuation
+ call), MACOFFP shall be either NULL, or point to a location that
+ contains the same section offset as was at *MACOFFP of the call
+ that the passed-in continuation token came from. */
+extern ptrdiff_t dwarf_getmacros_die (Dwarf_Die *cudie, Dwarf_Off *macoffp,
+ int (*callback) (Dwarf_Macro *, void *),
+ void *arg, ptrdiff_t token)
+ __nonnull_attribute__ (3);
+
+/* This is similar in operation to dwarf_getmacros_die, but selects
+ the section to iterate through by offset instead of by CU. This
+ can be used for handling DW_MACRO_GNU_transparent_include's or
+ similar opcodes, or for continuation calls seeded with MACOFF and
+ TOKEN that came back from dwarf_getmacros_die (or a previous call
+ to dwarf_getmacros_off). Note that with TOKEN of 0, this will
+ always iterate through DW_AT_GNU_macros style section. */
+extern ptrdiff_t dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
+ int (*callback) (Dwarf_Macro *, void *),
+ void *arg, ptrdiff_t token)
+ __nonnull_attribute__ (3);
+
+/* Return Dwarf version of this macro opcode. The versions are 0 for
+ macro elements coming from DW_AT_macro_info, and 4 for macro
+ elements coming from DW_AT_GNU_macros. It is expected that 5 and
+ further will be for macro elements coming from standardized
+ DW_AT_macros. */
+extern int dwarf_macro_version (Dwarf_Macro *macro, unsigned int *versionp)
+ __nonnull_attribute__ (2);
+
+/* Set *OFFP to .debug_line offset associated with the Dwarf macro
+ section that this MACRO comes from. Returns -1 for errors or 0 for
+ success.
-/* Return macro opcode. */
+ The offset is considered to be 0xffffffffffffffff (or (Dwarf_Off)
+ -1) if .debug_line offset was not set in the section header, which
+ will always be the case for .debug_macinfo macro sections, and may
+ be the case for .debug_macro sections as well. This condition is
+ not considered an error. */
+extern int dwarf_macro_line_offset (Dwarf_Macro *macro, Dwarf_Off *offp)
+ __nonnull_attribute__ (2);
+
+/* Return macro opcode. That's a constant that can be either from
+ DW_MACINFO_* domain if version of MACRO is 0, or from
+ DW_MACRO_GNU_* domain if the version is 4. */
extern int dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep)
__nonnull_attribute__ (2);
-/* Return first macro parameter. */
+/* Get number of parameters of MACRO and store it to *PARAMCNTP. */
+extern int dwarf_macro_getparamcnt (Dwarf_Macro *macro, size_t *paramcntp);
+
+/* Get IDX-th parameter of MACRO, and stores it to *ATTRIBUTE.
+ Returns 0 on success or -1 for errors.
+
+ After a successful call, you can query ATTRIBUTE by dwarf_whatform
+ to determine which of the dwarf_formX calls to make to get actual
+ value out of ATTRIBUTE. Note that calling dwarf_whatattr is not
+ meaningful for pseudo-attributes formed this way. */
+extern int dwarf_macro_param (Dwarf_Macro *macro, size_t idx,
+ Dwarf_Attribute *attribute);
+
+/* Return first macro parameter. This will return -1 if the parameter
+ is not an integral value. Use dwarf_macro_param for more general
+ access. */
extern int dwarf_macro_param1 (Dwarf_Macro *macro, Dwarf_Word *paramp)
__nonnull_attribute__ (2);
-/* Return second macro parameter. */
+/* Return second macro parameter. This will return -1 if the
+ parameter is not an integral or string value. Use
+ dwarf_macro_param for more general access. */
extern int dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp,
const char **strp);
-
/* Compute what's known about a call frame when the PC is at ADDRESS.
Returns 0 for success or -1 for errors.
On success, *FRAME is a malloc'd pointer. */
diff --git a/libdw/libdw.map b/libdw/libdw.map
index 55bc537..5a88bdc 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -306,4 +306,13 @@ ELFUTILS_0.160 {
global:
dwarf_cu_getdwarf;
dwarf_cu_die;
-} ELFUTILS_0.159;
\ No newline at end of file
+} ELFUTILS_0.159;
+
+ELFUTILS_0.161 {
+ global:
+ dwarf_getmacros_die;
+ dwarf_getmacros_off;
+ dwarf_macro_version;
+ dwarf_macro_getparamcnt;
+ dwarf_macro_param;
+} ELFUTILS_0.160;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index ce8a83d..47c2cc1 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -118,7 +118,8 @@ enum
DWARF_E_INVALID_OFFSET,
DWARF_E_NO_DEBUG_RANGES,
DWARF_E_INVALID_CFI,
- DWARF_E_NO_ALT_DEBUGLINK
+ DWARF_E_NO_ALT_DEBUGLINK,
+ DWARF_E_INVALID_OPCODE,
};
@@ -167,6 +168,9 @@ struct Dwarf
Dwarf_Off next_tu_offset;
Dwarf_Sig8_Hash sig8_hash;
+ /* Search tree for .debug_macro operator tables. */
+ void *macro_ops;
+
/* Address ranges. */
Dwarf_Aranges *aranges;
@@ -326,16 +330,48 @@ struct Dwarf_CU
}) \
-/* Macro information. */
+/* Prototype of a single .debug_macro operator. */
+typedef struct
+{
+ Dwarf_Word nforms;
+ unsigned char const *forms;
+} Dwarf_Macro_Op_Proto;
+
+/* Prototype table. */
+typedef struct
+{
+ /* Offset of .debug_macro section. */
+ Dwarf_Off offset;
+
+ /* Offset of associated .debug_line section. */
+ Dwarf_Off line_offset;
+
+ /* How far have we read in this section. This starts as 0 and is
+ increased as the section is worked through. */
+ Dwarf_Off read;
+
+ /* Header length. */
+ Dwarf_Half header_len;
+
+ uint16_t version;
+ bool is_64bit;
+
+ /* Shows where in TABLE each opcode is defined. Since opcode 0 is
+ never used, it stores index of opcode X in X-1'th element. The
+ value of 0xff means not stored at all. */
+ unsigned char opcodes[255];
+
+ /* Individual opcode prototypes. */
+ Dwarf_Macro_Op_Proto table[];
+} Dwarf_Macro_Op_Table;
+
struct Dwarf_Macro_s
{
- unsigned int opcode;
- Dwarf_Word param1;
- union
- {
- Dwarf_Word u;
- const char *s;
- } param2;
+ Dwarf_Off line_offset;
+ Dwarf_Word nargs;
+ uint16_t version;
+ uint8_t opcode;
+ Dwarf_Attribute *attributes;
};
--
1.7.6.5
9 years, 6 months