Coder Social home page Coder Social logo

libunwind / libunwind Goto Github PK

View Code? Open in Web Editor NEW
926.0 31.0 278.0 4.22 MB

libunwind official github repo (in need of new / additional maintainer, mail/open issue if interested)

Home Page: http://www.nongnu.org/libunwind/

License: MIT License

Makefile 2.57% M4 0.87% Shell 1.20% C 89.89% Assembly 4.52% C++ 0.21% CMake 0.73%

libunwind's Introduction

libunwind

libunwind is a portable and efficient C API for determining the current call chain of ELF program threads of execution and for resuming execution at any point in that call chain. The API supports both local (same process) and remote (other process) operation.

The API ise useful in a number of applications, including but not limited to the following.

  • program introspection Either for error messages showing a back trace of the call chain leading to a problem or for performance monitoring and analysis.
  • debugging Whether the debugging and analysis of the call chain of a remote program or the post-mortem analysis of a coredump.
  • language runtime exception handling libunwind optionally provides an alternative implementation of the Itanium exception handling ABI used by many popular toolchains.
  • alternative setjmp()/longjmp() libunwind optionally provides an alternative implementation of the setjmp()/longjmp() functionality of the C standard library.

Supported Systems

CI - Unix CI - Windows

This library supports several architecture/operating-system combinations:

System Architecture Status
Linux x86-64
Linux x86
Linux ARM
Linux AArch64
Linux PPC32
Linux PPC64
Linux SuperH
Linux IA-64
Linux PARISC Works well, but C library missing unwind-info
Linux MIPS
Linux RISC-V 64-bit only
Linux LoongArch 64-bit only
HP-UX IA-64 Mostly works, but known to have serious limitations
FreeBSD x86-64
FreeBSD x86
FreeBSD AArch64
FreeBSD PPC32
FreeBSD PPC64
QNX Aarch64
QNX x86-64
Solaris x86-64

Libc Requirements

libunwind depends on getcontext(), setcontext() functions which are missing from C libraries like musl-libc because they are considered to be "obsolescent" API by POSIX document. The following table tries to track current status of such dependencies

  • r, requires
  • p, provides its own implementation
  • empty, no requirement
Architecture getcontext setcontext
aarch64 p
arm p
hppa p p
ia64 p r
loongarch p
mips p
ppc32 r
ppc64 r r
riscv p p
s390x p p
sh r
x86 p r
x86_64 p p

General Build Instructions

In general, this library can be built and installed with the following commands:

$ autoreconf -i # Needed only for building from git. Depends on libtool.
$ ./configure --prefix=PREFIX
$ make
$ make install

where PREFIX is the installation prefix. By default, a prefix of /usr/local is used, such that libunwind.a is installed in /usr/local/lib and unwind.h is installed in /usr/local/include. For testing, you may want to use a prefix of /usr/local instead.

Building with Intel compiler

Version 8 and later

Starting with version 8, the preferred name for the IA-64 Intel compiler is icc (same name as on x86). Thus, the configure-line should look like this:

$ ./configure CC=icc CFLAGS="-g -O3 -ip" CXX=icc CCAS=gcc CCASFLAGS=-g \
    LDFLAGS="-L$PWD/src/.libs"

Building on HP-UX

For the time being, libunwind must be built with GCC on HP-UX.

libunwind should be configured and installed on HP-UX like this:

$ ./configure CFLAGS="-g -O2 -mlp64" CXXFLAGS="-g -O2 -mlp64"

Caveat: Unwinding of 32-bit (ILP32) binaries is not supported at the moment.

Building for PowerPC64 / Linux

For building for power64 you should use:

$ ./configure CFLAGS="-g -O2 -m64" CXXFLAGS="-g -O2 -m64"

If your power support altivec registers:

$ ./configure CFLAGS="-g -O2 -m64 -maltivec" CXXFLAGS="-g -O2 -m64 -maltivec"

To check if your processor has support for vector registers (altivec):

cat /proc/cpuinfo | grep altivec

and should have something like this:

cpu             : PPC970, altivec supported

If libunwind seems to not work (backtracing failing), try to compile it with -O0, without optimizations. There are some compiler problems depending on the version of your gcc.

Building on FreeBSD

General building instructions apply. To build and execute several tests on older versions of FreeBSD, you need libexecinfo library available in ports as devel/libexecinfo. This port has been removed as of 2017 and is indeed no longer needed.

Regression Testing

After building the library, you can run a set of regression tests with:

$ make check

Expected results on x86 Linux

The following tests are expected to fail on x86 Linux:

  • test-ptrace

Expected results on x86-64 Linux

The following tests are expected to fail on x86-64 Linux:

Expected results on PARISC Linux

