Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[PATCH 3/3] Dwarf: unwind the recorded stack frame of different target address sizes

12 views
Skip to first unread message

Jean Pihet

unread,
Jan 20, 2014, 4:30:01 PM1/20/14
to
When in compat mode, correctly unwind the recorded stack frame. The
returned pointers are cast to the desired target address size.

Signed-off-by: Jean Pihet <jean....@linaro.org>
---
src/dwarf/Gparser.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)

diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c
index b251e31..d676861 100644
--- a/src/dwarf/Gparser.c
+++ b/src/dwarf/Gparser.c
@@ -706,6 +706,29 @@ eval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as,
return 0;
}

+/* Cast pointer content to the type of target address size */
+static inline int cast_value_to_addr_size(unw_word_t *val, int addr_size)
+{
+ switch (addr_size) {
+ /*
+ * Return the value of the type found at binary load time (e.g. from the
+ * ELF format)...
+ */
+ case TARGET_ADDR_SIZE_32:
+ *val = (uint32_t) *val;
+ break;
+ case TARGET_ADDR_SIZE_64:
+ *val = (uint64_t) *val;
+ break;
+ /* ... otherwise leave it as is */
+ case TARGET_ADDR_SIZE_DEFAULT:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int
apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
{
@@ -743,6 +766,8 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
regnum = dwarf_to_unw_regnum (rs->reg[DWARF_CFA_REG_COLUMN].val);
if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0)
return ret;
+ /* Cast value to the type as found in the ELF binary format */
+ cast_value_to_addr_size(&cfa, as->target_addr_size);
}
cfa += rs->reg[DWARF_CFA_OFF_COLUMN].val;
}
@@ -797,6 +822,8 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip);
if (ret < 0)
return ret;
+ /* Cast value to the type as found in the ELF binary format */
+ cast_value_to_addr_size(&ip, as->target_addr_size);
c->ip = ip;
}

--
1.7.11.7

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majo...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Jean Pihet

unread,
Jan 20, 2014, 4:30:04 PM1/20/14
to
In the case of unwinding the debug info from a binary that has a different
address size than the current native platform, it is needed to record
it in the address space struct, in order to correctly parse the debug
info later. This mode is known as compat mode.

This is the case when e.g. profiling an ARMv7 binary that runs on an
ARMv8 (aka AARCH64) platform.

Depending on the target binary address size, loading and parsing of the
dwarf debug info and unwinding of the recorded stack frame must be
performed accordingly.

Tested dwarf local unwinding on ARMv8 (aka AARCH64) with ARMv7 and
ARMv8 binaries; and natively on X86_64.

Note:
- this series is an RFC, although tested OK on ARMv7, ARMv8 and x86_64,
- only local unwinding has been tested,
- retrieval of the next ip and frame pointer is performed using a
native read followed by a cast to the desired target address size.


Jean Pihet (3):
Add support for different binary target address sizes
Dwarf: load and parse the debug info of different target address
sizes
Dwarf: unwind the recorded stack frame of different target address
sizes

include/libunwind_i.h | 7 ++
include/tdep-aarch64/libunwind_i.h | 1 +
include/tdep-arm/libunwind_i.h | 1 +
include/tdep-hppa/libunwind_i.h | 1 +
include/tdep-ia64/libunwind_i.h | 1 +
include/tdep-mips/libunwind_i.h | 1 +
include/tdep-ppc32/libunwind_i.h | 1 +
include/tdep-ppc64/libunwind_i.h | 1 +
include/tdep-sh/libunwind_i.h | 1 +
include/tdep-x86/libunwind_i.h | 1 +
include/tdep-x86_64/libunwind_i.h | 1 +
src/dwarf/Gfde.c | 25 +++--
src/dwarf/Gfind_proc_info-lsb.c | 194 +++++++++++++++++++++++++++++--------
src/dwarf/Gparser.c | 27 ++++++
14 files changed, 214 insertions(+), 49 deletions(-)

