summaryrefslogtreecommitdiffstats
path: root/libdw
diff options
context:
space:
mode:
Diffstat (limited to 'libdw')
-rw-r--r--libdw/ChangeLog7
-rw-r--r--libdw/dwarf_getmacros.c161
-rw-r--r--libdw/libdw.h40
3 files changed, 123 insertions, 85 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index bab02e59..909fdbc1 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,10 @@
+2014-12-02 Petr Machata <[email protected]>
+
+ * dwarf_getmacros.c (token_from_offset, offset_from_token): New
+ helper functions.
+ (do_dwarf_getmacros_die): Merge into dwarf_getmacros.
+ * libdw.h (DWARF_GETMACROS_START): New macro.
+
2014-11-27 Mark Wielaard <[email protected]>
* Makefile.am (libdw.so): Use textrel_check.
diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c
index 8d9d78be..bd64d60f 100644
--- a/libdw/dwarf_getmacros.c
+++ b/libdw/dwarf_getmacros.c
@@ -384,13 +384,57 @@ read_macros (Dwarf *dbg, int sec_index,
return 0;
}
+/* Token layout:
+
+ - The highest bit is used for distinguishing between callers that
+ know that opcode 0xff may have one of two incompatible meanings.
+ The mask that we use for selecting this bit is
+ DWARF_GETMACROS_START.
+
+ - The rest of the token (31 or 63 bits) encodes address inside the
+ macro unit.
+
+ Besides, token value of 0 signals end of iteration and -1 is
+ reserved for signaling errors. That means it's impossible to
+ represent maximum offset of a .debug_macro unit to new-style
+ callers (which in practice decreases the permissible macro unit
+ size by another 1 byte). */
+
+static ptrdiff_t
+token_from_offset (ptrdiff_t offset, bool accept_0xff)
+{
+ if (offset == -1 || offset == 0)
+ return offset;
+
+ /* Make sure the offset didn't overflow into the flag bit. */
+ if ((offset & DWARF_GETMACROS_START) != 0)
+ {
+ __libdw_seterrno (DWARF_E_TOO_BIG);
+ return -1;
+ }
+
+ if (accept_0xff)
+ offset |= DWARF_GETMACROS_START;
+
+ return offset;
+}
+
+static ptrdiff_t
+offset_from_token (ptrdiff_t token, bool *accept_0xffp)
+{
+ *accept_0xffp = (token & DWARF_GETMACROS_START) != 0;
+ token &= ~DWARF_GETMACROS_START;
+
+ return token;
+}
+
static ptrdiff_t
gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
int (*callback) (Dwarf_Macro *, void *),
- void *arg, ptrdiff_t token, bool accept_0xff,
+ void *arg, ptrdiff_t offset, bool accept_0xff,
Dwarf_Die *cudie)
{
- assert (token <= 0);
+ assert (offset >= 0);
if (macoff >= dbg->sectiondata[IDX_debug_macro]->d_size)
{
@@ -398,23 +442,19 @@ gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
return -1;
}
- ptrdiff_t ret = read_macros (dbg, IDX_debug_macro, macoff,
- callback, arg, -token, accept_0xff, cudie);
- if (ret == -1)
- return -1;
- else
- return -ret;
+ return read_macros (dbg, IDX_debug_macro, macoff,
+ callback, arg, offset, accept_0xff, cudie);
}
static ptrdiff_t
macro_info_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
int (*callback) (Dwarf_Macro *, void *),
- void *arg, ptrdiff_t token, Dwarf_Die *cudie)
+ void *arg, ptrdiff_t offset, Dwarf_Die *cudie)
{
- assert (token >= 0);
+ assert (offset >= 0);
return read_macros (dbg, IDX_debug_macinfo, macoff,
- callback, arg, token, true, cudie);
+ callback, arg, offset, true, cudie);
}
ptrdiff_t
@@ -428,21 +468,22 @@ dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
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. */
- assert (token <= 0);
+ bool accept_0xff;
+ ptrdiff_t offset = offset_from_token (token, &accept_0xff);
+ assert (accept_0xff);
- return gnu_macros_getmacros_off (dbg, macoff, callback, arg, token, true,
- NULL);
+ offset = gnu_macros_getmacros_off (dbg, macoff, callback, arg, offset,
+ accept_0xff, NULL);
+
+ return token_from_offset (offset, accept_0xff);
}
-static ptrdiff_t
-do_dwarf_getmacros_die (Dwarf_Die *cudie, Dwarf_Off *macoffp,
- int (*callback) (Dwarf_Macro *, void *),
- void *arg, ptrdiff_t token, bool accept_0xff)
+ptrdiff_t
+dwarf_getmacros (cudie, callback, arg, token)
+ Dwarf_Die *cudie;
+ int (*callback) (Dwarf_Macro *, void *);
+ void *arg;
+ ptrdiff_t token;
{
if (cudie == NULL)
{
@@ -450,50 +491,6 @@ do_dwarf_getmacros_die (Dwarf_Die *cudie, Dwarf_Off *macoffp,
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, cudie);
-
- /* 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, cudie);
- }
-
- 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, accept_0xff,
- cudie);
-
- /* 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, accept_0xff,
- cudie);
-}
-
-ptrdiff_t
-dwarf_getmacros (die, callback, arg, offset)
- Dwarf_Die *die;
- int (*callback) (Dwarf_Macro *, void *);
- void *arg;
- ptrdiff_t offset;
-{
/* This function might be called from a code that expects to see
DW_MACINFO_* opcodes, not DW_MACRO_{GNU_,}* ones. It is fine to
serve most DW_MACRO_{GNU_,}* opcodes to such code, because those
@@ -511,7 +508,33 @@ dwarf_getmacros (die, callback, arg, offset)
some small probability that the two opcodes would look
superficially similar enough that a client would be confused and
misbehave as a result. For this reason, we refuse to serve
- through this interface 0xff's originating from .debug_macro. */
+ through this interface 0xff's originating from .debug_macro
+ unless the TOKEN that we obtained indicates the call originates
+ from a new-style caller. See above for details on what
+ information is encoded into tokens. */
+
+ bool accept_0xff;
+ ptrdiff_t offset = offset_from_token (token, &accept_0xff);
+
+ /* DW_AT_macro_info */
+ if (dwarf_hasattr (cudie, DW_AT_macro_info))
+ {
+ Dwarf_Word macoff;
+ if (get_offset_from (cudie, DW_AT_macro_info, &macoff) != 0)
+ return -1;
+ offset = macro_info_getmacros_off (cudie->cu->dbg, macoff,
+ callback, arg, offset, cudie);
+ }
+ else
+ {
+ /* DW_AT_GNU_macros, DW_AT_macros */
+ Dwarf_Word macoff;
+ if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0)
+ return -1;
+ offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff,
+ callback, arg, offset, accept_0xff,
+ cudie);
+ }
- return do_dwarf_getmacros_die (die, NULL, callback, arg, offset, false);
+ return token_from_offset (offset, accept_0xff);
}
diff --git a/libdw/libdw.h b/libdw/libdw.h
index c0baa219..b2b22828 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -32,6 +32,7 @@
#include <gelf.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
@@ -845,22 +846,24 @@ extern int dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts);
/* Iterate through the macro unit 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. A TOKEN of 0 starts the iteration. Returns -1 for
- errors or 0 if there are no more macro entries.
+ CALLBACK for each macro information entry. To start the iteration,
+ one would pass DWARF_GETMACROS_START for TOKEN.
+
+ The iteration continues while CALLBACK returns DWARF_CB_OK. If the
+ callback returns DWARF_CB_ABORT, the iteration stops and a
+ continuation token is returned, 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.
Note that the Dwarf_Macro pointer passed to the callback is only
valid for the duration of the callback invocation.
- Note that this interface will refuse to serve opcode 0xff from
- .debug_macro sections. Such opcode is considered invalid and will
- cause dwarf_getmacros to return with error. Note that this should
- be no limitation as of now, as DW_MACRO_GNU_* domain doesn't
- allocate 0xff. It is however a theoretical possibility with future
- Dwarf standards. */
+ For backward compatibility, a token of 0 is accepted for starting
+ the iteration as well, but in that case this interface will refuse
+ to serve opcode 0xff from .debug_macro sections. Such opcode would
+ be considered invalid and would cause dwarf_getmacros to return
+ with error. */
+#define DWARF_GETMACROS_START PTRDIFF_MIN
extern ptrdiff_t dwarf_getmacros (Dwarf_Die *cudie,
int (*callback) (Dwarf_Macro *, void *),
void *arg, ptrdiff_t token)
@@ -871,13 +874,16 @@ extern ptrdiff_t dwarf_getmacros (Dwarf_Die *cudie,
iterates .debug_macro. This can be used for handling
DW_MACRO_GNU_transparent_include's or similar opcodes.
+ TOKEN value of DWARF_GETMACROS_START can be used to start the
+ iteration.
+
It is not appropriate to obtain macro unit offset by hand from a CU
DIE and then request iteration through this interface. The reason
for this is that if a dwarf_macro_getsrcfiles is later called,
there would be no way to figure out what DW_AT_comp_dir was present
on the CU DIE, and file names referenced in either the macro unit
itself, or the .debug_line unit that it references, might be wrong.
- Use dwarf_getmacro. */
+ Use dwarf_getmacros. */
extern ptrdiff_t dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
int (*callback) (Dwarf_Macro *, void *),
void *arg, ptrdiff_t token)
@@ -895,9 +901,11 @@ extern int dwarf_macro_getsrcfiles (Dwarf *dbg, Dwarf_Macro *macro,
/* Return macro opcode. That's a constant that can be either from
DW_MACINFO_* domain or DW_MACRO_GNU_* domain. The two domains have
compatible values, so it's OK to use either of them for
- comparisons. The only differences is 0xff, which currently is
- never served from .debug_macro, and can thus be safely assumed to
- mean DW_MACINFO_vendor_ext. */
+ comparisons. The only differences is 0xff, which could be either
+ DW_MACINFO_vendor_ext or a vendor-defined DW_MACRO_* constant. One
+ would need to look if the CU DIE which the iteration was requested
+ for has attribute DW_AT_macro_info, or either of DW_AT_GNU_macros
+ or DW_AT_macros to differentiate the two interpretations. */
extern int dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep)
__nonnull_attribute__ (2);