The following tests are expected to fail on x86-64 Linux:

  • Gtest-bt (backtrace truncated at kill() due to lack of unwind-info)
  • Ltest-bt (likewise)
  • Gtest-resume-sig (Gresume.c:my_rt_sigreturn() is wrong somehow)
  • Ltest-resume-sig (likewise)
  • Gtest-init (likewise)
  • Ltest-init (likewise)
  • Gtest-dyn1 (no dynamic unwind info support yet)
  • Ltest-dyn1 (no dynamic unwind info support yet)
  • test-setjmp (longjmp() not implemented yet)
  • run-check-namespace (toolchain doesn't support HIDDEN yet)

Expected results on HP-UX

make check is currently unsupported for HP-UX. You can try to run it, but most tests will fail (and some may fail to terminate). The only test programs that are known to work at this time are:

  • tests/bt
  • tests/Gperf-simple
  • tests/test-proc-info
  • tests/test-static-link
  • tests/Gtest-init
  • tests/Ltest-init
  • tests/Gtest-resume-sig
  • tests/Ltest-resume-sig

Expected results on PPC64 Linux

make check should run with no more than 10 out of 24 tests failed.

Expected results on Solaris x86-64

make check is passing 27 out of 33 tests. The following six tests are consistently failing:

  • Gtest-concurrent
  • Ltest-concurrent
  • Ltest-init-local-signal
  • Lrs-race
  • test-setjmp
  • x64-unwind-badjmp-signal-frame

Performance Testing

This distribution includes a few simple performance tests which give some idea of the basic cost of various libunwind operations. After building the library, you can run these tests with the following commands:

$ cd tests
$ make perf

Contacting the Developers

Please raise issues and pull requests through the GitHub repository: https://github.com/libunwind/libunwind.

libunwind's People

Contributors

aaronrobinsonmsft avatar adrianbunk avatar adsharma avatar alexlarsson avatar am11 avatar ararslan avatar bertwesarg avatar bregma avatar codyps avatar dependabot[bot] avatar djwatson avatar employedrussian avatar gleocadie avatar idings avatar james-a-clark avatar kasperk81 avatar kenche-linaro avatar kostikbel avatar ksergeyv avatar lemul avatar mattfischer avatar milianw avatar mmilata avatar rantala avatar romain-geissler-1a avatar sdmaclea avatar unkadoug avatar vtjnash avatar yuyichao avatar zwelch-mgc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libunwind's Issues

glibc: _U and _UL are reserved names

On SmartOS (and probably other Solaris-likes), gcc (v7) throws the following error:

../include/libunwind-common.h:43:41: error: expected identifier or '(' before numeric constant
 # define UNW_PREFIX UNW_PASTE(UNW_PASTE(_U,UNW_TARGET),_)
                                         ^
../include/libunwind-common.h:35:25: note: in definition of macro 'UNW_PASTE2'
 #define UNW_PASTE2(x,y) x##y
                         ^
../include/libunwind-common.h:37:21: note: in expansion of macro 'UNW_PASTE'
 #define UNW_OBJ(fn) UNW_PASTE(UNW_PREFIX, fn)
                     ^~~~~~~~~
../include/libunwind-common.h:36:24: note: in expansion of macro 'UNW_PASTE2'
 #define UNW_PASTE(x,y) UNW_PASTE2(x,y)
                        ^~~~~~~~~~
../include/libunwind-common.h:43:21: note: in expansion of macro 'UNW_PASTE'
 # define UNW_PREFIX UNW_PASTE(UNW_PASTE(_U,UNW_TARGET),_)
                     ^~~~~~~~~
../include/libunwind-common.h:36:24: note: in expansion of macro 'UNW_PASTE2'
 #define UNW_PASTE(x,y) UNW_PASTE2(x,y)
                        ^~~~~~~~~~
../include/libunwind-common.h:43:31: note: in expansion of macro 'UNW_PASTE'
 # define UNW_PREFIX UNW_PASTE(UNW_PASTE(_U,UNW_TARGET),_)
                               ^~~~~~~~~
../include/libunwind-common.h:37:31: note: in expansion of macro 'UNW_PREFIX'
 #define UNW_OBJ(fn) UNW_PASTE(UNW_PREFIX, fn)
                               ^~~~~~~~~~
../include/tdep-x86_64/libunwind_i.h:211:41: note: in expansion of macro 'UNW_OBJ'
 #define tdep_trace                      UNW_OBJ(tdep_trace)
                                         ^~~~~~~
../include/tdep-x86_64/libunwind_i.h:260:12: note: in expansion of macro 'tdep_trace'
 extern int tdep_trace (unw_cursor_t *cursor, void **addresses, int *n);
            ^~~~~~~~~~

According to glibc manual (http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html):

In addition to the names documented in this manual, reserved names include all external identifiers (global functions and variables) that begin with an underscore (‘_’) and all identifiers regardless of use that begin with either two underscores or an underscore followed by a capital letter are reserved names. This is so that the library and header files can define functions, variables, and macros for internal purposes without risk of conflict with names in user programs.

There are two ways to fix this issue:

  1. rename _U and _UL to something else (will also require changes in tests/check-namespace.sh.in file and other places?).
  2. undefine _U explicitly:
    --- a/include/libunwind-common.h.in
    +++ b/include/libunwind-common.h.in
    @@ -23,6 +23,8 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
    
    +#undef _U
    +
     #define UNW_VERSION_MAJOR      @PKG_MAJOR@
     #define UNW_VERSION_MINOR      @PKG_MINOR@
     #define UNW_VERSION_EXTRA      @PKG_EXTRA@

which approach is safe/better? If #1 is non-breaking-ABI, I would go for it (because #2 might have side effects).

libunwind does not reuse opened files

When running a minimal reproduction code, we can see following behaviour with local tracing:

    open("/proc/18711/maps", O_RDONLY)      = 3
    open("/home/cmouse/src/unwind-stack/test", O_RDONLY) = 4
    close(4)                                = 0
    close(3)                                = 0
    #0 backtrace[0x556351635b40]
    open("/proc/18711/maps", O_RDONLY)      = 3
    open("/home/cmouse/src/unwind-stack/test", O_RDONLY) = 4
    close(4)                                = 0
    close(3)                                = 0
    #1 some_other_function[0x556351635d06]
    open("/proc/18711/maps", O_RDONLY)      = 3
    open("/home/cmouse/src/unwind-stack/test", O_RDONLY) = 4
    close(4)                                = 0
    close(3)                                = 0
    #2 some_function[0x556351635d17]
    open("/proc/18711/maps", O_RDONLY)      = 3
    open("/home/cmouse/src/unwind-stack/test", O_RDONLY) = 4
    close(4)                                = 0
    close(3)                                = 0
    #3 main[0x556351635d23]
    open("/proc/18711/maps", O_RDONLY)      = 3
    open("/lib/x86_64-linux-gnu/libc-2.24.so", O_RDONLY) = 4
    close(4)                                = 0
    close(3)                                = 0
    #4 __libc_start_main[0x7fc8d30431f0]
    open("/proc/18711/maps", O_RDONLY)      = 3
    open("/home/cmouse/src/unwind-stack/test", O_RDONLY) = 4
    close(4)                                = 0
    close(3)                                = 0

This shows the maps being opened & closed along with the binary for every symbol with no caching or reuse whatsoever. Perhaps it could at least reuse the last opened file and maps?

Minimal reproduction under #115

run-coredump-unwind fail when libunwind compiled with gcc 8

Hello dear maintainer,

As explained in the title, I have a problem building the lib with gcc 8. The problem occurs when running the test run-coredump-unwind.
In my case, I have no problem on my ubuntu plateform with gcc 5.4.0, binutils 2.26.1, glibc 2.23.
Now trying in a docker container with a more recent version of gcc (gcc 8.2.0, binutils 2.31.1, glibc 2.27) , I have:

root@7497245bf424:/git/libunwind# cat tests/test-suite.log
=============================================
   libunwind 1.3-rc1: tests/test-suite.log
=============================================

# TOTAL: 34
# PASS:  33
# SKIP:  0
# XFAIL: 0
# FAIL:  1
# XPASS: 0
# ERROR: 0

.. contents:: :depth: 2

FAIL: run-coredump-unwind
=========================

Segmentation fault (core dumped)
FAILURE: start IPs incorrect
FAIL run-coredump-unwind (exit status: 255)

I have the exact same issue with libunwind 1.2.1, 1.3-RC1 (even applying the patch #67) and git HEAD.
I also tried with the head of gcc 8.2.1 20180908.

How to reproduce

sudo sysctl -w kernel.core_pattern="core"
docker run -t -i debian:testing /bin/bash
apt-get update && apt-get install build-essential git autotools-dev autoconf libtool
git clone https://github.com/libunwind/libunwind.git
cd libunwind
./autogen.sh
./configure
make
make check

Investigation

Digging further, it seems that libunwind is a not able to step the 4 expected frames leading to an error.

If I run run-coredump-unwind without the -testcase option passed to test-coredump-unwind script, I get this in the working case:

:~/opensource/libunwind/tests$ ./run-coredump-unwind
Segmentation fault (core dumped)
        ip=0x00400890 proc=00400890-004008a1 handler=0x00000000 lsda=0x00000000
lt-test-coredump-unwind: step
lt-test-coredump-unwind: step done:1
        ip=0x004008bd proc=004008b0-004008d2 handler=0x00000000 lsda=0x00000000
lt-test-coredump-unwind: step
lt-test-coredump-unwind: step done:1
        ip=0x004008ca proc=004008b0-004008d2 handler=0x00000000 lsda=0x00000000
lt-test-coredump-unwind: step
lt-test-coredump-unwind: step done:1
        ip=0x004008fc proc=004008e0-00400906 handler=0x00000000 lsda=0x00000000
lt-test-coredump-unwind: step
lt-test-coredump-unwind: step done:1
signal:11 address:0x7f3d6f85fba0 ip:0x7f3d6f2301c6
/home/ubuntu/opensource/libunwind/tests/.libs/lt-test-coredump-unwind[0x4017b8]
/lib/x86_64-linux-gnu/libc.so.6(+0x354b0)[0x7f3d6ee8d4b0]
/home/ubuntu/opensource/libunwind/src/.libs/libunwind-x86_64.so.8(_Ux86_64_dwarf_find_unwind_table+0x146)[0x7f3d6f2301c6]
/home/ubuntu/opensource/libunwind/src/.libs/libunwind-coredump.so.0(_UCD_find_proc_info+0xc9)[0x7f3d6f43fa09]
/home/ubuntu/opensource/libunwind/src/.libs/libunwind-x86_64.so.8(+0x9987)[0x7f3d6f22b987]
/home/ubuntu/opensource/libunwind/src/.libs/libunwind-x86_64.so.8(+0xc1e7)[0x7f3d6f22e1e7]
/home/ubuntu/opensource/libunwind/src/.libs/libunwind-x86_64.so.8(_Ux86_64_get_proc_info+0x11)[0x7f3d6f226561]
/home/ubuntu/opensource/libunwind/tests/.libs/lt-test-coredump-unwind[0x401231]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f3d6ee78830]
/home/ubuntu/opensource/libunwind/tests/.libs/lt-test-coredump-unwind[0x401499]

And in the non-working case:

/git/libunwind/tests# ./run-coredump-unwind
Segmentation fault (core dumped)
        ip=0x56143448d2b0 proc=56143448d2b0-56143448d2b1 handler=0x00000000 lsda=0x00000000
test-coredump-unwind: step
test-coredump-unwind: step done:0
test-coredump-unwind: stepping ended

Hence the following question: why the return code of unw_step is 0 ?

Thanks in advance for your help,
Regards,
Stac

openwrt can not get the right backtrace?

@djwatson

I use libuwind in openwrt like this :
https://github.com/openwrt/openwrt/tree/master/package/libs/libunwind

I run Gtest-trace for test, get this result:

Normal backtrace:
normal trace:

    via backtrace():

    via unw_backtrace():

FAILURE: unw_step() loop and unw_backtrace() depths differ: 0 vs. 0
FAILURE: unw_step() loop and backtrace() depths differ: 0 vs. 0

Backtrace across signal handler:
sighandler: got signal 15, sp=0x7fcb7bd8
normal trace:

    via backtrace():

    via unw_backtrace():

FAILURE: unw_step() loop and unw_backtrace() depths differ: 0 vs. 0
FAILURE: unw_step() loop and backtrace() depths differ: 0 vs. 0

Backtrace across signal handler on alternate stack:
sighandler: got signal 15, sp=0x77cf8ce8
normal trace:

    via backtrace():

    via unw_backtrace():

FAILURE: unw_step() loop and unw_backtrace() depths differ: 0 vs. 0
FAILURE: unw_step() loop and backtrace() depths differ: 0 vs. 0
FAILURE: detected 6 errors

I run Gtest-bt for test, get this result:
Normal backtrace:
explicit backtrace:
0000000000400df8 <main+0x438> (sp=000000007ffee7a0)

    via backtrace():

Backtrace across signal handler:
sighandler: got signal 15, sp=0x7ffee548
explicit backtrace:
0000000000400df8 <main+0x438> (sp=000000007ffee448)

    via backtrace():

Backtrace across signal handler on alternate stack:
sighandler: got signal 15, sp=0x77768ce8
explicit backtrace:
0000000000400df8 <main+0x438> (sp=0000000077768be8)

    via backtrace():

SUCCESS.

I used toolchain:
mipsel-openwrt-linux-uclibc-gcc

how can solve this problem?

使用嵌入式ARM环境下栈空间消耗过大

在开发使用过程中,目前在ARM32位系统下unw_cursor_t是需要4K4Byte=16KB的空间,如果一个系统中有100多个线程在运行,那么每个线程都是需要额外增加这16KB的空间来进行栈回溯操作,100个线程16KB,大家想想这是需要消耗掉多大的栈内存空间,是否可以考虑ARM编译时确定这块栈空间合适的大小,总所周知,ARM芯片经常是运行在内存空间不那么充足的情况下,所以我觉得这个问题还是有必要进行讨论的,不知道大家中文能看懂吗*_*

test-ptrace fails on s390x

I've tested the libunwind master branch on Fedora Rawhide (to-be F-31 with kernel 5.1rc3, gcc-9.0.1, glibc-2.29.9000, ...) and the ptrace test fails with following (libunwind has been configured with --enable-setjmp=no)

=============================================
   libunwind 1.4-rc1: tests/test-suite.log
=============================================

# TOTAL: 33
# PASS:  32
# SKIP:  0
# XFAIL: 0
# FAIL:  1
# XPASS: 0
# ERROR: 0

.. contents:: :depth: 2

FAIL: test-ptrace
=================

Automated test (self,/bin/ls,/usr,(null))
FAILURE: unw_step() returned -8 for ip=3ff8d418826 (start ip=3ff8d41a4c8)
unwind failed with ret=-8
FAILURE: unw_step() returned -8 for ip=3ff8d41130e (start ip=3ff8d41a250)
unwind failed with ret=-8
FAILURE: unw_step() returned -8 for ip=3ff8d411388 (start ip=3ff8d41a4c8)
unwind failed with ret=-8
FAILURE: unw_step() returned -8 for ip=3ff8d418826 (start ip=3ff8d41a4c8)
unwind failed with ret=-8
FAILURE: unw_step() returned -8 for ip=3ff8d418826 (start ip=3ff8d41a4c8)
unwind failed with ret=-8
FAILURE: detected 10 errors
FAIL test-ptrace (exit status: 255)

cc: @mundaym

How to build the libunwind for QNX aarch64?

I need to build libunwind for QNX ARM-64. I saw the post from Matt Fischer in https://lists.nongnu.org/archive/html/libunwind-devel/2013-04/msg00006.html.

Which parameter options shall I pass to the ./configure?
If I execute ./configure --host=aarch64-unknown-nto-qnx7.0.0, it works. But I get such error messages below during the make build:

...
libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I../include -I../include -I../include/tdep-aarch64 -I. -D_GNU_SOURCE -DNDEBUG -g -O2 -fexceptions -Wall -Wsign-compare -MT aarch64/is_fpreg.lo -MD -MP -MF aarch64/.deps/is_fpreg.Tpo -c aarch64/is_fpreg.c  -fPIC -shared -DPIC -o aarch64/.libs/is_fpreg.o
aarch64/is_fpreg.c: In function ‘_Ux86_64_is_fpreg’:
aarch64/is_fpreg.c:31:21: error: ‘UNW_AARCH64_V0’ undeclared (first use in this function)
   return (regnum >= UNW_AARCH64_V0 && regnum <= UNW_AARCH64_V31);
                     ^
aarch64/is_fpreg.c:31:21: note: each undeclared identifier is reported only once for each function it appears in
aarch64/is_fpreg.c:31:49: error: ‘UNW_AARCH64_V31’ undeclared (first use in this function)
   return (regnum >= UNW_AARCH64_V0 && regnum <= UNW_AARCH64_V31);
                                                 ^
aarch64/is_fpreg.c:32:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^
Makefile:3493: recipe for target 'aarch64/is_fpreg.lo' failed
make[2]: *** [aarch64/is_fpreg.lo] Error 1

Symbols are not available after chroot

OS: Debian 9.0,
libunwind-1.1-4.1

When trying to create backtrace inside chrooted process, libunwind fails to find symbols.

Simple reproduction:

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <libunwind.h>
#include <assert.h>

int backtrace()
{
	char proc_name[256];
	int ret;
	unsigned int fp = 0;
	unw_cursor_t c;
	unw_context_t ctx;
	unw_proc_info_t pip;

	if ((ret = unw_getcontext(&ctx)) != 0) {
		printf("unw_getcontext() failed: %d", ret);
		return -1;
	}
	if ((ret = unw_init_local(&c, &ctx)) != 0) {
		printf("unw_init_local() failed: %d", ret);
		return -1;
	}

	do {
		printf("#%d ", fp);
		if ((ret = unw_get_proc_info(&c, &pip)) != 0) {
			printf("[unw_get_proc_info_failed(): %d]", ret);
		} else if (pip.start_ip == 0 || pip.end_ip == 0) {
			printf("[no start/end information]");
		} else if ((ret = unw_get_proc_name(&c, proc_name, sizeof(proc_name), 0)) != 0 &&
			   ret != UNW_ENOMEM) {
			printf("[unw_get_proc_name() failed: %d]", ret);
		} else {
			proc_name[255] = '\0';
			printf("%s", proc_name);
			printf("[0x%08lx]", pip.start_ip);
		}
		printf("\n");
		fp++;
	} while ((ret = unw_step(&c)) > 0);

	return ret == 0 ? 0 : -1;
}

static void some_other_function(void)
{
	backtrace();
}

static void some_function(void)
{
	some_other_function();
}

int main(void)
{
/* must be existing directory owned by root */
	assert(chroot("/empty") == 0);
	assert(setgid(99) == 0);
	assert(setuid(99) == 0);
	some_function();
	return 0;
}

Expected result:

#0 backtrace[0x55f817c78a50]
#1 some_other_function[0x55f817c78c1c]
#2 some_function[0x55f817c78c2d]
#3 main[0x55f817c78c39]
#4 __libc_start_main[0x7fd94c09a1f0]
#5 _start[0x55f817c78920]
#6 [no start/end information]

Actual result:

#0 [unw_get_proc_name() failed: -1]
#1 [unw_get_proc_name() failed: -1]
#2 [unw_get_proc_name() failed: -1]
#3 [unw_get_proc_name() failed: -1]
#4 [unw_get_proc_name() failed: -1]
#5 [unw_get_proc_name() failed: -1]
#6 [no start/end information]

Tests fail on Alpine Linux

I built libunwind master on Alpine Linux 3.7 x86-64 in Docker using

./autogen.sh
./configure
make

I then ran the test suite using make check, which produced the following summary:

PASS: test-proc-info
PASS: test-static-link
PASS: test-strerror
PASS: Gtest-bt
PASS: Ltest-bt
PASS: Gtest-exc
PASS: Ltest-exc
PASS: Gtest-init
PASS: Ltest-init
PASS: Gtest-concurrent
PASS: Ltest-concurrent
../config/test-driver: line 107:  1880 Segmentation fault      (core dumped) "$@" > $log_file 2>&1
FAIL: Gtest-resume-sig
../config/test-driver: line 107:  1904 Segmentation fault      (core dumped) "$@" > $log_file 2>&1
FAIL: Ltest-resume-sig
../config/test-driver: line 107:  1928 Segmentation fault      (core dumped) "$@" > $log_file 2>&1
FAIL: Gtest-resume-sig-rt
../config/test-driver: line 107:  1952 Segmentation fault      (core dumped) "$@" > $log_file 2>&1
FAIL: Ltest-resume-sig-rt
PASS: Gtest-trace
PASS: Ltest-trace
FAIL: Ltest-init-local-signal
PASS: Ltest-mem-validate
FAIL: test-async-sig
PASS: test-flush-cache
PASS: test-init-remote
PASS: test-mem
PASS: test-reg-state
PASS: Ltest-varargs
PASS: Ltest-nomalloc
PASS: Ltest-nocalloc
PASS: Lrs-race
PASS: test-ptrace
../config/test-driver: line 107:  2320 Aborted                 (core dumped) "$@" > $log_file 2>&1
FAIL: test-setjmp
FAIL: run-check-namespace
PASS: run-ptrace-mapper
PASS: run-ptrace-misc
FAIL: run-coredump-unwind
============================================================================
Testsuite summary for libunwind 1.3-rc1
============================================================================
# TOTAL: 34
# PASS:  25
# SKIP:  0
# XFAIL: 0
# FAIL:  9
# XPASS: 0
# ERROR: 0

The full log of configuration, building, and running the tests, as well as the tests/test-suite.log file are available in https://gist.github.com/ararslan/ca1efacb3f06426d1b4c1a399bd35735.

unwind-setjmp not work?

I want to try the unwind-setjmp in Debain 8, GCC 4.9.2
I add a debug printf in the function setjmp() in src/setjmp.c, and rebuild libunwind.
When I run my test program, I didn't see the debug print in consule. It seems the unwind-setjmp is not working. It is still the setjmp in libc.
And I check the result of cmdline: readelf -s libunwind-setjmp.so, no setjmp symbol was found.
here is my test program:

jmp_buf env; 
int main() 
{
    if (setjmp(env))
        return 1;
    return 0;
}

compile:
gcc -o test_setjmp test_setjmp.c -I ~/mylib/include -L ~/mylib/lib/ -lunwind-setjmp

did I make any mistake?

ABI difference when compiling against glibc 2.28 vs 2.27

Hello,
In freedesktop-sdk we maintain common software base for use by flatpak apps. We're trying to keep various elements like glibc or libunwind synced with latest upstream releases unless it would break ABI backward compatibility.

When trying update glibc from 2.27 to 2.28 then rebuilding libunwind against the new version there is following ABI change detected by libabigail:

┌───────────────────────────────────────────────────┐
│ ABI Break: libunwind-x86_64.so.8:libunwind-x86_64 │
└───────────────────────────────────────────────────┘

Functions changes summary: 0 Removed, 1 Changed, 0 Added function
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable

1 function with some indirect sub-type change:

  [C]'function int _Ux86_64_init_local(unw_cursor_t*, ucontext_t*)' at Ginit_local.c:42:1 has some indirect sub-type changes:
    parameter 2 of type 'ucontext_t*' has sub-type changes:
      in pointed to type 'struct ucontext_t' at ucontext.h:142:1:
        type size changed from 7488 to 7744 (in bits)
        1 data member insertion:
          'long long unsigned int ucontext_t::__ssp[4]', at offset 7488 (in bits) at ucontext.h:150:1
        no data member change (1 filtered);

┌─────────────────────────────────────┐
│ ABI Break: libunwind.so.8:libunwind │
└─────────────────────────────────────┘

Functions changes summary: 0 Removed, 1 Changed, 0 Added function
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable

1 function with some indirect sub-type change:

  [C]'function int _ULx86_64_init_local(unw_cursor_t*, ucontext_t*)' at Ginit_local.c:42:1 has some indirect sub-type changes:
    parameter 2 of type 'ucontext_t*' has sub-type changes:
      in pointed to type 'struct ucontext_t' at ucontext.h:142:1:
        type size changed from 7488 to 7744 (in bits)
        1 data member insertion:
          'long long unsigned int ucontext_t::__ssp[4]', at offset 7488 (in bits) at ucontext.h:150:1
        no data member change (1 filtered);

I suppose it's caused by this glibc commit related to new Intel CET feature.

As libunwind developers, do you think this change could negatively affect backward ABI compatibility in practice?

Thanks for help.

`unw_init_remote` returns `UNW_EBADREG` on Aarch64

Hi all, I am trying to use unw_init_remote on a Aarch64 single board computer. However, it keeps giving me the error; UNW_EBADREG .

I ran a uprobe trace on that function and on UPT_access_reg as I am using libunwind-ptrace. I do not understand why UNW_AARCH64_PC would be inaccessible. Could someone help me please? What might cause that problem?

uprobe_UPT_access_reg_shows_it_returns_UNW_EBADREG

The code I used is below. It works fine on x86-64, but not on Aarch64.

#include <stdarg.h>
#include <sys/ptrace.h>                                                                                                                                                                                      
#include <stdio.h>                                                                                                                                                                                           
#include <stdlib.h>                                                                                                                                                                                          
                                                                                                                                                                                                             
#include <libunwind-ptrace.h>
                                                  
static const char* UNW_ER[] = {                          
        "UNW_ESUCCESS",     /* no error */
        "UNW_EUNSPEC",      /* unspecified (general) error */
        "UNW_ENOMEM",       /* out of memory */
        "UNW_EBADREG",      /* bad register number */
        "UNW_EREADONLYREG", /* attempt to write read-only register */
        "UNW_ESTOPUNWIND",  /* stop unwinding */
        "UNW_EINVALIDIP",   /* invalid IP */
        "UNW_EBADFRAME",    /* bad frame */
        "UNW_EINVAL",       /* unsupported operation or bad value */
        "UNW_EBADVERSION",  /* unwind info has unsupported version */
        "UNW_ENOINFO"       /* no unwind info found */
};

void die(const char *fmt, ...)
{
        va_list ap;

        va_start(ap, fmt);
        vfprintf(stderr, fmt, ap);
        va_end(ap);
        exit(1);
}

int main(int argc, char **argv)
{
        if (argc != 2)
                die("USAGE: unwind-pid <pid>\n");

        unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, 0);

        pid_t pid = atoi(argv[1]);
        if (ptrace(PTRACE_ATTACH, pid, 0, 0) != 0)
                die("ERROR: cannot attach to %d\n", pid);

        void *context = _UPT_create(pid);
        unw_cursor_t cursor;
        int err = unw_init_remote(&cursor, as, context);
        if (err != 0)
                die("ERROR: cannot initialize cursor for remote unwinding. Errno: %s\n", UNW_ER[-err]);

        do {
                unw_word_t offset, pc;
                char sym[4096];
                if (unw_get_reg(&cursor, UNW_REG_IP, &pc))
                        die("ERROR: cannot read program counter\n");

                printf("0x%lx: ", pc);

                if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0)
                        printf("(%s+0x%lx)\n", sym, offset);
                else
                        printf("-- no symbol name found\n");
        } while (unw_step(&cursor) > 0);

        _UPT_destroy(context);
        (void) ptrace(PTRACE_DETACH, pid, 0, 0);

        return 0;
}