Jean Pihet

unread,
Jan 20, 2014, 4:30:05 PM1/20/14
to
When in compat mode, load and parse the dwarf debug info accordingly.

Tested dwarf local unwinding on ARMv8 (aka AARCH64) with ARMv7 and
ARMv8 binaries.

Signed-off-by: Jean Pihet <jean....@linaro.org>
---
src/dwarf/Gfde.c | 25 ++++--
src/dwarf/Gfind_proc_info-lsb.c | 194 +++++++++++++++++++++++++++++++---------
2 files changed, 170 insertions(+), 49 deletions(-)

diff --git a/src/dwarf/Gfde.c b/src/dwarf/Gfde.c
index 8659624..81959d1 100644
--- a/src/dwarf/Gfde.c
+++ b/src/dwarf/Gfde.c
@@ -59,14 +59,23 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
/* Pick appropriate default for FDE-encoding. DWARF spec says
start-IP (initial_location) and the code-size (address_range) are
"address-unit sized constants". The `R' augmentation can be used
- to override this, but by default, we pick an address-sized unit
- for fde_encoding. */
- switch (dwarf_addr_size (as))
- {
- case 4: fde_encoding = DW_EH_PE_udata4; break;
- case 8: fde_encoding = DW_EH_PE_udata8; break;
- default: fde_encoding = DW_EH_PE_omit; break;
- }
+ to override this, but by default, we pick the target binary address
+ size unit for fde_encoding. */
+ switch (as->target_addr_size)
+ {
+ /* If defined at binary load time (e.g. from the ELF format) */
+ case TARGET_ADDR_SIZE_32: fde_encoding = DW_EH_PE_udata4; break;
+ case TARGET_ADDR_SIZE_64: fde_encoding = DW_EH_PE_udata8; break;
+ /* If not defined, use the current address size unit */
+ case TARGET_ADDR_SIZE_DEFAULT:
+ default:
+ switch (dwarf_addr_size (as))
+ {
+ case 4: fde_encoding = DW_EH_PE_udata4; break;
+ case 8: fde_encoding = DW_EH_PE_udata8; break;
+ default: fde_encoding = DW_EH_PE_omit; break;
+ }
+ }