Old libtools causes builds with gcc 8 and -flto to fail

Hi,

I have been investigating an issue with gcc 8, -flto, and the test run-check-namespace.

Starting from gcc 8, gcc supports what we call "early debug LTO", ie LTO builds now have better debug symbol supports. This is implemented in gcc by adding some special symbols into .o files built with -flto -g, of the form filename.c.somehash.

The current old libtool included in libunwind does build .o files with "-g -flto" (if it is present in the CFLAGS), but even if we also have "-g -flto" in LDFLAGS, then "-g" is filtered out. It result in two things:

  • the generate binaries don't have proper debug symbols
  • the generated temporary lto debug symbols from gcc aren't merged, nor deleted from the final libunwind.so files. Thus it is polluted with fake symbols that "nm -g" shows.

When running tests, run-check-namespace uses "nm -g", and ends up with errors since there are extra symbols.

This patch in libunwind's libtool "fixes" the problem:

--- config/ltmain.sh
+++ config/ltmain.sh
@@ -5853,7 +5853,7 @@ func_mode_link ()
       # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
       -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
-      -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+      -O*|-flto*|-fwhopr*|-fuse-linker-plugin|-g*)
         func_quote_for_eval "$arg"
        arg="$func_quote_for_eval_result"
         func_append compile_command " $arg"