dci->lsda_encoding = DW_EH_PE_omit;
dci->handler = 0;
diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c
index f75bda2..8c35e58 100644
--- a/src/dwarf/Gfind_proc_info-lsb.c
+++ b/src/dwarf/Gfind_proc_info-lsb.c
@@ -81,36 +81,89 @@ linear_search (unw_addr_space_t as, unw_word_t ip,
#endif /* !UNW_REMOTE_ONLY */

#ifdef CONFIG_DEBUG_FRAME
-/* Load .debug_frame section from FILE. Allocates and returns space
- in *BUF, and sets *BUFSIZE to its size. IS_LOCAL is 1 if using the
- local process, in which case we can search the system debug file
- directory; 0 for other address spaces, in which case we do not; or
- -1 for recursive calls following .gnu_debuglink. Returns 0 on
- success, 1 on error. Succeeds even if the file contains no
- .debug_frame. */
-/* XXX: Could use mmap; but elf_map_image keeps tons mapped in. */
-
-static int
-load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
+static int load_debug_frame_Elf32(const char *file, FILE *f, char *linkbuf,
+ size_t *linksize, char **buf, size_t *bufsize)
{
- FILE *f;
- Elf_W (Ehdr) ehdr;
- Elf_W (Half) shstrndx;
- Elf_W (Shdr) *sec_hdrs = NULL;
+ Elf32_Ehdr ehdr;
+ Elf32_Shdr *sec_hdrs = NULL;
+ Elf32_Half shstrndx;
char *stringtab = NULL;
unsigned int i;
- size_t linksize = 0;
- char *linkbuf = NULL;
+
+ if (fseek(f, 0L, SEEK_SET))
+ goto file_error;
+ if (fread (&ehdr, sizeof(Elf32_Ehdr), 1, f) != 1)
+ goto file_error;

- *buf = NULL;
- *bufsize = 0;
+ shstrndx = ehdr.e_shstrndx;

- f = fopen (file, "r");
+ Debug (4, "opened file '%s'. Section header at offset %d\n",
+ file, (int) ehdr.e_shoff);
+
+ fseek (f, ehdr.e_shoff, SEEK_SET);
+ sec_hdrs = calloc (ehdr.e_shnum, sizeof(Elf32_Shdr));
+ if (fread (sec_hdrs, sizeof(Elf32_Shdr), ehdr.e_shnum, f) != ehdr.e_shnum)
+ goto file_error;

- if (!f)
- return 1;
+ Debug (4, "loading string table of size %zd\n",
+ sec_hdrs[shstrndx].sh_size);
+ stringtab = malloc (sec_hdrs[shstrndx].sh_size);
+ fseek (f, sec_hdrs[shstrndx].sh_offset, SEEK_SET);
+ if (fread (stringtab, 1, sec_hdrs[shstrndx].sh_size, f) != sec_hdrs[shstrndx].sh_size)
+ goto file_error;

- if (fread (&ehdr, sizeof (Elf_W (Ehdr)), 1, f) != 1)
+ for (i = 1; i < ehdr.e_shnum && *buf == NULL; i++)
+ {
+ char *secname = &stringtab[sec_hdrs[i].sh_name];
+
+ if (strcmp (secname, ".debug_frame") == 0)
+ {
+ *bufsize = sec_hdrs[i].sh_size;
+ *buf = malloc (*bufsize);
+
+ fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
+ if (fread (*buf, 1, *bufsize, f) != *bufsize)
+ goto file_error;
+
+ Debug (4, "read %zd bytes of .debug_frame from offset %d\n",
+ *bufsize, sec_hdrs[i].sh_offset);
+ }
+ else if (strcmp (secname, ".gnu_debuglink") == 0)
+ {
+ *linksize = sec_hdrs[i].sh_size;
+ linkbuf = malloc(*linksize);
+
+ fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
+ if (fread (linkbuf, 1, *linksize, f) != *linksize)
+ goto file_error;
+
+ Debug (4, "read %d bytes of .gnu_debuglink from offset %d\n",
+ (int) *linksize, sec_hdrs[i].sh_offset);
+ }
+ }
+
+ free(sec_hdrs);
+ free(stringtab);
+ return 0;
+
+file_error:
+ free(sec_hdrs);
+ free(stringtab);
+ return -1;
+}
+
+static int load_debug_frame_Elf64(const char *file, FILE *f, char *linkbuf,
+ size_t *linksize, char **buf, size_t *bufsize)
+{
+ Elf64_Ehdr ehdr;
+ Elf64_Shdr *sec_hdrs = NULL;
+ Elf64_Half shstrndx;
+ char *stringtab = NULL;
+ unsigned int i;
+
+ if (fseek(f, 0L, SEEK_SET))
+ goto file_error;
+ if (fread (&ehdr, sizeof(Elf64_Ehdr), 1, f) != 1)
goto file_error;

shstrndx = ehdr.e_shstrndx;
@@ -119,8 +172,8 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
file, (int) ehdr.e_shoff);

fseek (f, ehdr.e_shoff, SEEK_SET);
- sec_hdrs = calloc (ehdr.e_shnum, sizeof (Elf_W (Shdr)));
- if (fread (sec_hdrs, sizeof (Elf_W (Shdr)), ehdr.e_shnum, f) != ehdr.e_shnum)
+ sec_hdrs = calloc (ehdr.e_shnum, sizeof(Elf64_Shdr));
+ if (fread (sec_hdrs, sizeof(Elf64_Shdr), ehdr.e_shnum, f) != ehdr.e_shnum)
goto file_error;

Debug (4, "loading string table of size %zd\n",
@@ -131,7 +184,7 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
goto file_error;

for (i = 1; i < ehdr.e_shnum && *buf == NULL; i++)
- {
+ {
char *secname = &stringtab[sec_hdrs[i].sh_name];

if (strcmp (secname, ".debug_frame") == 0)
@@ -148,20 +201,71 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
}
else if (strcmp (secname, ".gnu_debuglink") == 0)
{
- linksize = sec_hdrs[i].sh_size;
- linkbuf = malloc (linksize);
+ *linksize = sec_hdrs[i].sh_size;
+ linkbuf = malloc(*linksize);

fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
- if (fread (linkbuf, 1, linksize, f) != linksize)
+ if (fread (linkbuf, 1, *linksize, f) != *linksize)
goto file_error;

- Debug (4, "read %zd bytes of .gnu_debuglink from offset %zd\n",
- linksize, sec_hdrs[i].sh_offset);
+ Debug (4, "read %d bytes of .gnu_debuglink from offset %zd\n",
+ (int) *linksize, sec_hdrs[i].sh_offset);
}
- }
+ }
+
+ free(sec_hdrs);
+ free(stringtab);
+ return 0;
+
+file_error:
+ free(sec_hdrs);
+ free(stringtab);
+ return -1;
+}
+
+/* Load .debug_frame section from FILE. Allocates and returns space
+ in *BUF, and sets *BUFSIZE to its size. IS_LOCAL is 1 if using the
+ local process, in which case we can search the system debug file
+ directory; 0 for other address spaces, in which case we do not; or
+ -1 for recursive calls following .gnu_debuglink. Returns 0 on
+ success, 1 on error. Succeeds even if the file contains no
+ .debug_frame. */
+/* XXX: Could use mmap; but elf_map_image keeps tons mapped in. */