However, this addition is already in recent libtools. You should migrate to newer libtools to definitely fix this issue.

Cheers,
Romain

test build failures: Lperf-simple.o: cannot make copy relocation for protected symbol '_ULx86_64_local_addr_space', defined in ../src/.libs/libunwind.so

I just tried to build current git master and get the following build errors in the tests:

make[1]: Entering directory '/ssd/milian/projects/build/libunwind/tests'
/bin/sh ../libtool  --tag=CC   --mode=link gcc  -g -O2 -fexceptions -Wall -Wsign-compare   -o Gperf-simple Gperf-simple.o ../src/libunwind-x86_64.la ../src/libunwind.la 
/bin/sh ../libtool  --tag=CC   --mode=link gcc  -g -O2 -fexceptions -Wall -Wsign-compare   -o Lperf-simple Lperf-simple.o ../src/libunwind.la 
/bin/sh ../libtool  --tag=CC   --mode=link gcc  -g -O2 -fexceptions -Wall -Wsign-compare   -o Gperf-trace Gperf-trace.o ../src/libunwind-x86_64.la ../src/libunwind.la 
/bin/sh ../libtool  --tag=CC   --mode=link gcc  -g -O2 -fexceptions -Wall -Wsign-compare   -o Lperf-trace Lperf-trace.o ../src/libunwind.la 
/bin/sh ../libtool  --tag=CC   --mode=link gcc  -g -O2 -fexceptions -Wall -Wsign-compare   -o test-coredump-unwind test-coredump-unwind.o ../src/libunwind-coredump.la ../src/libunwind-x86_64.la  
libtool: link: gcc -g -O2 -fexceptions -Wall -Wsign-compare -o .libs/Lperf-simple Lperf-simple.o  ../src/.libs/libunwind.so -lc -lgcc_s -llzma -Wl,-rpath -Wl,/home/milian/projects/compiled/other/lib
libtool: link: gcc -g -O2 -fexceptions -Wall -Wsign-compare -o .libs/Gperf-trace Gperf-trace.o  ../src/.libs/libunwind-x86_64.so /home/milian/projects/build/libunwind/src/.libs/libunwind.so ../src/.libs/libunwind.so -lc -lgcc_s -llzma -Wl,-rpath -Wl,/home/milian/projects/compiled/other/lib
libtool: link: gcc -g -O2 -fexceptions -Wall -Wsign-compare -o .libs/Lperf-trace Lperf-trace.o  ../src/.libs/libunwind.so -lc -lgcc_s -llzma -Wl,-rpath -Wl,/home/milian/projects/compiled/other/lib
libtool: link: gcc -g -O2 -fexceptions -Wall -Wsign-compare -o .libs/Gperf-simple Gperf-simple.o  ../src/.libs/libunwind-x86_64.so /home/milian/projects/build/libunwind/src/.libs/libunwind.so ../src/.libs/libunwind.so -lc -lgcc_s -llzma -Wl,-rpath -Wl,/home/milian/projects/compiled/other/lib
/home/milian/.bin/ld: error: Lperf-simple.o: cannot make copy relocation for protected symbol '_ULx86_64_local_addr_space', defined in ../src/.libs/libunwind.so
collect2: error: ld returned 1 exit status
make[1]: *** [Makefile:1125: Lperf-simple] Error 1
make[1]: *** Waiting for unfinished jobs....
libtool: link: gcc -g -O2 -fexceptions -Wall -Wsign-compare -o .libs/test-coredump-unwind test-coredump-unwind.o  ../src/.libs/libunwind-coredump.so ../src/.libs/libunwind-x86_64.so /home/milian/projects/build/libunwind/src/.libs/libunwind.so -lgcc_s -llzma -lc -Wl,-rpath -Wl,/home/milian/projects/compiled/other/lib
/home/milian/.bin/ld: error: Gperf-trace.o: cannot make copy relocation for protected symbol '_Ux86_64_local_addr_space', defined in ../src/.libs/libunwind-x86_64.so
collect2: error: ld returned 1 exit status
make[1]: *** [Makefile:1073: Gperf-trace] Error 1
/home/milian/.bin/ld: error: Lperf-trace.o: cannot make copy relocation for protected symbol '_ULx86_64_local_addr_space', defined in ../src/.libs/libunwind.so
collect2: error: ld returned 1 exit status
make[1]: *** [Makefile:1129: Lperf-trace] Error 1
/home/milian/.bin/ld: error: Gperf-simple.o: cannot make copy relocation for protected symbol '_Ux86_64_local_addr_space', defined in ../src/.libs/libunwind-x86_64.so
collect2: error: ld returned 1 exit status
make[1]: *** [Makefile:1069: Gperf-simple] Error 1
/home/milian/.bin/ld: error: test-coredump-unwind.o: cannot make copy relocation for protected symbol '_UCD_accessors', defined in ../src/.libs/libunwind-coredump.so
collect2: error: ld returned 1 exit status
make[1]: *** [Makefile:1225: test-coredump-unwind] Error 1

Any idea what that might trigger? I'm on ArchLinux with gcc 7.2.0 and use gold 1.14 from binutils 2.29.1 for linking.

Regression in static link test when building with Clang

The test-static-link check is now failing on master when building with Clang, but it passes on v1.3-rc1.

I can reproduce this on both FreeBSD and Linux. On FreeBSD Clang is the default compiler but for some reason libunwind picks up GCC if it's installed, so in both cases we need to set CC/CXX manually. Steps to reproduce:

export CC=clang CXX=clang++
./autogen.sh
./configure
make # gmake on FreeBSD
make check

The error is:

/home/alex/libunwind/src/dwarf/Gfind_proc_info-lsb.c:813: multiple definition of `dwarf_search_unwind_table_int'; ../src/.libs/libunwind-x86_64.a(Gfind_proc_info-lsb.o):/home/alex/libunwind/src/dwarf/Gfind_proc_info-lsb.c:813: first defined here

Note that this does not happen with GCC on either FreeBSD or Linux.

multillib test failures

export CC="gcc -m32"
export CXX="g++ -m32"

./configure
--build=i686-pc-linux-gnu
--host=i686-pc-linux-gnu
--prefix=/usr
--libdir=/usr/lib32
--disable-documentation # man pages are already included in libunwind package
make

-m32 multilib builds, but doesn't pass tests. At first glance, it appears ptrace and coredump functions are broken.

Segfault when first stepping a cursor that has moved since initialization

I'm using libunwind 1.2.1 on x86_64 Linux.

#include <stdio.h>
#include <libunwind.h>

unw_cursor_t init_cursor(unw_context_t *uc) {
	unw_cursor_t cursor;
	unw_init_local(&cursor, uc);
	return cursor;
}

int main() {
	unw_cursor_t cursor; unw_context_t uc;
	unw_word_t ip, sp;

	unw_getcontext(&uc);
	cursor = init_cursor(&uc);
	while (unw_step(&cursor) > 0) {
		unw_get_reg(&cursor, UNW_REG_IP, &ip);
		unw_get_reg(&cursor, UNW_REG_SP, &sp);
		printf ("ip = %lx, sp = %lx\n", (long) ip, (long) sp);
	}
}
(gdb) run
Starting program: /work/unwind/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
access_reg (as=<optimized out>, reg=6, val=0x7fffffffda88, write=0,
    arg=<optimized out>) at x86_64/Ginit.c:201
201	      *val = *(unw_word_t *) addr;
(gdb) bt
#0  access_reg (as=<optimized out>, reg=6, val=0x7fffffffda88, write=0,
    arg=<optimized out>) at x86_64/Ginit.c:201
#1  0x00007ffff7996bcf in dwarf_get (c=0x7fffffffe7f0, c=0x7fffffffe7f0,
    val=0x7fffffffda88, loc=...) at ../include/tdep-x86_64/libunwind_i.h:164
#2  _Ux86_64_access_reg (c=c@entry=0x7fffffffe7f0, reg=<optimized out>,
    valp=valp@entry=0x7fffffffda88, write=write@entry=0) at x86_64/Gregs.c:130
#3  0x00007ffff79958bc in _Ux86_64_get_reg (
    cursor=cursor@entry=0x7fffffffe7f0, regnum=<optimized out>,
    valp=valp@entry=0x7fffffffda88) at mi/Gget_reg.c:40
#4  0x00007ffff799e4c9 in apply_reg_state (c=c@entry=0x7fffffffe7f0,
    rs=rs@entry=0x7fffffffdb70) at dwarf/Gparser.c:759
#5  0x00007ffff79a0d53 in _Ux86_64_dwarf_find_save_locs (
    c=c@entry=0x7fffffffe7f0) at dwarf/Gparser.c:907
#6  0x00007ffff79a220e in _Ux86_64_dwarf_step (c=c@entry=0x7fffffffe7f0)
    at dwarf/Gstep.c:34
#7  0x00007ffff7997479 in _Ux86_64_step (cursor=0x7fffffffe7f0)
    at x86_64/Gstep.c:71
#8  0x00005555555549b5 in main () at foo.c:16
(gdb) p addr
$1 = (unw_word_t *) 0x78

This only seems to be an issue with the first step. If I step once in init_cursor before returning it, future steps work fine. Is this intended or a bug? It doesn't seem to be documented but I could have missed it.

validate doesn't check for PROT_NONE

Neither of the existing validate functions, mincore or msync, check if the memory is actually readable or writable, i.e. PROT_NONE.

#7 is an attempt to fix, using a test write to a pipe. Someone on the list ran in to this on x86 as well as x86_64. Also, for a pipefd, needs to be fork-safe.

libunwind 1.2.1 UNW_VERSION_MINOR is not an integer

Configuring libunwind 1.2.1 after autoreconf generates this in include/libunwind-common.h:

#define UNW_VERSION_MAJOR	1
#define UNW_VERSION_MINOR	2.1
#define UNW_VERSION_EXTRA	

Since UNW_VERSION_MINOR is not an integer, it is not comparable in macros.

This happens because configure.ac contains

define(pkg_major, 1)
define(pkg_minor, 2.1)
define(pkg_extra, )

This breaks compilation of julia 0.5.1:

src/julia_internal.h:496:35: error: floating constant in preprocessor expression
        (UNW_VERSION_MAJOR == 1 && UNW_VERSION_MINOR > 1))
                                   ^

Discovered in NixOS/nixpkgs#26891 (comment)

--enable-shared --disable-static installs broken symlink

I recently packaged libunwind for the conan package manager. In the course of that I noticed a small bug in libunwind's build system:

If I configure with ./configure --prefix= --enable-shared --disable-static, a broken symlink lib/libunwind-generic.a is installed that points to a missing architecture-specific version of that library (e.g. lib/libunwind-x86_64.a). I suppose that not installing that library is the intended behavior with these configuration settings, so the symlink should not be there in the first place.

I was able to reproduce this bug on several Linux systems, native on x86_64 as well as cross-compiling to i686. I tried both, libunwind versions 1.2 and 1.2.1 from http://download.savannah.nongnu.org/releases/libunwind/ as well as the current version here on GitHub (commit 2934cf4). For the latter I used libtool version 2.4.6 from the Fedora 25 package repository. All tests showed the same behavior.

Configure step throws: error: Unknown ELF target: s390x

Trying to build the libunwind package from its source under the target architecture s390x (IBM system z) in order to full-fill a prerequisite for Julia language installation. The ./configure step throws the following messages:

checking for sys/ptrace.h... (cached) yes
checking if we should build libunwind-ptrace... yes
checking if we should build libunwind-setjmp... yes
checking for build architecture... s390x
checking for host architecture... s390x
checking for target architecture... s390x
checking for target operating system... linux-gnu
checking for ELF helper width... configure: error: Unknown ELF target: s390x

Is it possible to add a support for this architecture to the libunwind, in a similar way as previously done for ppc64 machines?

Segfault on aarch64 with clang

Hello,
I am using libunwind on arm64 with clang and the musl-libc.
The issue is also reproducible with the glibc.
The resulting program built with libunwind segfaults.
It has been tested with clang versions 5.0.1 and 6.0.0-rc3 and libunwind versions v1.3-rc1 and 7d6cc66.

This script reproduces the issue:

#!/bin/sh

clang --version
# clang version 5.0.1 (tags/RELEASE_501/final)
# Target: aarch64-unknown-linux-gnu
# Thread model: posix
# InstalledDir: /usr/bin

if false ; then
  export PATH=/opt/llvm/bin:/usr/bin
  clang --version
  # clang version 6.0.0 (tags/RELEASE_600/rc3)
  # Target: aarch64-unknown-linux-gnu
  # Thread model: posix
  # InstalledDir: /opt/llvm/bin
fi

git clone git://git.sv.gnu.org/libunwind.git

cd libunwind
CC=clang ./autogen.sh \
  --enable-static          \
  --disable-shared         \
  --disable-documentation  \
  --disable-tests          \
  --disable-coredump       \
  --disable-ptrace         \
  --disable-setjmp         \
  --disable-debug          \
  --disable-cxx-exceptions \
  --disable-msabi-support  \
  --disable-minidebuginfo
make

cat << EOF > uw.c
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <stdio.h>

void show_backtrace(int x, int y) {
  unw_cursor_t cursor; unw_context_t uc;
  unw_word_t ip, sp;

  unw_getcontext(&uc);
  unw_init_local(&cursor, &uc);
  while (unw_step(&cursor) > 0) {
    unw_get_reg(&cursor, UNW_REG_IP, &ip);
    unw_get_reg(&cursor, UNW_REG_SP, &sp);
    printf ("ip = %lx, sp = %lx\n", (long) ip, (long) sp);
  }
}

int main() {
  show_backtrace(2, 3);
  return(0);
}
EOF

clang -Iinclude -O0 -g -c uw.c -o uw.o
clang uw.o src/.libs/libunwind.a -o uw
./uw
# ip = 3, sp = ffffd37c2bf0
# Segmentation fault

Regards,
  Vicenç.

'make perf' target fails on x86-64 Linux

$ make perf
########## Basic performance of generic libunwind:
unw_getcontext : cold avg=   38.147 nsec, warm avg=   28.610 nsec
unw_init_local : cold avg=   71.526 nsec, warm avg=   19.073 nsec
Unwound only 6 levels, expected at least 100 levels
Makefile:2172: recipe for target 'perf' failed
make: *** [perf] Error 255

Cross-compiling static archives for arm-linux-gnueabihf

Goal

I want to cross-compile static archives that can perform local unwinding on arm-linux-gnueabihf (and many other platforms, but one thing at a time). I do not need remote unwinding.

System

Output of uname -a:

Linux karl-VirtualBox 4.15.0-36-generic #39~16.04.1-Ubuntu SMP Tue Sep 25 08:59:23 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

What I did

Commands:

git clone https://github.com/libunwind/libunwind
cd libunwind
./autogen.sh
./configure --enable-shared=no --host=arm-linux-gnu-eabihf
make

Output (last 11 out of 1168 lines):

/bin/bash ../libtool  --tag=CC   --mode=link arm-linux-gnueabihf-gcc  -g -O2 -fexceptions -Wall -Wsign-compare   -o Gperf-trace Gperf-trace.o ../src/libunwind-arm.la ../src/libunwind.la
libtool: link: arm-linux-gnueabihf-gcc -g -O2 -fexceptions -Wall -Wsign-compare -o Gperf-trace Gperf-trace.o  ../src/.libs/libunwind-arm.a /home/karl/s/scratch/libunwind/src/.libs/libunwind.a ../src/.libs/libunwind.a -lc -lgcc_s
/home/karl/s/scratch/libunwind/src/.libs/libunwind.a(Lex_tables.o): In function `arm_search_unwind_table':
/home/karl/s/scratch/libunwind/src/arm/Gex_tables.c:388: multiple definition of `arm_search_unwind_table'
../src/.libs/libunwind-arm.a(Gex_tables.o):/home/karl/s/scratch/libunwind/src/arm/Gex_tables.c:388: first defined here
collect2: error: ld returned 1 exit status
Makefile:1073: recipe for target 'Gperf-trace' failed
make[1]: *** [Gperf-trace] Error 1
make[1]: Leaving directory '/home/karl/s/scratch/libunwind/tests'
Makefile:603: recipe for target 'all-recursive' failed
make: *** [all-recursive] Error 1

Troubleshooting

Looks like a test is failing to be built. I notice that arm/Lex_tables.c conditionally includes Gex_tables.c. The multiple definition error implies that the condition is true.

I notice that the Travis build is trying out different --target values, and from the job logs, --host is x86_64 and I see no indication that it varies. That is, the CI builds are building x86 libraries that can do remote unwinding on various targets. I was surprised to see that the --target flag was being used, as I didn't consider libunwind a "compiler tool".

I tried adding --target=arm-linux-gnu-eabihf; the result was the same.

Perhaps it is significant that README.md does not show how to build libunwind for ARM. Nevertheless it says "Linux/ARM: Works well." I guess remote only?

Build failing while cross compiling for "arm-linux-android"

I want to cross compile for host "arm-linux-android" on my linux_x86-64 machine.
As per instructions in "INSTALL" file generated after running autogen.sh and config.sub, I did
./configure --host="arm-linux-android"

Configure ran successfully but when I did 'make', build failed with these errors: https://pastebin.ca/3833752

Looking at the errors, it can't seem to find the declared variables for ARM registers like UNW_ARM_S0, UNW_ARM_F0 etc. They are declared in libunwind-arm.h header.

The file throwing the error "arm/is_fpreg.c" does not import "libunwind-arm.h", so I tried to add this header in the include but it didn't work out.

I looked at the Makefile generated after configure, I could not find any abnormalities regarding build or host platform. It appears to detect correct files and system types.
Here's the part which I think can be relevant.

build_triplet = x86_64-pc-linux-gnu
host_triplet = arm-unknown-linux-android
target_triplet = arm-unknown-linux-android
am__append_1 = include/libunwind-ptrace.h
am__append_2 = include/libunwind-coredump.h
#am__append_3 = include/libunwind-aarch64.h
am__append_4 = include/libunwind-arm.h
#am__append_5 = include/libunwind-ia64.h
#am__append_6 = include/libunwind-hppa.h
#am__append_7 = include/libunwind-mips.h
#am__append_8 = include/libunwind-tilegx.h
#am__append_9 = include/libunwind-x86.h
#am__append_10 = include/libunwind-x86_64.h
#am__append_11 = include/libunwind-ppc32.h
#am__append_12 = include/libunwind-ppc64.h
#am__append_13 = include/libunwind-sh.h
am__append_14 = include/libunwind.h include/unwind.h
am__append_15 = tests
#am__append_16 = doc

Let me know if more information is required or if I missed something while building. I'd be happy to fix this.
I'm able to successfully build with default values i.e ./configure without any parameters. It correctly detects my build and host triplet as "x86_64-pc-linux-gnu".

dl_iterate_phdr not async signal safe

The implementation of dl_iterate_phdr in glibc both takes locks, and allocates memory. People hit this sporadically in production.

Barring a fix in glibc, the best fix is probably an optionally linked library that will override dlopen, dlclose, and dl_iterate_phdr with a lock-free and non-mallocing cache.

x86 sigreturn unimplemented for some libcs

with Buildroot we have some compile issues when using uClibc-ng or
musl toolchains. The reason is the x86 specific code is using
deprecated sigreturn and setcontext functions.

The best solution would be if the code would use a direct
syscall to rt_sigreturn as the x86_64 code does:
http://git.savannah.gnu.org/gitweb/?p=libunwind.git;a=blob;f=src/x86_64/Gos-linux.c;h=6f70d3ffdb1e514a567d0c2146c852765bda953d;hb=
+HEAD#l148

I think sigreturn() is a noop in GNU C Library for x86 and x86_64.

Memory leak and high CPU using unw_step in libunwind-1.1-3

Build server OS: RHEL6.8
Deploy server OS: RHEL6.8
libunwind version: libunwind-1.1-3.el6.i686.rpm

The Application is 32bit, C++11, compiled with GCC7 and deployed on 64bit RHEL (v6.8). The libunwind library is being invoked by the Application on allocation and deallocation of memory within the Application to unwind the call stack, store details and use later for memory leak analysis.

The integration of libunwind into the Application code is as described in your documentation https://www.nongnu.org/libunwind/man/libunwind(3).html;

while (unw_step(&cursor) > 0) { }

To test the Application with libunwind, some light load was run through the Application.

Immediately it was obvious that there was a significant memory leak and CPU consumption for the Application was very high.

To narrow down the issue, I removed reading of registers from the while loop. The while loop is empty and contains no logic. The leak was still occurring.

I decided to put bounds on the while loop iterating only a certain number of times. I tested with 1 iteration, 2 iterations up to 5 iterations.

With 1 iteration of the while loop (one call to unw_step) the memory leak is not really visible (maybe very slight).
With 5 iterations of the while loop (five calls to unw_step) the memory leak is very noticeable and leaking quickly.

Note that with the while loop commented out (no call to unw_step()), the memory and CPU are stable.

Have you any idea of what the issue could be? Is it a known issue?

Second thing. I pulled down the latest version of libunwind source code (1.3.1) and tried to compiled for x86 so I could try this to see if the issue was resolved.

I am building using;
./configure --target=i686-linux
make install

A couple of things, the *.so files that are built do not match up with the *.so that are installed by the libunwind-1.1-3.el6.i686.rpm.

v1.1-3 x86 installed libraries;
image

v1.3.1 x86 build outputted libraries;
image

The libunwind.so.8.0.1 and libunwind-coredump.so.0.0.0 are not generated in the i686 build at all.

If I build with x86_64 then these libraries are generated along with a lot of other libraries, likely related to the libunwind-devel package.

Any help would be appreciated.

Eoghan

Release schedule

Is a full v1.3.0 release planned for the near future? The 1.3 release candidate was tagged over a year ago, in November of 2017.

Opt out of creating a weak alias for backtrace

libunwind creates a weak alias for backtrace unconditionally. On our application we write libc's backtrace and our own (previously using the _Unwind functions and now libunwind) so we have two pieces of info and to make sure our implementation doesn't have any bugs.

When calling libunwind functions from a signal handler when an invalid function dereference has happened (null pointer), libunwind crashes in _ULarm_step. Because of the alias the crash is happening when we call backtrace_symbols_fd, voiding our intent of having the system's backtrace written to disk before calling our own.

In the same way that we can configure without C++ exceptions --disable-cxx-exceptions(so the _Unwind functions are not aliased), I think the same should happen with backtrace

unw_init_local_ex

commit 14c48b3
added unw_init_local_signal.

This should probably be generalized to just an unw_init_local that takes a flag, to future proof. Also, validate could be a flag as well.

Re-enable per-thread dwarf cache

Has been broken for a long time, currently doesn't use TLS nor locks, and just isn't thread safe.

#8 is an attempt to fix.

One complication here is that TLS, at least in the glibc implementation, allocates memory and sometimes takes locks, making it not thread safe. For some users this might not matter, but can't be the default.

unw_get_proc_info gnu_debuglink issue

On at least one of my machines, 54a9700 broke unw_get_proc_info. Haven't had a chance to dive in, but suspecting that the actual debuglink file is missing, so we're not getting debug info.

unw_get_proc_name can call an AS-unsafe function

The documentation claims the following:

unw_get_proc_name() is thread-safe. If cursor cp is in the local address-space, this routine is also safe to use from a signal handler.

However, invoking this function on an x86_64 Linux machine on a local-address-space cursor might lead to the following call stack:

#0  lzma_stream_buffer_decode (memlimit=0x7fffffffca40, flags=0, allocator=0x0, in=0x7fffbd3144d0 "\375\067zXZ", in_pos=0x7fffffffca48, in_size=915412, out=0x7fffbc936000 "", 
    out_pos=0x7fffffffca50, out_size=4470304) at ../../../../src/liblzma/common/stream_buffer_decoder.c:21
#1  0x00007ffff7f8017b in _Uelf64_extract_minidebuginfo (ei=0x7fffffffcb90, mdi=0x7fffffffcb00) at elfxx.c:278
#2  0x00007ffff7f80261 in _Uelf64_get_proc_name_in_image (as=0x7ffff7f892a0 <local_addr_space>, ei=0x7fffffffcb90, segbase=93824993083392, mapoff=851968, ip=93824994457837, 
    buf=0x7fffffffd110 "foo", buf_len=42, offp=0x7fffffffd108) at elfxx.c:320
#3  0x00007ffff7f80393 in _Uelf64_get_proc_name (as=0x7ffff7f892a0 <local_addr_space>, pid=6674, ip=93824994457837, buf=0x7fffffffd110 "foo", buf_len=42, offp=0x7fffffffd108) at elfxx.c:353
#4  0x00007ffff7f75b68 in get_static_proc_name (as=0x7ffff7f892a0 <local_addr_space>, ip=93824994457837, buf=0x7fffffffd110 "foo", buf_len=42, offp=0x7fffffffd108, arg=0x7fffffffc520)
    at x86_64/Ginit.c:249
#5  0x00007ffff7f7415b in get_proc_name (as=0x7ffff7f892a0 <local_addr_space>, ip=93824994457837, buf=0x7fffffffd110 "foo", buf_len=42, offp=0x7fffffffd108, arg=0x7fffffffc520)
    at mi/Gget_proc_name.c:93
#6  0x00007ffff7f741e8 in _ULx86_64_get_proc_name (cursor=0x7fffffffcd10, buf=0x7fffffffd110 "foo", buf_len=42, offp=0x7fffffffd108) at mi/Gget_proc_name.c:111

The lzma_stream_buffer_decode function doesn't give any AS-safety guarantees; moreover, it claims to allocate memory with malloc/free if allocator=NULL (which is the case). Hence, unw_get_proc_name is unsafe to use from a signal handler.

unw_backtrace() returns wrong addresses

I have unw_backtrace() on x86-64 machine always returning addresses that are off by one relative to the instruction address after the call. This issue is related to fast backtrace optimization and I guess it may be caused by not restoring rip after decrementing it by use_prev_instr flag. Indeed, in src/x86_64/Gtrace.c we have:
line 438: rip -= d->use_prev_instr;
and before finishing the loop iteration:
line 543: buffer[depth++] = (void *) (rip - d->use_prev_instr);
I see no place where rip gets incremented again in this loop, so at least for standard frames we definitely write to the buffer the wrong value.
There is no problem if I manually unwind the stack using unw_step().

ARM perf regression

Luke Diamand says:

I could be wrong about this, but I'm finding a roughly 10x slowdown on
ARM between 1.2.1 and current HEAD (e1ca874).

I have a small test program here:

https://gist.github.com/luked99/7c67d94da5c33cac5a1b41a500013355

On my Raspberry Pi 2, this is getting ~180us to do a self-backtrace in
1.2.1 and around 1.8ms in HEAD.
I tried running perf, and that seems to be saying that it is opening
and closing files a lot.

I also had a go at git bisecting, but there's a separate bug which was
introduced and then fixed which caused it to segfault, which overlaps
with this problem, along with some other performance regression fixes.
90d0d15 didn't crash, but was slow.
2a5d1a6 crashed.
v1.2.1 is fast.
If do:
export UNW_ARM_UNWIND_METHOD=4

(so only use the exidx tables) then it drops from ~1ms to 95us.

My image only has the exidx tables; it's built with gcc using
bog-standard compiler and linker options.

$ objdump -S bt_perf
Idx Name Size VMA LMA File off Algn
....
15 .ARM.extab 00000264 0000a7e8 0000a7e8 0000a7e8 22
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .ARM.exidx 000002a0 0000aa4c 0000aa4c 0000aa4c 2
2
CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .eh_frame 00000004 0000acec 0000acec 0000acec 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA

minidebuginfo test can't resolve proc names

The run-coredump-unwind-mdi test does not work for me on x86-64 and Ubuntu 17.07. Even gdb can't resolve the proc names. Running the original crasher binary under gdb produces this backtrace:

Program received signal SIGSEGV, Segmentation fault.
a () at ../../tests/crasher.c:99
99        *(volatile int *)32 = 1;
(gdb) bt
#0  a () at ../../tests/crasher.c:99
#1  0x0000555555554a65 in b (x=1) at ../../tests/crasher.c:110
#2  0x0000555555554a52 in b (x=<optimized out>) at ../../tests/crasher.c:112
#3  0x0000555555554799 in main (argc=<optimized out>, argv=<optimized out>) at ../../tests/crasher.c:121

The crasher binary with the compressed .gnu_debugdata section produces this backtrace:

Program received signal SIGSEGV, Segmentation fault.
0x0000555555554a20 in ?? ()
(gdb) bt
#0  0x0000555555554a20 in ?? ()
#1  0x0000555555554a65 in ?? ()
#2  0x0000555555554a52 in ?? ()
#3  0x0000555555554799 in ?? ()
#4  0x00007ffff7a303f1 in __libc_start_main (main=0x555555554780, argc=1, argv=0x7fffffffd458, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffd448)
    at ../csu/libc-start.c:291
#5  0x00005555555547ca in ?? ()

Details on support for Alpine on PPC64LE

I have seen the table in readme stating that libunwind is available on PPC64.

I would like to know if it can be built / available on PPC64LE (little endian) for alpine linux.

In package page of alpine i could only see its available for x86_64 architecture. I would like to know the availability of it on PPC64LE

dwarf unw_get_proc_info needs a cache

The original IA64 code had a cache for unw_get_proc_info. There is a TODO comment in the dwarf version, but it doesn't yet have an implementation.

libunwind crashes during stack unwinding

Following example crashes with libunwind-1.2 (commit 5f354cb v1.2-stable branch) on x86:

#include <vector>
#include <cstdio>

#define UNW_LOCAL_ONLY
#include <libunwind.h>

__attribute__((noinline))
void show_backtrace (void)
{
    unw_cursor_t cursor; unw_context_t uc;
    unw_word_t ip, sp, esi;

    unw_getcontext(&uc);
    unw_init_local(&cursor, &uc);
    while (unw_step(&cursor) > 0) {
        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        unw_get_reg(&cursor, UNW_REG_SP, &sp);
        unw_get_reg(&cursor, UNW_X86_ESI, &esi);
        printf ("ip = %lx, sp = %lx, esi = %lx\n", (long) ip, (long) sp, (long) esi);
    }
}

__attribute__((noinline))
void func(int a, std::vector<char*> &v)
{
    show_backtrace();
    printf("%d %d\n", a, v.size());
}

int main(int argc, char **argv)
{
    std::vector<char*> v(2);

    if (argc > 1)
    {
        if (argc > 100)
            return 1;

        v[0] = argv[argc - 2];
        v[1] = argv[argc - 1];

        func(argc - 1, v);

        return 2;
    }
    else
    {
        v[0] = argv[0];

        func(argc - 2, v);

        return 3;
    }

    return 0;
}

Steps to reproduce

  1. Compile libunwind-1.2:
$ git branch 
  master
* v1.2-stable
$ ./autogen.sh
./configure --enable-debug --host=i386-linux-gnu "CFLAGS=-m32" "CXXFLAGS=-m32" "LDFLAGS=-m32"
$ make
  1. Compile example:
$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ -m32 -L/media/kbaladurin/data/dotnet/forked/libunwind/src/.libs/ -I/media/kbaladurin/data/dotnet/forked/libunwind/include -O2 unwind.cpp  -lunwind
$ LD_LIBRARY_PATH=/media/kbaladurin/data/dotnet/forked/libunwind/src/.libs/ ldd ./a.out
	linux-gate.so.1 =>  (0xf77b7000)
	libunwind.so.8 => /media/kbaladurin/data/dotnet/forked/libunwind/src/.libs/libunwind.so.8 (0xf7792000)
	libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xf75ef000)
	libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xf75d2000)
	libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf741c000)
	libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xf73c7000)
	/lib/ld-linux.so.2 (0xf77b8000)
$ LD_LIBRARY_PATH=/media/kbaladurin/data/dotnet/forked/libunwind/src/.libs/ ./a.out
ip = 80489b8, sp = ff99a140, esi = f75ac000
ip = 80487a8, sp = ff99a150, esi = f75ac000
Segmentation fault (core dumped)

Crash details

$ LD_LIBRARY_PATH=/media/kbaladurin/data/dotnet/forked/libunwind/src/.libs/ UNW_DEBUG_LEVEL=15 gdb -q ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/kbaladurin/Desktop/tests/a.out 
...
ip = 80487a8, sp = ffffcd30, esi = f7def000
 >_ULx86_step: (cursor=0xffffcb10, ip=0x080487a8)
              >_ULx86_dwarf_find_proc_info: looking for IP=0x80487a7
               >_ULx86_dwarf_callback: checking , base=0x0)
               >_ULx86_dwarf_callback: found table `': segbase=0x8048a68, len=12, gp=0x804a000, table_data=0x8048a74
               >lookup: e->start_ip_offset = ffffff28
               >lookup: e->start_ip_offset = fffffc68
               >lookup: e->start_ip_offset = fffffe68
               >_ULx86_dwarf_search_unwind_table: ip=0x80487a7, start_ip=0xfffffc68
 >_ULx86_dwarf_search_unwind_table: e->fde_offset = 16c, segbase = 8048a68, debug_frame_base = 0, fde_addr = 8048bd4
            >_ULx86_dwarf_extract_proc_info_from_fde: FDE @ 0x8048bd4
               >_ULx86_dwarf_extract_proc_info_from_fde: looking for CIE at address 8048bb4
               >parse_cie: CIE parsed OK, augmentation = "zPLR", handler=0x80486a0
               >_ULx86_dwarf_extract_proc_info_from_fde: FDE covers IP 0x80486d0-0x80487d5, LSDA=0x8048c84
               >run_cfi_program: CFA_def_cfa r4+0x4
               >run_cfi_program: CFA_offset r8 at cfa+0xfffffffc
               >run_cfi_program: CFA_advance_loc to 0x80486d4
               >run_cfi_program: CFA_def_cfa r1+0x0
               >run_cfi_program: CFA_advance_loc to 0x80486db
               >run_cfi_program: CFA_expression r5 @ 0xffffc5e0 [2 bytes]
               >run_cfi_program: CFA_advance_loc to 0x80486e1
               >run_cfi_program: CFA_def_cfa_expr @ 0x8048bf6 [3 bytes]
               >run_cfi_program: CFA_expression r7 @ 0xffffc5e0 [2 bytes]
               >run_cfi_program: CFA_expression r6 @ 0xffffc5e0 [2 bytes]
               >run_cfi_program: CFA_expression r3 @ 0xffffc5e0 [2 bytes]
               >run_cfi_program: CFA_advance_loc1 to 0x8048762
               >run_cfi_program: CFA_remember_state
               >run_cfi_program: CFA_restore r1
               >run_cfi_program: CFA_def_cfa r1+0x0
               >run_cfi_program: CFA_advance_loc to 0x8048763
               >run_cfi_program: CFA_restore r3
               >run_cfi_program: CFA_advance_loc to 0x8048764
               >run_cfi_program: CFA_restore r6
               >run_cfi_program: CFA_advance_loc to 0x8048765
               >run_cfi_program: CFA_restore r7
               >run_cfi_program: CFA_advance_loc to 0x8048766
               >run_cfi_program: CFA_restore r5
               >run_cfi_program: CFA_advance_loc to 0x8048769
               >run_cfi_program: CFA_def_cfa r4+0x4
               >run_cfi_program: CFA_advance_loc to 0x804876a
               >run_cfi_program: CFA_restore_state
               >run_cfi_program: CFA_advance_loc to 0x8048786
               >run_cfi_program: CFA_GNU_args_size 16
              >_ULx86_dwarf_eval_expr: len=3, pushing cfa=0xffffcd30
               >_ULx86_dwarf_eval_expr: OP_breg(r5,0xfffffff0)
               >_ULx86_dwarf_eval_expr: OP_deref
              >_ULx86_dwarf_eval_expr: final value = 0xffffcd80
              >_ULx86_dwarf_eval_expr: len=2, pushing cfa=0xffffcd30
               >_ULx86_dwarf_eval_expr: OP_breg(r5,0xfffffff4)
              >_ULx86_dwarf_eval_expr: final value = 0xffffcd5c
              >_ULx86_dwarf_eval_expr: len=2, pushing cfa=0xffffcd30
               >_ULx86_dwarf_eval_expr: OP_breg(r5,0x0)
              >_ULx86_dwarf_eval_expr: final value = 0xffffcd68
              >_ULx86_dwarf_eval_expr: len=2, pushing cfa=0xffffcd30
               >_ULx86_dwarf_eval_expr: OP_breg(r5,0xfffffff8)
              >_ULx86_dwarf_eval_expr: final value = 0xfffffff8
              >_ULx86_dwarf_eval_expr: len=2, pushing cfa=0xffffcd30
               >_ULx86_dwarf_eval_expr: OP_breg(r5,0xfffffffc)
              >_ULx86_dwarf_eval_expr: final value = 0xfffffffc
               >_ULx86_dwarf_step: returning 1
  >_ULx86_step: returning 1