- free (stringtab);
- free (sec_hdrs);
+static int
+load_debug_frame (const char *file, char **buf, size_t *bufsize,
+ unw_addr_space_t as, int is_local)
+{
+ FILE *f;
+ unsigned char e_ident[sizeof(((Elf32_Ehdr *)0)->e_ident)];
+ size_t linksize = 0;
+ char *linkbuf = NULL;
+
+ *buf = NULL;
+ *bufsize = 0;
+
+ f = fopen (file, "r");
+
+ if (!f)
+ return 1;
+
+ if (fread (&e_ident, sizeof(e_ident), 1, f) != 1)
+ goto file_error;
+
+ switch (e_ident[EI_CLASS]) {
+ case ELFCLASS32:
+ as->target_addr_size = TARGET_ADDR_SIZE_32;
+ load_debug_frame_Elf32(file, f, linkbuf, &linksize, buf, bufsize);
+ break;
+ case ELFCLASS64:
+ as->target_addr_size = TARGET_ADDR_SIZE_64;
+ load_debug_frame_Elf64(file, f, linkbuf, &linksize, buf, bufsize);
+ break;
+ case ELFCLASSNONE:
+ default:
+ Debug (15, "Wrong ELF class 0x%02x\n", e_ident[EI_CLASS]);
+ goto file_error;
+ }

fclose (f);

@@ -195,14 +299,14 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
strcpy (newname, basedir);
strcat (newname, "/");
strcat (newname, linkbuf);
- ret = load_debug_frame (newname, buf, bufsize, -1);
+ ret = load_debug_frame (newname, buf, bufsize, as, -1);

if (ret == 1)
{
strcpy (newname, basedir);
strcat (newname, "/.debug/");
strcat (newname, linkbuf);
- ret = load_debug_frame (newname, buf, bufsize, -1);
+ ret = load_debug_frame (newname, buf, bufsize, as, -1);
}

if (ret == 1 && is_local == 1)
@@ -211,20 +315,19 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
strcat (newname, basedir);
strcat (newname, "/");
strcat (newname, linkbuf);
- ret = load_debug_frame (newname, buf, bufsize, -1);
+ ret = load_debug_frame (newname, buf, bufsize, as, -1);
}

free (basedir);
free (newname);
}
- free (linkbuf);
+
+ free(linkbuf);

return 0;

/* An error reading image file. Release resources and return error code */
file_error:
- free(stringtab);
- free(sec_hdrs);
free(linkbuf);
fclose(f);

@@ -303,7 +406,8 @@ locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname,
else
name = (char*) dlname;

- err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space);
+ err = load_debug_frame (name, &buf, &bufsize, as,
+ as == unw_local_addr_space);

if (!err)
{
@@ -851,6 +955,14 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
#ifndef UNW_REMOTE_ONLY
struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data;

+ /*
+ * Set the target address size as found in the loaded debug binary.
+ * Note: in case of local unwinding the caller 'as' is set to
+ * unw_local_addr_space, cf. below. Let's assign the value to
+ * the caller 'as' before changing the value of 'as'.
+ */
+ as->target_addr_size = unw_local_addr_space->target_addr_size;
+
/* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is read from local address
space. Both the index and the unwind tables live in local memory, but
the address space to check for properties like the address size and

Jean Pihet

unread,
Jan 20, 2014, 4:30:03 PM1/20/14
to
In the case of unwinding the debug info from a binary that has a different
address size than the current native platform, it is needed to record
it in the address space struct, in order to correctly parse the debug
info later. This mode is known as compat mode.

This is the case on e.g. profiling an ARMv7 binary that runs on an
ARMv8 (aka AARCH64) platform.

Add the target_addr_size field in the unw_addr_space struct and provide
the 32 and 64 bit macros for use in the code.

Signed-off-by: Jean Pihet <jean....@linaro.org>
---
include/libunwind_i.h | 7 +++++++
include/tdep-aarch64/libunwind_i.h | 1 +
include/tdep-arm/libunwind_i.h | 1 +
include/tdep-hppa/libunwind_i.h | 1 +
include/tdep-ia64/libunwind_i.h | 1 +
include/tdep-mips/libunwind_i.h | 1 +
include/tdep-ppc32/libunwind_i.h | 1 +
include/tdep-ppc64/libunwind_i.h | 1 +
include/tdep-sh/libunwind_i.h | 1 +
include/tdep-x86/libunwind_i.h | 1 +
include/tdep-x86_64/libunwind_i.h | 1 +
11 files changed, 17 insertions(+)

diff --git a/include/libunwind_i.h b/include/libunwind_i.h
index 0be551f..859ae03 100644
--- a/include/libunwind_i.h
+++ b/include/libunwind_i.h
@@ -345,6 +345,13 @@ static inline void invalidate_edi (struct elf_dyn_info *edi)
# define PT_ARM_EXIDX 0x70000001 /* ARM unwind segment */
#endif /* !PT_ARM_EXIDX */

+/* Define binary target address size */
+enum {
+ TARGET_ADDR_SIZE_DEFAULT,
+ TARGET_ADDR_SIZE_32,
+ TARGET_ADDR_SIZE_64
+};
+
#include "tdep/libunwind_i.h"

#ifndef tdep_get_func_addr
diff --git a/include/tdep-aarch64/libunwind_i.h b/include/tdep-aarch64/libunwind_i.h
index b162271..5341118 100644
--- a/include/tdep-aarch64/libunwind_i.h
+++ b/include/tdep-aarch64/libunwind_i.h
@@ -61,6 +61,7 @@ struct unw_addr_space
{
struct unw_accessors acc;
int big_endian;
+ int target_addr_size; /* target binary: 32/64 bit */
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;
diff --git a/include/tdep-arm/libunwind_i.h b/include/tdep-arm/libunwind_i.h
index 291b101..7353f82 100644
--- a/include/tdep-arm/libunwind_i.h
+++ b/include/tdep-arm/libunwind_i.h
@@ -46,6 +46,7 @@ struct unw_addr_space
{
struct unw_accessors acc;
int big_endian;
+ int target_addr_size; /* target binary: 32/64 bit */
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;
diff --git a/include/tdep-hppa/libunwind_i.h b/include/tdep-hppa/libunwind_i.h
index b5bbcec..7e2ebd7 100644
--- a/include/tdep-hppa/libunwind_i.h
+++ b/include/tdep-hppa/libunwind_i.h
@@ -45,6 +45,7 @@ unw_tdep_frame_t;
struct unw_addr_space
{
struct unw_accessors acc;
+ int target_addr_size; /* target binary: 32/64 bit */
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;
diff --git a/include/tdep-ia64/libunwind_i.h b/include/tdep-ia64/libunwind_i.h
index 2bea830..20dd999 100644
--- a/include/tdep-ia64/libunwind_i.h
+++ b/include/tdep-ia64/libunwind_i.h
@@ -96,6 +96,7 @@ struct unw_addr_space
struct unw_accessors acc;
int big_endian;
int abi; /* abi < 0 => unknown, 0 => SysV, 1 => HP-UX, 2 => Windows */
+ int target_addr_size; /* target binary: 32/64 bit */
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;
diff --git a/include/tdep-mips/libunwind_i.h b/include/tdep-mips/libunwind_i.h
index 3ef1cef..c7a0c16 100644
--- a/include/tdep-mips/libunwind_i.h
+++ b/include/tdep-mips/libunwind_i.h
@@ -52,6 +52,7 @@ struct unw_addr_space
int big_endian;
mips_abi_t abi;
unsigned int addr_size;
+ int target_addr_size; /* target binary: 32/64 bit */

unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
diff --git a/include/tdep-ppc32/libunwind_i.h b/include/tdep-ppc32/libunwind_i.h
index 06c0023..3c67454 100644
--- a/include/tdep-ppc32/libunwind_i.h
+++ b/include/tdep-ppc32/libunwind_i.h
@@ -51,6 +51,7 @@ unw_tdep_frame_t;
struct unw_addr_space
{
struct unw_accessors acc;
+ int target_addr_size; /* target binary: 32/64 bit */
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;
diff --git a/include/tdep-ppc64/libunwind_i.h b/include/tdep-ppc64/libunwind_i.h
index 6024455..faf6483 100644
--- a/include/tdep-ppc64/libunwind_i.h
+++ b/include/tdep-ppc64/libunwind_i.h
@@ -53,6 +53,7 @@ struct unw_addr_space
struct unw_accessors acc;
int big_endian;
ppc64_abi_t abi;
+ int target_addr_size; /* target binary: 32/64 bit */
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;
diff --git a/include/tdep-sh/libunwind_i.h b/include/tdep-sh/libunwind_i.h
index 51234d1..c731001 100644
--- a/include/tdep-sh/libunwind_i.h
+++ b/include/tdep-sh/libunwind_i.h
@@ -46,6 +46,7 @@ struct unw_addr_space
{
struct unw_accessors acc;
int big_endian;
+ int target_addr_size; /* target binary: 32/64 bit */
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;
diff --git a/include/tdep-x86/libunwind_i.h b/include/tdep-x86/libunwind_i.h
index f59a3cf..7f5be18 100644
--- a/include/tdep-x86/libunwind_i.h
+++ b/include/tdep-x86/libunwind_i.h
@@ -45,6 +45,7 @@ unw_tdep_frame_t;
struct unw_addr_space
{
struct unw_accessors acc;
+ int target_addr_size; /* target binary: 32/64 bit */
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;
diff --git a/include/tdep-x86_64/libunwind_i.h b/include/tdep-x86_64/libunwind_i.h
index 8c9cd05..623416b 100644
--- a/include/tdep-x86_64/libunwind_i.h
+++ b/include/tdep-x86_64/libunwind_i.h
@@ -62,6 +62,7 @@ unw_tdep_frame_t;
struct unw_addr_space
{
struct unw_accessors acc;
+ int target_addr_size; /* target binary: 32/64 bit */
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;

Will Deacon

unread,
Jan 21, 2014, 6:30:02 AM1/21/14
to
On Mon, Jan 20, 2014 at 09:21:59PM +0000, Jean Pihet wrote:
> In the case of unwinding the debug info from a binary that has a different
> address size than the current native platform, it is needed to record
> it in the address space struct, in order to correctly parse the debug
> info later. This mode is known as compat mode.

Terminology issues here.... compat mode isn't really that well defined, but
typically involves a different kernel ABI. That doesn't necessarily affect
the address size.

> This is the case when e.g. profiling an ARMv7 binary that runs on an
> ARMv8 (aka AARCH64) platform.

ARMv8 != AArch64

Will

Jean Pihet

unread,
Feb 3, 2014, 10:30:02 AM2/3/14
to
Hi Arun,

On 22 January 2014 06:15, Arun Sharma <ar...@sharma-home.net> wrote:
> On Tue, Jan 21, 2014 at 12:16 AM, Jean Pihet <jean....@linaro.org> wrote:
>
>>>> This is the case when e.g. profiling an ARMv7 binary that runs on an
>>>> ARMv8 (aka AARCH64) platform.
>>>
>>> Why not configure libunwind for ARMv7 in that case?
>>>
>>> I'm trying to understand how is your use case different from using
>>> x86_32 libunwind to do local unwinding on a x86_64 machine.
>> Can you give more details on the use case and how to configure
>> libunwind?
>
> You could either build libunwind on a ARMv7 machine and copy it over
> or setup a 32 bit chroot on a 64 bit kernel and compile libunwind
> inside that.
>
>> The provided patches dynamically detect the target binary
>> address size and parse the debug info accordingly, all that in a
>> single library.
>
> This is generally called cross-unwinding in libunwind lingo. Some
> description here:
>
> http://www.nongnu.org/libunwind/man/libunwind%283%29.html#section_4
>
>>
>> Note: my use case is to call libunwind from the perf utility in order
>> to unwind from the dwarf info.
>>
>
> You could link in two copies of libunwind into the perf binary:
> * libunwind.a for local (host == target) unwinding
> * libunwind-arm.a for 32 bit cross-unwinding
>
> Doing cross-unwinding requires you to write a bunch of "accessors" on
> how to access the address space of a non-local thread.
>
> Something like ./configure --target=arm on aarch64.

Thanks for the link and info.

Is there a concrete example of cross-unwinding with multiple targets,
for example on x86_64 using native and x86_32 libunwind libraries
simultaneously?
I am trying to assess the impact of multiple unwinding libs in the perf code.

Jiri, Arnaldo,
How is that done on x86? I do not think this can be done with the
current perf code, am I correct?

>
> -Arun

Regards,
Jean

Arun Sharma

unread,
Feb 3, 2014, 11:00:01 AM2/3/14
to
On Mon, Feb 3, 2014 at 7:28 AM, Jean Pihet <jean....@linaro.org> wrote:

>> Something like ./configure --target=arm on aarch64.
>
> Thanks for the link and info.
>
> Is there a concrete example of cross-unwinding with multiple targets,
> for example on x86_64 using native and x86_32 libunwind libraries
> simultaneously?
> I am trying to assess the impact of multiple unwinding libs in the perf code.

Might want to check with folks who worked on Frysk. There was some
criticism that it was non-trivial, but it's been done.

http://lists.nongnu.org/archive/html/libunwind-devel/2007-05/msg00006.html

-Arun

Jiri Olsa

unread,
Feb 3, 2014, 11:40:01 AM2/3/14
to
correct, but it sounds cool ;-)

jirka
0 new messages