Program received signal SIGSEGV, Segmentation fault.
0xf7fb6a83 in access_mem () from /media/kbaladurin/data/dotnet/forked/libunwind/src/.libs/libunwind.so.8
(gdb) bt
#0  0xf7fb6a83 in access_mem () from /media/kbaladurin/data/dotnet/forked/libunwind/src/.libs/libunwind.so.8
#1  0xf7fb75ed in dwarf_get () from /media/kbaladurin/data/dotnet/forked/libunwind/src/.libs/libunwind.so.8
#2  0xf7fb790b in _ULx86_access_reg () from /media/kbaladurin/data/dotnet/forked/libunwind/src/.libs/libunwind.so.8
#3  0xf7fb64a6 in _ULx86_get_reg () from /media/kbaladurin/data/dotnet/forked/libunwind/src/.libs/libunwind.so.8
#4  0x08048938 in show_backtrace() ()
#5  0x0804899d in func(int, std::vector<char*, std::allocator<char*> >&) ()
#6  0x080487a8 in main ()
(gdb) x/10i $pc
=> 0xf7fb6a83 <access_mem+197>:	mov    (%eax),%edx
   0xf7fb6a85 <access_mem+199>:	mov    0x10(%ebp),%eax
   0xf7fb6a88 <access_mem+202>:	mov    %edx,(%eax)
   0xf7fb6a8a <access_mem+204>:	mov    -0x18(%ebx),%eax
   0xf7fb6a90 <access_mem+210>:	mov    (%eax),%eax
   0xf7fb6a92 <access_mem+212>:	cmp    $0xf,%eax
   0xf7fb6a95 <access_mem+215>:	jle    0xf7fb6af3 <access_mem+309>
   0xf7fb6a97 <access_mem+217>:	movl   $0x10,-0x10(%ebp)
   0xf7fb6a9e <access_mem+224>:	cmpl   $0x10,-0x10(%ebp)
   0xf7fb6aa2 <access_mem+228>:	jle    0xf7fb6aab <access_mem+237>
(gdb) i r
eax            0xfffffff8	-8
ecx            0xfffffff8	-8
edx            0xf7fce200	-134422016
ebx            0xf7fca000	-134438912
esp            0xffffc8c0	0xffffc8c0
ebp            0xffffc8d8	0xffffc8d8
esi            0xffffc9ac	-13908
edi            0xffffc9a8	-13912
eip            0xf7fb6a83	0xf7fb6a83 <access_mem+197>
eflags         0x10246	[ PF ZF IF RF ]
cs             0x23	35
ss             0x2b	43
ds             0x2b	43
es             0x2b	43
fs             0x0	0
gs             0x63	99

Crash occurs during getting esi value due to incorrect esi's location (0xfffffff8) that was restored from the main function's frame.
main function of this test application has following prologue:

   0x080486d0 <+0>:	lea    ecx,[esp+0x4]
   0x080486d4 <+4>:	and    esp,0xfffffff0
   0x080486d7 <+7>:	push   DWORD PTR [ecx-0x4]
   0x080486da <+10>:	push   ebp
   0x080486db <+11>:	mov    ebp,esp
   0x080486dd <+13>:	push   edi
   0x080486de <+14>:	push   esi
   0x080486df <+15>:	push   ebx
   0x080486e0 <+16>:	push   ecx
   0x080486e1 <+17>:	sub    esp,0x24

Compiler generates following unwind info for it:

$ objdump --dwarf=frames a.out
...
00000130 00000048 00000024 FDE cie=00000110 pc=080486d0..080487d5
  Augmentation data:     84 8c 04 08

  DW_CFA_advance_loc: 4 to 080486d4
  DW_CFA_def_cfa: r1 (ecx) ofs 0
  DW_CFA_advance_loc: 7 to 080486db
  DW_CFA_expression: r5 (ebp) (DW_OP_breg5 (ebp): 0)
  DW_CFA_advance_loc: 6 to 080486e1
  DW_CFA_def_cfa_expression (DW_OP_breg5 (ebp): -16; DW_OP_deref)
  DW_CFA_expression: r7 (edi) (DW_OP_breg5 (ebp): -4)
  DW_CFA_expression: r6 (esi) (DW_OP_breg5 (ebp): -8)
  DW_CFA_expression: r3 (ebx) (DW_OP_breg5 (ebp): -12)
  DW_CFA_advance_loc1: 129 to 08048762
  DW_CFA_remember_state
  DW_CFA_restore: r1 (ecx)
  DW_CFA_def_cfa: r1 (ecx) ofs 0
  DW_CFA_advance_loc: 1 to 08048763
  DW_CFA_restore: r3 (ebx)
  DW_CFA_advance_loc: 1 to 08048764
  DW_CFA_restore: r6 (esi)
  DW_CFA_advance_loc: 1 to 08048765
  DW_CFA_restore: r7 (edi)
  DW_CFA_advance_loc: 1 to 08048766
  DW_CFA_restore: r5 (ebp)
  DW_CFA_advance_loc: 3 to 08048769
  DW_CFA_def_cfa: r4 (esp) ofs 4
  DW_CFA_advance_loc: 1 to 0804876a
  DW_CFA_restore_state
  DW_CFA_advance_loc: 28 to 08048786
  DW_CFA_GNU_args_size: 16
...

libunwind restores registers in the following order: ebx, ebp, esi, edi. Their locations are defined by dwarf expressions based on ebp value:

DW_CFA_expression: r5 (ebp) (DW_OP_breg5 (ebp): 0)
DW_CFA_expression: r7 (edi) (DW_OP_breg5 (ebp): -4)
DW_CFA_expression: r6 (esi) (DW_OP_breg5 (ebp): -8)
DW_CFA_expression: r3 (ebx) (DW_OP_breg5 (ebp): -12)

Locations of the ebx and ebp are calculated using current ebp (0xffffcd68) but locations of the esi and edi are calculated using previous (restored) one that is zero. It's incorrect and lead to crash.

Possible solution
I think we should always use current context when evaluates dwarf expression (as llvm's libunwind). The following patch fixes this crash:

diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c
index 3a47255..455124b 100644
--- a/src/dwarf/Gparser.c
+++ b/src/dwarf/Gparser.c
@@ -776,40 +776,45 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
       cfa = DWARF_GET_LOC (cfa_loc);
     }
 
+  dwarf_loc_t new_loc[DWARF_NUM_PRESERVED_REGS];
+  memcpy(new_loc, c->loc, sizeof(new_loc));
+
   for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
     {
       switch ((dwarf_where_t) rs->reg[i].where)
         {
         case DWARF_WHERE_UNDEF:
-          c->loc[i] = DWARF_NULL_LOC;
+          new_loc[i] = DWARF_NULL_LOC;
           break;
 
         case DWARF_WHERE_SAME:
           break;
 
         case DWARF_WHERE_CFAREL:
-          c->loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg[i].val);
+          new_loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg[i].val);
           break;
 
         case DWARF_WHERE_REG:
-          c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val));
+          new_loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val));
           break;
 
         case DWARF_WHERE_EXPR:
           addr = rs->reg[i].val;
-          if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0)
+          if ((ret = eval_location_expr (c, as, a, addr, new_loc + i, arg)) < 0)
             return ret;
           break;
 
         case DWARF_WHERE_VAL_EXPR:
           addr = rs->reg[i].val;
-          if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0)
+          if ((ret = eval_location_expr (c, as, a, addr, new_loc + i, arg)) < 0)
             return ret;
-          c->loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (c->loc[i]));
+          new_loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (new_loc[i]));
           break;
         }
     }
 
+  memcpy(c->loc, new_loc, sizeof(new_loc));
+
   c->cfa = cfa;
   /* DWARF spec says undefined return address location means end of stack. */
   if (DWARF_IS_NULL_LOC (c->loc[c->ret_addr_column]))
$ LD_LIBRARY_PATH=/media/kbaladurin/data/dotnet/forked/libunwind/src/.libs/ UNW_DEBUG_LEVEL=15 ./a.out
...
ip = 80487a8, sp = ffa67f60, esi = f7542000
 >_ULx86_step: (cursor=0xffa67d40, ip=0x080487a8)
              >_ULx86_dwarf_find_proc_info: looking for IP=0x80487a7
               >_ULx86_dwarf_callback: checking , base=0x0)
               >_ULx86_dwarf_callback: found table `': segbase=0x8048a68, len=12, gp=0x804a000, table_data=0x8048a74
               >lookup: e->start_ip_offset = ffffff28
               >lookup: e->start_ip_offset = fffffc68
               >lookup: e->start_ip_offset = fffffe68
               >_ULx86_dwarf_search_unwind_table: ip=0x80487a7, start_ip=0xfffffc68
 >_ULx86_dwarf_search_unwind_table: e->fde_offset = 16c, segbase = 8048a68, debug_frame_base = 0, fde_addr = 8048bd4
            >_ULx86_dwarf_extract_proc_info_from_fde: FDE @ 0x8048bd4
               >_ULx86_dwarf_extract_proc_info_from_fde: looking for CIE at address 8048bb4
               >parse_cie: CIE parsed OK, augmentation = "zPLR", handler=0x80486a0
               >_ULx86_dwarf_extract_proc_info_from_fde: FDE covers IP 0x80486d0-0x80487d5, LSDA=0x8048c84
               >run_cfi_program: CFA_def_cfa r4+0x4
               >run_cfi_program: CFA_offset r8 at cfa+0xfffffffc
               >run_cfi_program: CFA_advance_loc to 0x80486d4
               >run_cfi_program: CFA_def_cfa r1+0x0
               >run_cfi_program: CFA_advance_loc to 0x80486db
               >run_cfi_program: CFA_expression r5 @ 0xffa67810 [2 bytes]
               >run_cfi_program: CFA_advance_loc to 0x80486e1
               >run_cfi_program: CFA_def_cfa_expr @ 0x8048bf6 [3 bytes]
               >run_cfi_program: CFA_expression r7 @ 0xffa67810 [2 bytes]
               >run_cfi_program: CFA_expression r6 @ 0xffa67810 [2 bytes]
               >run_cfi_program: CFA_expression r3 @ 0xffa67810 [2 bytes]
               >run_cfi_program: CFA_advance_loc1 to 0x8048762
               >run_cfi_program: CFA_remember_state
               >run_cfi_program: CFA_restore r1
               >run_cfi_program: CFA_def_cfa r1+0x0
               >run_cfi_program: CFA_advance_loc to 0x8048763
               >run_cfi_program: CFA_restore r3
               >run_cfi_program: CFA_advance_loc to 0x8048764
               >run_cfi_program: CFA_restore r6
               >run_cfi_program: CFA_advance_loc to 0x8048765
               >run_cfi_program: CFA_restore r7
               >run_cfi_program: CFA_advance_loc to 0x8048766
               >run_cfi_program: CFA_restore r5
               >run_cfi_program: CFA_advance_loc to 0x8048769
               >run_cfi_program: CFA_def_cfa r4+0x4
               >run_cfi_program: CFA_advance_loc to 0x804876a
               >run_cfi_program: CFA_restore_state
               >run_cfi_program: CFA_advance_loc to 0x8048786
               >run_cfi_program: CFA_GNU_args_size 16
              >_ULx86_dwarf_eval_expr: len=3, pushing cfa=0xffa67f60
               >_ULx86_dwarf_eval_expr: OP_breg(r5,0xfffffff0)
               >_ULx86_dwarf_eval_expr: OP_deref
              >_ULx86_dwarf_eval_expr: final value = 0xffa67fb0
              >_ULx86_dwarf_eval_expr: len=2, pushing cfa=0xffa67f60
               >_ULx86_dwarf_eval_expr: OP_breg(r5,0xfffffff4)
              >_ULx86_dwarf_eval_expr: final value = 0xffa67f8c
              >_ULx86_dwarf_eval_expr: len=2, pushing cfa=0xffa67f60
               >_ULx86_dwarf_eval_expr: OP_breg(r5,0x0)
              >_ULx86_dwarf_eval_expr: final value = 0xffa67f98
              >_ULx86_dwarf_eval_expr: len=2, pushing cfa=0xffa67f60
               >_ULx86_dwarf_eval_expr: OP_breg(r5,0xfffffff8)
              >_ULx86_dwarf_eval_expr: final value = 0xffa67f90
              >_ULx86_dwarf_eval_expr: len=2, pushing cfa=0xffa67f60
               >_ULx86_dwarf_eval_expr: OP_breg(r5,0xfffffffc)
              >_ULx86_dwarf_eval_expr: final value = 0xffa67f94
               >_ULx86_dwarf_step: returning 1
  >_ULx86_step: returning 1
...
-1 2

Is it correct solution?
Thank you!

error: 'NLGA' undeclared here (not in a function)

I'm installed libunwind on centos 7.4 86_64x ,but it's error:

In file included from x86_64/Linit.c:4:0:
x86_64/Ginit.c:216:28: error: 'NLGA' undeclared here (not in a function)
static AO_T last_good_addr[NLGA];
^
x86_64/Ginit.c:216:13: warning: 'last_good_addr' defined but not used [-Wunused-variable]
static AO_T last_good_addr[NLGA];
^
make[2]: *** [x86_64/Linit.lo] Error 1
make[2]: Leaving directory /usr/local/src/libunwind/src' make[1]: *** [all] Error 2 make[1]: Leaving directory /usr/local/src/libunwind/src'
make: *** [all-recursive] Error 1

SIGSEGV JVM exits stating libunwind.so as the problematic frame

I do not have any experience in using libunwind, but the people at jemalloc recommended it for backtracing since libgcc wasn't working for me.
I have compiled jemalloc with libunwind for backtracing. When I run my java program, however, the following appears:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x76cdcaa8, pid=2527, tid=1992274976
#
# JRE version:  (8.0_65-b17) (build )
# Java VM: Java HotSpot(TM) Client VM (25.65-b01 mixed mode linux-arm )
# Problematic frame:
# C  [libunwind.so.8+0x3aa8]  _ULarm_step+0x1b0
#
# Core dump written. Default location: /home/pi/Desktop/jemalloc-master/core or core.2527
#
# An error report file with more information is saved as:
# /home/pi/Desktop/jemalloc-master/hs_err_pid2527.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Aborted (core dumped)

I have attached the error log.
Let me know if core dump is also required, I'll upload a google drive link.
Please help soon. Thank you very much.

hs_err_pid29350.log

Anyone can help in compiling libunwind on Ubuntu x86-64 for Android?

Anyone who can help compile libunwind on Ubuntu x86-64 for Android devices?(wanna get 32bit and 64bit so files...)
How to config OR compile with android NDK?
I have tried ./configure --host="arm-linux-android"(also ./configure --host=arm-linux-androideabi)and make but failed...

libtool: compile: gcc -DHAVE_CONFIG_H -I. -I../include -I../include -I../include/tdep-arm -I. -D_GNU_SOURCE -DNDEBUG -g -O2 -fexceptions -Wall -Wsign-compare -MT arm/is_fpreg.lo -MD -MP -MF arm/.deps/is_fpreg.Tpo -c arm/is_fpreg.c -fPIC -DPIC -o arm/.libs/is_fpreg.o
arm/is_fpreg.c: In function '_Ux86_64_is_fpreg':
arm/is_fpreg.c:33:22: error: 'UNW_ARM_S0' undeclared (first use in this function)
return ((regnum >= UNW_ARM_S0 && regnum <= UNW_ARM_S31)

Thanks.

setcontext deprecated on x86

Related to #13

setcontext is also deprecated and not present on x86 android. It would be nice if x86 would provide its own setcontext.S, similar to x86_64

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.