From: Jan Kratochvil Date: Mon, 2 Dec 2013 19:54:28 +0000 (+0100) Subject: Tests for unwinder of x86*. X-Git-Tag: elfutils-0.158~50 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8ae9bc9d315be6ecbb97dd9754b9d8424b5a70f0;p=platform%2Fupstream%2Felfutils.git Tests for unwinder of x86*. Signed-off-by: Jan Kratochvil --- diff --git a/ChangeLog b/ChangeLog index df99309..1347f1f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-12-02 Jan Kratochvil + + * configure.ac (CC_BIARCH): Remove AS_IF for it. + 2013-11-07 Jan Kratochvil * configure.ac: New AC_CHECK_SIZEOF for long. Call utrace_BIARCH, new diff --git a/configure.ac b/configure.ac index 99b74ae..72fb3e8 100644 --- a/configure.ac +++ b/configure.ac @@ -332,9 +332,7 @@ AC_CHECK_SIZEOF(long) # Likewise in a 32-bit build on a host where $CC -m64 works. utrace_BIARCH # `$utrace_biarch' will be `-m64' even on an uniarch i386 machine. -AS_IF([test $utrace_cv_cc_biarch = yes], - [CC_BIARCH="$CC $utrace_biarch"], - [CC_BIARCH="$CC"]) +CC_BIARCH="$CC $utrace_biarch" AC_SUBST([CC_BIARCH]) AC_OUTPUT diff --git a/m4/ChangeLog b/m4/ChangeLog index 0fc7871..c950e54 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,7 @@ +2013-12-02 Jan Kratochvil + + * biarch.m4 (utrace_BIARCH): Call AC_MSG_WARN if !BIARCH. + 2013-11-07 Roland McGrath Jan Kratochvil diff --git a/m4/biarch.m4 b/m4/biarch.m4 index a15323e..04c8dba 100644 --- a/m4/biarch.m4 +++ b/m4/biarch.m4 @@ -41,5 +41,7 @@ save_CC="$CC" CC="$biarch_CC" AC_RUN_IFELSE([AC_LANG_PROGRAM([], [])], utrace_cv_cc_biarch=yes, utrace_cv_cc_biarch=no) -CC="$save_CC"])], [utrace_cv_cc_biarch=no])]) +CC="$save_CC"])], [utrace_cv_cc_biarch=no]) +AS_IF([test $utrace_cv_cc_biarch != yes], [dnl +AC_MSG_WARN([not running biarch tests, $biarch_CC does not work])])]) AM_CONDITIONAL(BIARCH, [test $utrace_cv_cc_biarch = yes])]) diff --git a/tests/ChangeLog b/tests/ChangeLog index 6c0ec36..9bd2fe8 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,41 @@ +2013-12-02 Jan Kratochvil + + * Makefile.am (check_PROGRAMS): Add backtrace, backtrace-child, + backtrace-data and backtrace-dwarf. + (BUILT_SOURCES, clean-local, backtrace-child-biarch): New. + (TESTS): Add run-backtrace-native.sh, run-backtrace-data.sh, + run-backtrace-dwarf.sh, run-backtrace-native-biarch.sh, + run-backtrace-native-core.sh, run-backtrace-native-core-biarch.sh, + run-backtrace-core-x86_64.sh and run-backtrace-core-i386.sh. + Add export of ELFUTILS_DISABLE_BIARCH. + (EXTRA_DIST): Add run-backtrace-data.sh, run-backtrace-dwarf.sh, + cleanup-13.c, run-backtrace-native.sh, run-backtrace-native-biarch.sh, + run-backtrace-native-core.sh, run-backtrace-native-core-biarch.sh, + run-backtrace-core-x86_64.sh, run-backtrace-core-i386.sh, + backtrace-subr.sh, backtrace.i386.core.bz2, backtrace.i386.exec.bz2, + backtrace.x86_64.core.bz2, backtrace.x86_64.exec.bz2. + (backtrace_LDADD, backtrace_child_CFLAGS, backtrace_child_LDFLAGS) + (backtrace_data_LDADD, backtrace_dwarf_CFLAGS, backtrace_dwarf_LDADD): + New. + * backtrace-child.c: New file. + * backtrace-data.c: New file. + * backtrace-dwarf.c: New file. + * backtrace-subr.sh: New file. + * backtrace.c: New file. + * cleanup-13.c: New file. + * backtrace.i386.core.bz2: New file. + * backtrace.i386.exec.bz2: New file. + * backtrace.x86_64.core.bz2: New file. + * backtrace.x86_64.exec.bz2: New file. + * run-backtrace-core-i386.sh: New file. + * run-backtrace-core-x86_64.sh: New file. + * run-backtrace-native-biarch.sh: New file. + * run-backtrace-native-core-biarch.sh: New file. + * run-backtrace-native-core.sh: New file. + * run-backtrace-native.sh: New file. + * run-backtrace-data.sh: New file. + * run-backtrace-dwarf.sh: New file. + 2013-11-27 Mark Wielaard * dwflsyms.c (gelf_bind_order): New function. diff --git a/tests/Makefile.am b/tests/Makefile.am index cedb684..a74830b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -52,10 +52,23 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ test-flag-nobits dwarf-getstring rerequest_tag \ alldts md5-sha1-test typeiter typeiter2 low_high_pc \ test-elf_cntl_gelf_getshdr dwflsyms dwfllines \ - dwfl-report-elf-align varlocs + dwfl-report-elf-align varlocs backtrace backtrace-child \ + backtrace-data backtrace-dwarf asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \ asm-tst6 asm-tst7 asm-tst8 asm-tst9 +if BIARCH +check_PROGRAMS += backtrace-child-biarch +endif + +# Substitute $(COMPILE). +backtrace-child-biarch: backtrace-child.c + $(CC_BIARCH) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) $(backtrace_child_CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) $(backtrace_child_LDFLAGS) \ + -o $@ $< + TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \ update1 update2 update3 update4 \ run-show-die-info.sh run-get-files.sh run-get-lines.sh \ @@ -89,7 +102,15 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \ run-test-archive64.sh run-readelf-vmcoreinfo.sh \ run-readelf-mixed-corenote.sh run-dwfllines.sh \ run-dwfl-report-elf-align.sh run-addr2line-test.sh \ - run-addr2line-i-test.sh run-varlocs.sh run-funcretval.sh + run-addr2line-i-test.sh run-varlocs.sh run-funcretval.sh \ + run-backtrace-native.sh run-backtrace-data.sh run-backtrace-dwarf.sh \ + run-backtrace-native-biarch.sh run-backtrace-native-core.sh \ + run-backtrace-native-core-biarch.sh run-backtrace-core-x86_64.sh \ + run-backtrace-core-i386.sh + +if !BIARCH +export ELFUTILS_DISABLE_BIARCH = 1 +endif if !STANDALONE check_PROGRAMS += msg_tst md5-sha1-test @@ -218,7 +239,13 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ testfile_entry_value.c testfile_entry_value.bz2 \ testfile_implicit_value.c testfile_implicit_value.bz2 \ testfile_aarch64_core.bz2 \ - run-funcretval.sh funcretval_test.c funcretval_test_aarch64.bz2 + run-funcretval.sh funcretval_test.c funcretval_test_aarch64.bz2 \ + run-backtrace-data.sh run-backtrace-dwarf.sh cleanup-13.c \ + run-backtrace-native.sh run-backtrace-native-biarch.sh \ + run-backtrace-native-core.sh run-backtrace-native-core-biarch.sh \ + run-backtrace-core-x86_64.sh run-backtrace-core-i386.sh \ + backtrace-subr.sh backtrace.i386.core.bz2 backtrace.i386.exec.bz2 \ + backtrace.x86_64.core.bz2 backtrace.x86_64.exec.bz2 if USE_VALGRIND valgrind_cmd='valgrind -q --trace-children=yes --error-exitcode=1 --run-libc-freeres=no' @@ -347,6 +374,13 @@ dwflsyms_LDADD = $(libdw) $(libelf) $(libmudflap) dwfllines_LDADD = $(libdw) $(libelf) $(libmudflap) dwfl_report_elf_align_LDADD = $(libdw) $(libmudflap) varlocs_LDADD = $(libdw) $(libelf) $(libmudflap) +backtrace_LDADD = $(libdw) $(libelf) $(libmudflap) +# backtrace-child-biarch also uses those *_CFLAGS and *_LDLAGS variables: +backtrace_child_CFLAGS = -fPIE +backtrace_child_LDFLAGS = -pie -pthread +backtrace_data_LDADD = $(libdw) $(libelf) $(libmudflap) +backtrace_dwarf_CFLAGS = -Wno-unused-parameter +backtrace_dwarf_LDADD = $(libdw) $(libelf) $(libmudflap) if GCOV check: check-am coverage diff --git a/tests/backtrace-child.c b/tests/backtrace-child.c new file mode 100644 index 0000000..2bc0ede --- /dev/null +++ b/tests/backtrace-child.c @@ -0,0 +1,221 @@ +/* Test child for parent backtrace test. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Command line syntax: ./backtrace-child [--ptraceme|--gencore] + --ptraceme will call ptrace (PTRACE_TRACEME) in the two threads. + --gencore will call abort () at its end. + Main thread will signal SIGUSR2. Other thread will signal SIGUSR1. + On x86_64 only: + PC will get changed to function 'jmp' by backtrace.c function + prepare_thread. Then SIGUSR2 will be signalled to backtrace-child + which will invoke function sigusr2. + This is all done so that signal interrupts execution of the very first + instruction of a function. Properly handled unwind should not slip into + the previous unrelated function. + The tested functionality is arch-independent but the code reproducing it + has to be arch-specific. + On non-x86_64: + sigusr2 gets called by normal function call from function stdarg. + On any arch then sigusr2 calls raise (SIGUSR1) for --ptraceme. + abort () is called otherwise, expected for --gencore core dump. + + Expected x86_64 output: + TID 10276: + # 0 0x7f7ab61e9e6b raise + # 1 0x7f7ab661af47 - 1 main + # 2 0x7f7ab5e3bb45 - 1 __libc_start_main + # 3 0x7f7ab661aa09 - 1 _start + TID 10278: + # 0 0x7f7ab61e9e6b raise + # 1 0x7f7ab661ab3c - 1 sigusr2 + # 2 0x7f7ab5e4fa60 __restore_rt + # 3 0x7f7ab661ab47 jmp + # 4 0x7f7ab661ac92 - 1 stdarg + # 5 0x7f7ab661acba - 1 backtracegen + # 6 0x7f7ab661acd1 - 1 start + # 7 0x7f7ab61e2c53 - 1 start_thread + # 8 0x7f7ab5f0fdbd - 1 __clone + + Expected non-x86_64 (i386) output; __kernel_vsyscall are skipped if found: + TID 10408: + # 0 0xf779f430 __kernel_vsyscall + # 1 0xf7771466 - 1 raise + # 2 0xf77c1d07 - 1 main + # 3 0xf75bd963 - 1 __libc_start_main + # 4 0xf77c1761 - 1 _start + TID 10412: + # 0 0xf779f430 __kernel_vsyscall + # 1 0xf7771466 - 1 raise + # 2 0xf77c18f4 - 1 sigusr2 + # 3 0xf77c1a10 - 1 stdarg + # 4 0xf77c1a2c - 1 backtracegen + # 5 0xf77c1a48 - 1 start + # 6 0xf77699da - 1 start_thread + # 7 0xf769bbfe - 1 __clone + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +#define NOINLINE_NOCLONE __attribute__ ((noinline, noclone)) +#else +#define NOINLINE_NOCLONE __attribute__ ((noinline)) +#endif + +#define NORETURN __attribute__ ((noreturn)) +#define UNUSED __attribute__ ((unused)) +#define USED __attribute__ ((used)) + +static int ptraceme, gencore; + +/* Execution will arrive here from jmp by an artificial ptrace-spawn signal. */ + +static void +sigusr2 (int signo) +{ + assert (signo == SIGUSR2); + if (! gencore) + { + raise (SIGUSR1); + /* It should not be reached. */ + abort (); + } + /* Here we dump the core for --gencore. */ + raise (SIGABRT); +} + +static NOINLINE_NOCLONE void +dummy1 (void) +{ + asm volatile (""); +} + +#ifdef __x86_64__ +static NOINLINE_NOCLONE USED void +jmp (void) +{ + /* Not reached, signal will get ptrace-spawn to jump into sigusr2. */ + abort (); +} +#endif + +static NOINLINE_NOCLONE void +dummy2 (void) +{ + asm volatile (""); +} + +static NOINLINE_NOCLONE NORETURN void +stdarg (int f UNUSED, ...) +{ + sighandler_t sigusr2_orig = signal (SIGUSR2, sigusr2); + assert (sigusr2_orig == SIG_DFL); + errno = 0; + if (ptraceme) + { + long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); + assert_perror (errno); + assert (l == 0); + } +#ifdef __x86_64__ + if (! gencore) + { + /* Execution will get PC patched into function jmp. */ + raise (SIGUSR1); + } +#endif + sigusr2 (SIGUSR2); + /* Not reached. */ + abort (); +} + +static NOINLINE_NOCLONE void +dummy3 (void) +{ + asm volatile (""); +} + +static NOINLINE_NOCLONE void +backtracegen (void) +{ + stdarg (1); + /* Here should be no instruction after the stdarg call as it is noreturn + function. It must be stdarg so that it is a call and not jump (jump as + a tail-call). */ +} + +static NOINLINE_NOCLONE void +dummy4 (void) +{ + asm volatile (""); +} + +static void * +start (void *arg UNUSED) +{ + backtracegen (); + /* Not reached. */ + abort (); +} + +int +main (int argc UNUSED, char **argv) +{ + setbuf (stdout, NULL); + assert (*argv++); + ptraceme = (*argv && strcmp (*argv, "--ptraceme") == 0); + argv += ptraceme; + gencore = (*argv && strcmp (*argv, "--gencore") == 0); + argv += gencore; + assert (!*argv); + /* These dummy* functions are there so that each of their surrounding + functions has some unrelated code around. The purpose of some of the + tests is verify unwinding the very first / after the very last instruction + does not inappropriately slip into the unrelated code around. */ + dummy1 (); + dummy2 (); + dummy3 (); + dummy4 (); + if (gencore) + printf ("%ld\n", (long) getpid ()); + pthread_t thread; + int i = pthread_create (&thread, NULL, start, NULL); + // pthread_* functions do not set errno. + assert (i == 0); + if (ptraceme) + { + errno = 0; + long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); + assert_perror (errno); + assert (l == 0); + } + if (gencore) + pthread_join (thread, NULL); + else + raise (SIGUSR2); + /* Not reached. */ + abort (); +} diff --git a/tests/backtrace-data.c b/tests/backtrace-data.c new file mode 100644 index 0000000..f54263b --- /dev/null +++ b/tests/backtrace-data.c @@ -0,0 +1,325 @@ +/* Test custom provided Dwfl_Thread_Callbacks vector. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Test custom provided Dwfl_Thread_Callbacks vector. Test mimics what + a ptrace based vector would do. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include ELFUTILS_HEADER(dwfl) + +#ifndef __x86_64__ + +int +main (void) +{ + return 77; +} + +#else /* __x86_64__ */ + +/* The only arch specific code is set_initial_registers. */ + +static int +find_elf (Dwfl_Module *mod __attribute__ ((unused)), + void **userdata __attribute__ ((unused)), + const char *modname __attribute__ ((unused)), + Dwarf_Addr base __attribute__ ((unused)), + char **file_name __attribute__ ((unused)), + Elf **elfp __attribute__ ((unused))) +{ + /* Not used as modules are reported explicitly. */ + assert (0); +} + +static bool +memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, + void *dwfl_arg __attribute__ ((unused))) +{ + pid_t child = dwfl_pid (dwfl); + + errno = 0; + long l = ptrace (PTRACE_PEEKDATA, child, (void *) (uintptr_t) addr, NULL); + assert_perror (errno); + *result = l; + + /* We could also return false for failed ptrace. */ + return true; +} + +/* Return filename and VMA address *BASEP where its mapping starts which + contains ADDR. */ + +static char * +maps_lookup (pid_t pid, Dwarf_Addr addr, GElf_Addr *basep) +{ + char *fname; + int i = asprintf (&fname, "/proc/%ld/maps", (long) pid); + assert_perror (errno); + assert (i > 0); + FILE *f = fopen (fname, "r"); + assert_perror (errno); + assert (f); + free (fname); + for (;;) + { + // 37e3c22000-37e3c23000 rw-p 00022000 00:11 49532 /lib64/ld-2.14.90.so */ + unsigned long start, end, offset; + i = fscanf (f, "%lx-%lx %*s %lx %*x:%*x %*x", &start, &end, &offset); + assert_perror (errno); + assert (i == 3); + char *filename = strdup (""); + assert (filename); + size_t filename_len = 0; + for (;;) + { + int c = fgetc (f); + assert (c != EOF); + if (c == '\n') + break; + if (c == ' ' && *filename == '\0') + continue; + filename = realloc (filename, filename_len + 2); + assert (filename); + filename[filename_len++] = c; + filename[filename_len] = '\0'; + } + if (start <= addr && addr < end) + { + i = fclose (f); + assert_perror (errno); + assert (i == 0); + + *basep = start - offset; + return filename; + } + free (filename); + } +} + +/* Add module containing ADDR to the DWFL address space. + + dwfl_report_elf call here violates Dwfl manipulation as one should call + dwfl_report only between dwfl_report_begin_add and dwfl_report_end. + Current elfutils implementation does not mind as dwfl_report_begin_add is + empty. */ + +static Dwfl_Module * +report_module (Dwfl *dwfl, pid_t child, Dwarf_Addr addr) +{ + GElf_Addr base; + char *long_name = maps_lookup (child, addr, &base); + Dwfl_Module *mod = dwfl_report_elf (dwfl, long_name, long_name, -1, + base, false /* add_p_vaddr */); + assert (mod); + free (long_name); + assert (dwfl_addrmodule (dwfl, addr) == mod); + return mod; +} + +static pid_t +next_thread (Dwfl *dwfl, void *dwfl_arg __attribute__ ((unused)), + void **thread_argp) +{ + if (*thread_argp != NULL) + return 0; + /* Put arbitrary non-NULL value into *THREAD_ARGP as a marker so that this + function returns non-zero PID only once. */ + *thread_argp = thread_argp; + return dwfl_pid (dwfl); +} + +static bool +set_initial_registers (Dwfl_Thread *thread, + void *thread_arg __attribute__ ((unused))) +{ + pid_t child = dwfl_pid (dwfl_thread_dwfl (thread)); + + struct user_regs_struct user_regs; + long l = ptrace (PTRACE_GETREGS, child, NULL, &user_regs); + assert_perror (errno); + assert (l == 0); + + Dwarf_Word dwarf_regs[17]; + dwarf_regs[0] = user_regs.rax; + dwarf_regs[1] = user_regs.rdx; + dwarf_regs[2] = user_regs.rcx; + dwarf_regs[3] = user_regs.rbx; + dwarf_regs[4] = user_regs.rsi; + dwarf_regs[5] = user_regs.rdi; + dwarf_regs[6] = user_regs.rbp; + dwarf_regs[7] = user_regs.rsp; + dwarf_regs[8] = user_regs.r8; + dwarf_regs[9] = user_regs.r9; + dwarf_regs[10] = user_regs.r10; + dwarf_regs[11] = user_regs.r11; + dwarf_regs[12] = user_regs.r12; + dwarf_regs[13] = user_regs.r13; + dwarf_regs[14] = user_regs.r14; + dwarf_regs[15] = user_regs.r15; + dwarf_regs[16] = user_regs.rip; + bool ok = dwfl_thread_state_registers (thread, 0, 17, dwarf_regs); + assert (ok); + + /* x86_64 has PC contained in its CFI subset of DWARF register set so + elfutils will figure out the real PC value from REGS. + So no need to explicitly call dwfl_thread_state_register_pc. */ + + return true; +} + +static const Dwfl_Thread_Callbacks callbacks = +{ + next_thread, + memory_read, + set_initial_registers, + NULL, /* detach */ + NULL, /* thread_detach */ +}; + +static int +frame_callback (Dwfl_Frame *state, void *arg) +{ + unsigned *framenop = arg; + Dwarf_Addr pc; + bool isactivation; + if (! dwfl_frame_pc (state, &pc, &isactivation)) + { + error (1, 0, "%s", dwfl_errmsg (-1)); + return 1; + } + Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1); + + /* Get PC->SYMNAME. */ + Dwfl *dwfl = dwfl_thread_dwfl (dwfl_frame_thread (state)); + Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted); + if (mod == NULL) + mod = report_module (dwfl, dwfl_pid (dwfl), pc_adjusted); + const char *symname = NULL; + symname = dwfl_module_addrname (mod, pc_adjusted); + + printf ("#%2u %#" PRIx64 "%4s\t%s\n", (*framenop)++, (uint64_t) pc, + ! isactivation ? "- 1" : "", symname); + return DWARF_CB_OK; +} + +static int +thread_callback (Dwfl_Thread *thread, void *thread_arg __attribute__ ((unused))) +{ + unsigned frameno = 0; + switch (dwfl_thread_getframes (thread, frame_callback, &frameno)) + { + case 0: + break; + case -1: + error (1, 0, "dwfl_thread_getframes: %s", dwfl_errmsg (-1)); + default: + abort (); + } + return DWARF_CB_OK; +} + +int +main (int argc __attribute__ ((unused)), char **argv __attribute__ ((unused))) +{ + /* We use no threads here which can interfere with handling a stream. */ + __fsetlocking (stdin, FSETLOCKING_BYCALLER); + __fsetlocking (stdout, FSETLOCKING_BYCALLER); + __fsetlocking (stderr, FSETLOCKING_BYCALLER); + + /* Set locale. */ + (void) setlocale (LC_ALL, ""); + + elf_version (EV_CURRENT); + + pid_t child = fork (); + switch (child) + { + case -1: + assert_perror (errno); + assert (0); + case 0:; + long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); + assert_perror (errno); + assert (l == 0); + raise (SIGUSR1); + assert (0); + default: + break; + } + + int status; + pid_t pid = waitpid (child, &status, 0); + assert_perror (errno); + assert (pid == child); + assert (WIFSTOPPED (status)); + assert (WSTOPSIG (status) == SIGUSR1); + + static char *debuginfo_path; + static const Dwfl_Callbacks offline_callbacks = + { + .find_debuginfo = dwfl_standard_find_debuginfo, + .debuginfo_path = &debuginfo_path, + .section_address = dwfl_offline_section_address, + .find_elf = find_elf, + }; + Dwfl *dwfl = dwfl_begin (&offline_callbacks); + assert (dwfl); + + struct user_regs_struct user_regs; + long l = ptrace (PTRACE_GETREGS, child, NULL, &user_regs); + assert_perror (errno); + assert (l == 0); + report_module (dwfl, child, user_regs.rip); + + bool ok = dwfl_attach_state (dwfl, EM_NONE, child, &callbacks, NULL); + assert (ok); + + /* Multiple threads are not handled here. */ + int err = dwfl_getthreads (dwfl, thread_callback, NULL); + assert (! err); + + dwfl_end (dwfl); + kill (child, SIGKILL); + pid = waitpid (child, &status, 0); + assert_perror (errno); + assert (pid == child); + assert (WIFSIGNALED (status)); + assert (WTERMSIG (status) == SIGKILL); + + return EXIT_SUCCESS; +} + +#endif /* x86_64 */ diff --git a/tests/backtrace-dwarf.c b/tests/backtrace-dwarf.c new file mode 100644 index 0000000..92c892d --- /dev/null +++ b/tests/backtrace-dwarf.c @@ -0,0 +1,195 @@ +/* Test program for unwinding of complicated DWARF expressions. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include ELFUTILS_HEADER(dwfl) + +static void cleanup_13_abort (void); +#define main cleanup_13_main +#include "cleanup-13.c" +#undef main + +static void +report_pid (Dwfl *dwfl, pid_t pid) +{ + int result = dwfl_linux_proc_report (dwfl, pid); + if (result < 0) + error (2, 0, "dwfl_linux_proc_report: %s", dwfl_errmsg (-1)); + else if (result > 0) + error (2, result, "dwfl_linux_proc_report"); + + if (dwfl_report_end (dwfl, NULL, NULL) != 0) + error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1)); +} + +static Dwfl * +pid_to_dwfl (pid_t pid) +{ + static char *debuginfo_path; + static const Dwfl_Callbacks proc_callbacks = + { + .find_debuginfo = dwfl_standard_find_debuginfo, + .debuginfo_path = &debuginfo_path, + + .find_elf = dwfl_linux_proc_find_elf, + }; + Dwfl *dwfl = dwfl_begin (&proc_callbacks); + if (dwfl == NULL) + error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1)); + report_pid (dwfl, pid); + return dwfl; +} + +static const char *executable = "/proc/self/exe"; + +static int +find_elf (Dwfl_Module *mod, void **userdata, const char *modname, + Dwarf_Addr base, char **file_name, Elf **elfp) +{ + if (executable && modname != NULL + && (strcmp (modname, "[exe]") == 0 || strcmp (modname, "[pie]") == 0)) + { + char *executable_dup = strdup (executable); + if (executable_dup) + { + free (*file_name); + *file_name = executable_dup; + return -1; + } + } + return dwfl_build_id_find_elf (mod, userdata, modname, base, file_name, elfp); +} + +static Dwfl * +dwfl_offline (void) +{ + static char *debuginfo_path; + static const Dwfl_Callbacks offline_callbacks = + { + .find_debuginfo = dwfl_standard_find_debuginfo, + .debuginfo_path = &debuginfo_path, + + .section_address = dwfl_offline_section_address, + + /* We use this table for core files too. */ + .find_elf = find_elf, + }; + Dwfl *dwfl = dwfl_begin (&offline_callbacks); + if (dwfl == NULL) + error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1)); + return dwfl; +} + +static int +frame_callback (Dwfl_Frame *state, void *frame_arg) +{ + Dwarf_Addr pc; + bool isactivation; + if (! dwfl_frame_pc (state, &pc, &isactivation)) + { + error (0, 0, "%s", dwfl_errmsg (-1)); + return DWARF_CB_ABORT; + } + Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1); + + /* Get PC->SYMNAME. */ + Dwfl_Thread *thread = dwfl_frame_thread (state); + Dwfl *dwfl = dwfl_thread_dwfl (thread); + Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted); + const char *symname = NULL; + if (mod) + symname = dwfl_module_addrname (mod, pc_adjusted); + + printf ("%#" PRIx64 "\t%s\n", (uint64_t) pc, symname); + + if (symname && (strcmp (symname, "main") == 0 + || strcmp (symname, ".main") == 0)) + { + kill (dwfl_pid (dwfl), SIGKILL); + exit (0); + } + + return DWARF_CB_OK; +} + +static int +thread_callback (Dwfl_Thread *thread, void *thread_arg) +{ + dwfl_thread_getframes (thread, frame_callback, NULL); + error (1, 0, "dwfl_thread_getframes: %s", dwfl_errmsg (-1)); +} + +static void +ptrace_detach_stopped (pid_t pid) +{ + errno = 0; + long l = ptrace (PTRACE_DETACH, pid, NULL, (void *) (intptr_t) SIGSTOP); + assert_perror (errno); + assert (l == 0); +} + +int +main (int argc __attribute__ ((unused)), char **argv) +{ + /* We use no threads here which can interfere with handling a stream. */ + __fsetlocking (stdin, FSETLOCKING_BYCALLER); + __fsetlocking (stdout, FSETLOCKING_BYCALLER); + __fsetlocking (stderr, FSETLOCKING_BYCALLER); + + /* Set locale. */ + (void) setlocale (LC_ALL, ""); + + elf_version (EV_CURRENT); + + pid_t pid = fork (); + switch (pid) + { + case -1: + abort (); + case 0:; + long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); + assert_perror (errno); + assert (l == 0); + cleanup_13_main (); + abort (); + default: + break; + } + + errno = 0; + int status; + pid_t got = waitpid (pid, &status, 0); + assert_perror (errno); + assert (got == pid); + assert (WIFSTOPPED (status)); + assert (WSTOPSIG (status) == SIGABRT); + + ptrace_detach_stopped (pid); + + Dwfl *dwfl = pid_to_dwfl (pid); + dwfl_getthreads (dwfl, thread_callback, NULL); + + /* There is an exit (0) call if we find the "main" frame, */ + error (1, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1)); +} diff --git a/tests/backtrace-subr.sh b/tests/backtrace-subr.sh new file mode 100644 index 0000000..39d40b3 --- /dev/null +++ b/tests/backtrace-subr.sh @@ -0,0 +1,115 @@ +# Copyright (C) 2013 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/test-subr.sh + +# Verify one of the backtraced threads contains function 'main'. +check_main() +{ + if grep -w main $1; then + return + fi + echo >&2 $2: no main + false +} + +# Without proper ELF symbols resolution we could get inappropriate weak +# symbol "gsignal" with the same address as the correct symbol "raise". +# It was fixed by GIT commit 78dec228b3cfb2f9300cd0b682ebf416c9674c91 . +# [patch] Improve ELF symbols preference (global > weak) +# https://lists.fedorahosted.org/pipermail/elfutils-devel/2012-October/002624.html +check_gsignal() +{ + if ! grep -w gsignal $1; then + return + fi + echo >&2 $2: found gsignal + false +} + +# Verify the STDERR output does not contain unexpected errors. +# In some cases we cannot reliably find out we got behind _start as some +# operating system do not properly terminate CFI by undefined PC. +# Ignore it here as it is a bug of OS, not a bug of elfutils. +check_err() +{ + if [ $(egrep -v <$1 'dwfl_thread_getframes: (No DWARF information found|no matching address range)$' \ + | wc -c) \ + -eq 0 ] + then + return + fi + echo >&2 $2: neither empty nor just out of DWARF + false +} + +check_all() +{ + bt=$1 + err=$2 + testname=$3 + check_main $bt $testname + check_gsignal $bt $testname + check_err $err $testname +} + +check_unsupported() +{ + err=$1 + testname=$2 + if grep -q ': Unwinding not supported for this architecture$' $err; then + echo >&2 $testname: arch not supported + exit 77 + fi +} + +check_core() +{ + arch=$1 + testfiles backtrace.$arch.{exec,core} + tempfiles backtrace.$arch.{bt,err} + echo ./backtrace ./backtrace.$arch.{exec,core} + testrun ${abs_builddir}/backtrace -e ./backtrace.$arch.exec --core=./backtrace.$arch.core 1>backtrace.$arch.bt 2>backtrace.$arch.err || true + cat backtrace.$arch.{bt,err} + check_all backtrace.$arch.{bt,err} backtrace.$arch.core +} + +# Backtrace live process. +# Do not abort on non-zero exit code due to some warnings of ./backtrace +# - see function check_err. +check_native() +{ + child=$1 + tempfiles $child.{bt,err} + (set +ex; testrun ${abs_builddir}/backtrace --backtrace-exec=${abs_builddir}/$child 1>$child.bt 2>$child.err; true) + cat $child.{bt,err} + check_unsupported $child.err $child + check_all $child.{bt,err} $child +} + +# Backtrace core file. +check_native_core() +{ + child=$1 + core="core.`ulimit -c unlimited; set +ex; testrun ${abs_builddir}/$child --gencore; true`" + # Do not abort on non-zero exit code due to some warnings of ./backtrace + # - see function check_err. + tempfiles $core{,.{bt,err}} + (set +ex; testrun ${abs_builddir}/backtrace -e ${abs_builddir}/$child --core=$core 1>$core.bt 2>$core.err; true) + cat $core.{bt,err} + check_unsupported $core.err $child-$core + check_all $core.{bt,err} $child-$core +} diff --git a/tests/backtrace.c b/tests/backtrace.c new file mode 100644 index 0000000..06d3878 --- /dev/null +++ b/tests/backtrace.c @@ -0,0 +1,452 @@ +/* Test program for unwinding of frames. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include ELFUTILS_HEADER(dwfl) + +static int +dump_modules (Dwfl_Module *mod, void **userdata __attribute__ ((unused)), + const char *name, Dwarf_Addr start, + void *arg __attribute__ ((unused))) +{ + Dwarf_Addr end; + dwfl_module_info (mod, NULL, NULL, &end, NULL, NULL, NULL, NULL); + printf ("%#" PRIx64 "\t%#" PRIx64 "\t%s\n", (uint64_t) start, (uint64_t) end, + name); + return DWARF_CB_OK; +} + +static bool is_x86_64_native; +static pid_t check_tid; + +static void +callback_verify (pid_t tid, unsigned frameno, Dwarf_Addr pc, + const char *symname, Dwfl *dwfl) +{ + static bool seen_main = false; + if (symname && *symname == '.') + symname++; + if (symname && strcmp (symname, "main") == 0) + seen_main = true; + if (pc == 0) + { + assert (seen_main); + return; + } + if (check_tid == 0) + check_tid = tid; + if (tid != check_tid) + { + // For the main thread we are only interested if we can unwind till + // we see the "main" symbol. + return; + } + Dwfl_Module *mod; + static bool reduce_frameno = false; + if (reduce_frameno) + frameno--; + if (! is_x86_64_native && frameno >= 2) + frameno += 2; + const char *symname2 = NULL; + switch (frameno) + { + case 0: + if (! reduce_frameno && symname + && strcmp (symname, "__kernel_vsyscall") == 0) + reduce_frameno = true; + else + assert (symname && strcmp (symname, "raise") == 0); + break; + case 1: + assert (symname != NULL && strcmp (symname, "sigusr2") == 0); + break; + case 2: // x86_64 only + /* __restore_rt - glibc maybe does not have to have this symbol. */ + break; + case 3: // x86_64 only + if (is_x86_64_native) + { + /* Verify we trapped on the very first instruction of jmp. */ + assert (symname != NULL && strcmp (symname, "jmp") == 0); + mod = dwfl_addrmodule (dwfl, pc - 1); + if (mod) + symname2 = dwfl_module_addrname (mod, pc - 1); + assert (symname2 == NULL || strcmp (symname2, "jmp") != 0); + break; + } + /* PASSTHRU */ + case 4: + assert (symname != NULL && strcmp (symname, "stdarg") == 0); + break; + case 5: + /* Verify we trapped on the very last instruction of child. */ + assert (symname != NULL && strcmp (symname, "backtracegen") == 0); + mod = dwfl_addrmodule (dwfl, pc); + if (mod) + symname2 = dwfl_module_addrname (mod, pc); + assert (symname2 == NULL || strcmp (symname2, "backtracegen") != 0); + break; + } +} + +static int +frame_callback (Dwfl_Frame *state, void *frame_arg) +{ + int *framenop = frame_arg; + Dwarf_Addr pc; + bool isactivation; + if (! dwfl_frame_pc (state, &pc, &isactivation)) + { + error (0, 0, "%s", dwfl_errmsg (-1)); + return DWARF_CB_ABORT; + } + Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1); + + /* Get PC->SYMNAME. */ + Dwfl_Thread *thread = dwfl_frame_thread (state); + Dwfl *dwfl = dwfl_thread_dwfl (thread); + Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted); + const char *symname = NULL; + if (mod) + symname = dwfl_module_addrname (mod, pc_adjusted); + + printf ("#%2d %#" PRIx64 "%4s\t%s\n", *framenop, (uint64_t) pc, + ! isactivation ? "- 1" : "", symname); + pid_t tid = dwfl_thread_tid (thread); + callback_verify (tid, *framenop, pc, symname, dwfl); + (*framenop)++; + + return DWARF_CB_OK; +} + +static int +thread_callback (Dwfl_Thread *thread, void *thread_arg __attribute__((unused))) +{ + printf ("TID %ld:\n", (long) dwfl_thread_tid (thread)); + int frameno = 0; + switch (dwfl_thread_getframes (thread, frame_callback, &frameno)) + { + case 0: + break; + case DWARF_CB_ABORT: + return DWARF_CB_ABORT; + case -1: + error (0, 0, "dwfl_thread_getframes: %s", dwfl_errmsg (-1)); + /* All platforms do not have yet proper unwind termination. */ + break; + default: + abort (); + } + return DWARF_CB_OK; +} + +static void +dump (Dwfl *dwfl) +{ + ptrdiff_t ptrdiff = dwfl_getmodules (dwfl, dump_modules, NULL, 0); + assert (ptrdiff == 0); + bool err = false; + switch (dwfl_getthreads (dwfl, thread_callback, NULL)) + { + case 0: + break; + case DWARF_CB_ABORT: + err = true; + break; + case -1: + error (0, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1)); + err = true; + break; + default: + abort (); + } + callback_verify (0, 0, 0, NULL, dwfl); + if (err) + exit (EXIT_FAILURE); +} + +struct see_exec_module +{ + Dwfl_Module *mod; + char selfpath[PATH_MAX + 1]; +}; + +static int +see_exec_module (Dwfl_Module *mod, void **userdata __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + Dwarf_Addr start __attribute__ ((unused)), void *arg) +{ + struct see_exec_module *data = arg; + if (strcmp (name, data->selfpath) != 0) + return DWARF_CB_OK; + assert (data->mod == NULL); + data->mod = mod; + return DWARF_CB_OK; +} + +/* On x86_64 only: + PC will get changed to function 'jmp' by backtrace.c function + prepare_thread. Then SIGUSR2 will be signalled to backtrace-child + which will invoke function sigusr2. + This is all done so that signal interrupts execution of the very first + instruction of a function. Properly handled unwind should not slip into + the previous unrelated function. */ + +static void +prepare_thread (pid_t pid2 __attribute__ ((unused)), + void (*jmp) (void) __attribute__ ((unused))) +{ +#ifndef __x86_64__ + abort (); +#else /* x86_64 */ + long l; + errno = 0; + l = ptrace (PTRACE_POKEUSER, pid2, + (void *) (intptr_t) offsetof (struct user_regs_struct, rip), jmp); + assert_perror (errno); + assert (l == 0); + l = ptrace (PTRACE_CONT, pid2, NULL, (void *) (intptr_t) SIGUSR2); + int status; + pid_t got = waitpid (pid2, &status, __WALL); + assert_perror (errno); + assert (got == pid2); + assert (WIFSTOPPED (status)); + assert (WSTOPSIG (status) == SIGUSR1); +#endif /* __x86_64__ */ +} + +#include +#include +#define tgkill(pid, tid, sig) syscall (__NR_tgkill, (pid), (tid), (sig)) + +static void +ptrace_detach_stopped (pid_t pid) +{ + errno = 0; + long l = ptrace (PTRACE_DETACH, pid, NULL, (void *) (intptr_t) SIGSTOP); + assert_perror (errno); + assert (l == 0); +} + +static void +report_pid (Dwfl *dwfl, pid_t pid) +{ + int result = dwfl_linux_proc_report (dwfl, pid); + if (result < 0) + error (2, 0, "dwfl_linux_proc_report: %s", dwfl_errmsg (-1)); + else if (result > 0) + error (2, result, "dwfl_linux_proc_report"); + + if (dwfl_report_end (dwfl, NULL, NULL) != 0) + error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1)); +} + +static Dwfl * +pid_to_dwfl (pid_t pid) +{ + static char *debuginfo_path; + static const Dwfl_Callbacks proc_callbacks = + { + .find_debuginfo = dwfl_standard_find_debuginfo, + .debuginfo_path = &debuginfo_path, + + .find_elf = dwfl_linux_proc_find_elf, + }; + Dwfl *dwfl = dwfl_begin (&proc_callbacks); + if (dwfl == NULL) + error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1)); + report_pid (dwfl, pid); + return dwfl; +} + +static void +exec_dump (const char *exec) +{ + pid_t pid = fork (); + switch (pid) + { + case -1: + abort (); + case 0: + execl (exec, exec, "--ptraceme", NULL); + abort (); + default: + break; + } + + /* Catch the main thread. Catch it first otherwise the /proc evaluation of + PID may have caught still ourselves before executing execl above. */ + errno = 0; + int status; + pid_t got = waitpid (pid, &status, 0); + assert_perror (errno); + assert (got == pid); + assert (WIFSTOPPED (status)); + // Main thread will signal SIGUSR2. Other thread will signal SIGUSR1. + assert (WSTOPSIG (status) == SIGUSR2); + + /* Catch the spawned thread. Do not use __WCLONE as we could get racy + __WCLONE, probably despite pthread_create already had to be called the new + task is not yet alive enough for waitpid. */ + pid_t pid2 = waitpid (-1, &status, __WALL); + assert_perror (errno); + assert (pid2 > 0); + assert (pid2 != pid); + assert (WIFSTOPPED (status)); + // Main thread will signal SIGUSR2. Other thread will signal SIGUSR1. + assert (WSTOPSIG (status) == SIGUSR1); + + Dwfl *dwfl = pid_to_dwfl (pid); + char *selfpathname; + int i = asprintf (&selfpathname, "/proc/%ld/exe", (long) pid); + assert (i > 0); + struct see_exec_module data; + ssize_t ssize = readlink (selfpathname, data.selfpath, + sizeof (data.selfpath)); + free (selfpathname); + assert (ssize > 0 && ssize < (ssize_t) sizeof (data.selfpath)); + data.selfpath[ssize] = '\0'; + data.mod = NULL; + ptrdiff_t ptrdiff = dwfl_getmodules (dwfl, see_exec_module, &data, 0); + assert (ptrdiff == 0); + assert (data.mod != NULL); + GElf_Addr loadbase; + Elf *elf = dwfl_module_getelf (data.mod, &loadbase); + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + assert (ehdr != NULL); + /* It is false also on x86_64 with i386 inferior. */ +#ifndef __x86_64__ + is_x86_64_native = false; +#else /* __x86_64__ */ + is_x86_64_native = ehdr->e_ident[EI_CLASS] == ELFCLASS64; +#endif /* __x86_64__ */ + void (*jmp) (void); + if (is_x86_64_native) + { + // Find inferior symbol named "jmp". + int nsym = dwfl_module_getsymtab (data.mod); + int symi; + for (symi = 1; symi < nsym; ++symi) + { + GElf_Sym symbol; + const char *symbol_name = dwfl_module_getsym (data.mod, symi, &symbol, NULL); + if (symbol_name == NULL) + continue; + switch (GELF_ST_TYPE (symbol.st_info)) + { + case STT_SECTION: + case STT_FILE: + case STT_TLS: + continue; + default: + if (strcmp (symbol_name, "jmp") != 0) + continue; + break; + } + /* LOADBASE is already applied here. */ + jmp = (void (*) (void)) (uintptr_t) symbol.st_value; + break; + } + assert (symi < nsym); + prepare_thread (pid2, jmp); + } + dwfl_end (dwfl); + ptrace_detach_stopped (pid); + ptrace_detach_stopped (pid2); + check_tid = pid2; + dwfl = pid_to_dwfl (pid); + dump (dwfl); + dwfl_end (dwfl); +} + +#define OPT_BACKTRACE_EXEC 0x100 + +static const struct argp_option options[] = + { + { "backtrace-exec", OPT_BACKTRACE_EXEC, "EXEC", 0, N_("Run executable"), 0 }, + { NULL, 0, NULL, 0, NULL, 0 } + }; + + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case ARGP_KEY_INIT: + state->child_inputs[0] = state->input; + break; + + case OPT_BACKTRACE_EXEC: + exec_dump (arg); + exit (0); + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +int +main (int argc __attribute__ ((unused)), char **argv) +{ + /* We use no threads here which can interfere with handling a stream. */ + __fsetlocking (stdin, FSETLOCKING_BYCALLER); + __fsetlocking (stdout, FSETLOCKING_BYCALLER); + __fsetlocking (stderr, FSETLOCKING_BYCALLER); + + /* Set locale. */ + (void) setlocale (LC_ALL, ""); + + elf_version (EV_CURRENT); + + Dwfl *dwfl = NULL; + const struct argp_child argp_children[] = + { + { .argp = dwfl_standard_argp () }, + { .argp = NULL } + }; + const struct argp argp = + { + options, parse_opt, NULL, NULL, argp_children, NULL, NULL + }; + (void) argp_parse (&argp, argc, argv, 0, NULL, &dwfl); + assert (dwfl != NULL); + dump (dwfl); + dwfl_end (dwfl); + return 0; +} diff --git a/tests/backtrace.i386.core.bz2 b/tests/backtrace.i386.core.bz2 new file mode 100644 index 0000000..e120d9b Binary files /dev/null and b/tests/backtrace.i386.core.bz2 differ diff --git a/tests/backtrace.i386.exec.bz2 b/tests/backtrace.i386.exec.bz2 new file mode 100644 index 0000000..1b0f001 Binary files /dev/null and b/tests/backtrace.i386.exec.bz2 differ diff --git a/tests/backtrace.x86_64.core.bz2 b/tests/backtrace.x86_64.core.bz2 new file mode 100644 index 0000000..1f34e20 Binary files /dev/null and b/tests/backtrace.x86_64.core.bz2 differ diff --git a/tests/backtrace.x86_64.exec.bz2 b/tests/backtrace.x86_64.exec.bz2 new file mode 100644 index 0000000..70a151b Binary files /dev/null and b/tests/backtrace.x86_64.exec.bz2 differ diff --git a/tests/cleanup-13.c b/tests/cleanup-13.c new file mode 100644 index 0000000..b87c696 --- /dev/null +++ b/tests/cleanup-13.c @@ -0,0 +1,334 @@ +// http://gcc.gnu.org/viewcvs/gcc/trunk/gcc/testsuite/gcc.dg/cleanup-13.c?view=co&content-type=text%2Fplain + +/* HP-UX libunwind.so doesn't provide _UA_END_OF_STACK */ +/* { dg-do run } */ +/* { dg-options "-fexceptions" } */ +/* { dg-skip-if "" { "ia64-*-hpux11.*" } { "*" } { "" } } */ +/* Verify DW_OP_* handling in the unwinder. */ + +#include +#include +#include + +/* #define OP_addr(x) 0x06, ... */ +#define OP_deref 0x06, +#define SLEB128(x) (x)&0x7f /* Assume here the value is -0x40 ... 0x3f. */ +#define ULEB128(x) (x)&0x7f /* Assume here the value is 0 ... 0x7f. */ +#define VAL1(x) (x)&0xff +#if defined (__BIG_ENDIAN__) +#define VAL2(x) ((x)>>8)&0xff,(x)&0xff +#define VAL4(x) ((x)>>24)&0xff,((x)>>16)&0xff,((x)>>8)&0xff,(x)&0xff +#define VAL8(x) ((x)>>56)&0xff,((x)>>48)&0xff,((x)>>40)&0xff,((x)>>32)&0xff,((x)>>24)&0xff,((x)>>16)&0xff,((x)>>8)&0xff,(x)&0xff +#elif defined(__LITTLE_ENDIAN__) || defined(__x86_64__) || defined(__i386__) +#define VAL2(x) (x)&0xff,((x)>>8)&0xff +#define VAL4(x) (x)&0xff,((x)>>8)&0xff,((x)>>16)&0xff,((x)>>24)&0xff +#define VAL8(x) (x)&0xff,((x)>>8)&0xff,((x)>>16)&0xff,((x)>>24)&0xff,((x)>>32)&0xff,((x)>>40)&0xff,((x)>>48)&0xff,((x)>>56)&0xff +#endif +#define OP_const1u(x) 0x08,VAL1(x), +#define OP_const1s(x) 0x09,VAL1(x), +#define OP_const2u(x) 0x0a,VAL2(x), +#define OP_const2s(x) 0x0b,VAL2(x), +#define OP_const4u(x) 0x0c,VAL4(x), +#define OP_const4s(x) 0x0d,VAL4(x), +#define OP_const8u(x) 0x0e,VAL8(x), +#define OP_const8s(x) 0x0f,VAL8(x), +#define OP_constu(x) 0x10,ULEB128(x), +#define OP_consts(x) 0x11,SLEB128(x), +#define OP_dup 0x12, +#define OP_drop 0x13, +#define OP_over 0x14, +#define OP_pick(x) 0x15,VAL1(x), +#define OP_swap 0x16, +#define OP_rot 0x17, +#define OP_xderef 0x18, +#define OP_abs 0x19, +#define OP_and 0x1a, +#define OP_div 0x1b, +#define OP_minus 0x1c, +#define OP_mod 0x1d, +#define OP_mul 0x1e, +#define OP_neg 0x1f, +#define OP_not 0x20, +#define OP_or 0x21, +#define OP_plus 0x22, +#define OP_plus_uconst(x) 0x23,ULEB128(x), +#define OP_shl 0x24, +#define OP_shr 0x25, +#define OP_shra 0x26, +#define OP_xor 0x27, +#define OP_bra(x) 0x28,VAL2(x), +#define OP_eq 0x29, +#define OP_ge 0x2a, +#define OP_gt 0x2b, +#define OP_le 0x2c, +#define OP_lt 0x2d, +#define OP_ne 0x2e, +#define OP_skip(x) 0x2f,VAL2(x), +#define OP_lit0 0x30, +#define OP_lit1 0x31, +#define OP_lit2 0x32, +#define OP_lit3 0x33, +#define OP_lit4 0x34, +#define OP_lit5 0x35, +#define OP_lit6 0x36, +#define OP_lit7 0x37, +#define OP_lit8 0x38, +#define OP_lit9 0x39, +#define OP_lit10 0x3a, +#define OP_lit11 0x3b, +#define OP_lit12 0x3c, +#define OP_lit13 0x3d, +#define OP_lit14 0x3e, +#define OP_lit15 0x3f, +#define OP_lit16 0x40, +#define OP_lit17 0x41, +#define OP_lit18 0x42, +#define OP_lit19 0x43, +#define OP_lit20 0x44, +#define OP_lit21 0x45, +#define OP_lit22 0x46, +#define OP_lit23 0x47, +#define OP_lit24 0x48, +#define OP_lit25 0x49, +#define OP_lit26 0x4a, +#define OP_lit27 0x4b, +#define OP_lit28 0x4c, +#define OP_lit29 0x4d, +#define OP_lit30 0x4e, +#define OP_lit31 0x4f, +#define OP_reg0 0x50, +#define OP_reg1 0x51, +#define OP_reg2 0x52, +#define OP_reg3 0x53, +#define OP_reg4 0x54, +#define OP_reg5 0x55, +#define OP_reg6 0x56, +#define OP_reg7 0x57, +#define OP_reg8 0x58, +#define OP_reg9 0x59, +#define OP_reg10 0x5a, +#define OP_reg11 0x5b, +#define OP_reg12 0x5c, +#define OP_reg13 0x5d, +#define OP_reg14 0x5e, +#define OP_reg15 0x5f, +#define OP_reg16 0x60, +#define OP_reg17 0x61, +#define OP_reg18 0x62, +#define OP_reg19 0x63, +#define OP_reg20 0x64, +#define OP_reg21 0x65, +#define OP_reg22 0x66, +#define OP_reg23 0x67, +#define OP_reg24 0x68, +#define OP_reg25 0x69, +#define OP_reg26 0x6a, +#define OP_reg27 0x6b, +#define OP_reg28 0x6c, +#define OP_reg29 0x6d, +#define OP_reg30 0x6e, +#define OP_reg31 0x6f, +#define OP_breg0(x) 0x70,SLEB128(x), +#define OP_breg1(x) 0x71,SLEB128(x), +#define OP_breg2(x) 0x72,SLEB128(x), +#define OP_breg3(x) 0x73,SLEB128(x), +#define OP_breg4(x) 0x74,SLEB128(x), +#define OP_breg5(x) 0x75,SLEB128(x), +#define OP_breg6(x) 0x76,SLEB128(x), +#define OP_breg7(x) 0x77,SLEB128(x), +#define OP_breg8(x) 0x78,SLEB128(x), +#define OP_breg9(x) 0x79,SLEB128(x), +#define OP_breg10(x) 0x7a,SLEB128(x), +#define OP_breg11(x) 0x7b,SLEB128(x), +#define OP_breg12(x) 0x7c,SLEB128(x), +#define OP_breg13(x) 0x7d,SLEB128(x), +#define OP_breg14(x) 0x7e,SLEB128(x), +#define OP_breg15(x) 0x7f,SLEB128(x), +#define OP_breg16(x) 0x80,SLEB128(x), +#define OP_breg17(x) 0x81,SLEB128(x), +#define OP_breg18(x) 0x82,SLEB128(x), +#define OP_breg19(x) 0x83,SLEB128(x), +#define OP_breg20(x) 0x84,SLEB128(x), +#define OP_breg21(x) 0x85,SLEB128(x), +#define OP_breg22(x) 0x86,SLEB128(x), +#define OP_breg23(x) 0x87,SLEB128(x), +#define OP_breg24(x) 0x88,SLEB128(x), +#define OP_breg25(x) 0x89,SLEB128(x), +#define OP_breg26(x) 0x8a,SLEB128(x), +#define OP_breg27(x) 0x8b,SLEB128(x), +#define OP_breg28(x) 0x8c,SLEB128(x), +#define OP_breg29(x) 0x8d,SLEB128(x), +#define OP_breg30(x) 0x8e,SLEB128(x), +#define OP_breg31(x) 0x8f,SLEB128(x), +#define OP_regx(x) 0x90,SLEB128(x), +#define OP_fbreg(x) 0x91,SLEB128(x), +#define OP_bregx(x,y) 0x92,ULEB128(x),SLEB128(y), +#define OP_piece(x) 0x93,ULEB128(x), +#define OP_deref_size(x) 0x94,VAL1(x), +#define OP_xderef_size(x) 0x95,VAL1(x), +#define OP_nop 0x96, +#define OP_nop_termination 0x96 +#define OP_push_object_address 0x97, +#define OP_call2(x) 0x98,VAL2(x), +#define OP_call4(x) 0x99,VAL4(x), +/* #define OP_call_ref(x) 0x9a,... */ +#define OP_form_tls_address(x) 0x9b, +#define OP_call_frame_cfa 0x9c, +#define OP_bit_piece(x) 0x9d,ULEB128(x), +/* #define OP_implicit_value(x...) 0x9e,... */ +#define OP_stack_value 0x9f, +#define OP_GNU_push_tls_address 0xe0, +/* #define OP_GNU_encoded_addr(x...) 0xf1, */ + +#define ASSERT_TOS_NON0 OP_bra(3) OP_skip(-3) +#define ASSERT_TOS_0 OP_lit0 OP_eq ASSERT_TOS_NON0 + +/* Initially there is CFA value on the stack, we want to + keep it there at the end. */ +#define CFI_PROGRAM \ +OP_lit0 OP_nop ASSERT_TOS_0 \ +OP_lit1 ASSERT_TOS_NON0 \ +OP_lit1 OP_const1u(1) OP_eq ASSERT_TOS_NON0 \ +OP_lit16 OP_const2u(16) OP_eq ASSERT_TOS_NON0 \ +OP_lit31 OP_const4u(31) OP_ne ASSERT_TOS_0 \ +OP_lit1 OP_neg OP_const1s(-1) OP_eq ASSERT_TOS_NON0 \ +OP_lit16 OP_neg OP_const2s(-16) OP_ne ASSERT_TOS_0 \ +OP_lit31 OP_const4s(-31) OP_neg OP_ne ASSERT_TOS_0 \ +OP_lit7 OP_dup OP_plus_uconst(2) OP_lit9 OP_eq ASSERT_TOS_NON0 \ + OP_lit7 OP_eq ASSERT_TOS_NON0 \ +OP_lit20 OP_lit1 OP_drop OP_lit20 OP_eq ASSERT_TOS_NON0 \ +OP_lit17 OP_lit19 OP_over OP_lit17 OP_eq ASSERT_TOS_NON0 \ + OP_lit19 OP_eq ASSERT_TOS_NON0 OP_lit17 OP_eq ASSERT_TOS_NON0 \ +OP_lit1 OP_lit2 OP_lit3 OP_lit4 OP_pick(2) OP_lit2 OP_eq ASSERT_TOS_NON0\ + OP_lit4 OP_eq ASSERT_TOS_NON0 OP_lit3 OP_eq ASSERT_TOS_NON0 \ + OP_pick(0) OP_lit2 OP_eq ASSERT_TOS_NON0 \ + OP_lit2 OP_eq ASSERT_TOS_NON0 OP_lit1 OP_eq ASSERT_TOS_NON0 \ +OP_lit6 OP_lit12 OP_swap OP_lit6 OP_eq ASSERT_TOS_NON0 \ + OP_lit12 OP_eq ASSERT_TOS_NON0 \ +OP_lit7 OP_lit8 OP_lit9 OP_rot OP_lit8 OP_eq ASSERT_TOS_NON0 \ + OP_lit7 OP_eq ASSERT_TOS_NON0 OP_lit9 OP_eq ASSERT_TOS_NON0 \ +OP_lit7 OP_abs OP_lit7 OP_eq ASSERT_TOS_NON0 \ +OP_const1s(-123) OP_abs OP_const1u(123) OP_eq ASSERT_TOS_NON0 \ +OP_lit3 OP_lit6 OP_and OP_lit2 OP_eq ASSERT_TOS_NON0 \ +OP_lit3 OP_lit6 OP_or OP_lit7 OP_eq ASSERT_TOS_NON0 \ +OP_lit17 OP_lit2 OP_minus OP_lit15 OP_eq ASSERT_TOS_NON0 \ +/* Divide is signed truncating toward zero. */ \ +OP_const1s(-6) OP_const1s(-2) OP_div OP_lit3 OP_eq ASSERT_TOS_NON0 \ +OP_const1s(-7) OP_const1s(3) OP_div OP_const1s(-2) \ + OP_eq ASSERT_TOS_NON0 \ +/* Modulo is unsigned. */ \ +OP_const1s(-6) OP_const1s(-4) OP_mod OP_const1s(-6) \ + OP_eq ASSERT_TOS_NON0 \ +OP_const1s(-6) OP_lit4 OP_mod OP_lit2 OP_eq ASSERT_TOS_NON0 \ +OP_lit6 OP_const1s(-4) OP_mod OP_lit6 OP_eq ASSERT_TOS_NON0 \ +/* Signed modulo can be implemented using "over over div mul minus". */\ +OP_const1s(-6) OP_const1s(-4) OP_over OP_over OP_div OP_mul OP_minus \ + OP_const1s(-2) OP_eq ASSERT_TOS_NON0 \ +OP_const1s(-7) OP_lit3 OP_over OP_over OP_div OP_mul OP_minus \ + OP_const1s(-1) OP_eq ASSERT_TOS_NON0 \ +OP_lit7 OP_const1s(-3) OP_over OP_over OP_div OP_mul OP_minus \ + OP_lit1 OP_eq ASSERT_TOS_NON0 \ +OP_lit16 OP_lit31 OP_plus_uconst(1) OP_mul OP_const2u(512) \ + OP_eq ASSERT_TOS_NON0 \ +OP_lit5 OP_not OP_lit31 OP_and OP_lit26 OP_eq ASSERT_TOS_NON0 \ +OP_lit12 OP_lit31 OP_plus OP_const1u(43) OP_eq ASSERT_TOS_NON0 \ +OP_const1s(-6) OP_lit2 OP_plus OP_const1s(-4) OP_eq ASSERT_TOS_NON0 \ +OP_const1s(-6) OP_plus_uconst(3) OP_const1s(-3) OP_eq ASSERT_TOS_NON0 \ +OP_lit16 OP_lit4 OP_shl OP_const2u(256) OP_eq ASSERT_TOS_NON0 \ +OP_lit16 OP_lit3 OP_shr OP_lit2 OP_eq ASSERT_TOS_NON0 \ +OP_const1s(-16) OP_lit3 OP_shra OP_const1s(-2) OP_eq ASSERT_TOS_NON0 \ +OP_lit3 OP_lit6 OP_xor OP_lit5 OP_eq ASSERT_TOS_NON0 \ +OP_lit3 OP_lit6 OP_le ASSERT_TOS_NON0 \ +OP_lit3 OP_lit3 OP_le ASSERT_TOS_NON0 \ +OP_lit6 OP_lit3 OP_le ASSERT_TOS_0 \ +OP_lit3 OP_lit6 OP_lt ASSERT_TOS_NON0 \ +OP_lit3 OP_lit3 OP_lt ASSERT_TOS_0 \ +OP_lit6 OP_lit3 OP_lt ASSERT_TOS_0 \ +OP_lit3 OP_lit6 OP_ge ASSERT_TOS_0 \ +OP_lit3 OP_lit3 OP_ge ASSERT_TOS_NON0 \ +OP_lit6 OP_lit3 OP_ge ASSERT_TOS_NON0 \ +OP_lit3 OP_lit6 OP_gt ASSERT_TOS_0 \ +OP_lit3 OP_lit3 OP_gt ASSERT_TOS_0 \ +OP_lit6 OP_lit3 OP_gt ASSERT_TOS_NON0 \ +OP_const1s(-6) OP_lit1 OP_shr OP_lit0 OP_gt ASSERT_TOS_NON0 \ +OP_const1s(-6) OP_lit1 OP_shra OP_lit0 OP_lt ASSERT_TOS_NON0 + +#define CFI_ESCAPE_VAL_2(VALUES...) #VALUES +#define CFI_ESCAPE_VAL_1(VALUES...) CFI_ESCAPE_VAL_2(VALUES) +#define CFI_ESCAPE_VAL(VALUES...) CFI_ESCAPE_VAL_1(VALUES) +#define CFI_ESCAPE do { } while (0) +#define CFI_ARCH_PROGRAM OP_nop_termination +#ifdef __GCC_HAVE_DWARF2_CFI_ASM +#if defined (__x86_64__) +#undef CFI_ESCAPE +#undef CFI_ARCH_PROGRAM +#define CFI_ARCH_PROGRAM CFI_PROGRAM OP_lit8 OP_minus OP_nop_termination +unsigned char cfi_arch_program[] = { CFI_ARCH_PROGRAM }; +extern char verify_it[sizeof (cfi_arch_program) - 0x80 < 0x3f80 ? 1 : -1]; +/* DW_CFA_expression %rip, uleb128(l2-l1), l1: program DW_OP_lit8 DW_OP_minus DW_OP_nop l2: */ +#define CFI_ESCAPE \ + asm volatile (".cfi_escape 0x10, 0x10, (%P0&0x7f)+0x80, %P0>>7, " \ + CFI_ESCAPE_VAL (CFI_ARCH_PROGRAM) \ + : : "i" (sizeof (cfi_arch_program))) +#elif defined (__i386__) +#undef CFI_ESCAPE +#undef CFI_ARCH_PROGRAM +#define CFI_ARCH_PROGRAM CFI_PROGRAM OP_lit4 OP_minus OP_nop_termination +unsigned char cfi_arch_program[] = { CFI_ARCH_PROGRAM }; +extern char verify_it[sizeof (cfi_arch_program) - 0x80 < 0x3f80 ? 1 : -1]; +/* DW_CFA_expression %eip, uleb128(l2-l1), l1: program DW_OP_lit4 DW_OP_minus DW_OP_nop l2: */ +#define CFI_ESCAPE \ + asm volatile (".cfi_escape 0x10, 8, (%P0&0x7f)+0x80, %P0>>7, " \ + CFI_ESCAPE_VAL (CFI_ARCH_PROGRAM) \ + : : "i" (sizeof (cfi_arch_program))) +#endif +#endif +static _Unwind_Reason_Code +force_unwind_stop (int version, _Unwind_Action actions, + _Unwind_Exception_Class exc_class, + struct _Unwind_Exception *exc_obj, + struct _Unwind_Context *context, + void *stop_parameter) +{ + if (actions & _UA_END_OF_STACK) + abort (); + return _URC_NO_REASON; +} + +static void force_unwind () +{ + struct _Unwind_Exception *exc = malloc (sizeof (*exc)); + memset (&exc->exception_class, 0, sizeof (exc->exception_class)); + exc->exception_cleanup = 0; + +#ifndef __USING_SJLJ_EXCEPTIONS__ + _Unwind_ForcedUnwind (exc, force_unwind_stop, 0); +#else + _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0); +#endif + + abort (); +} + +static void handler (void *p __attribute__((unused))) +{ + exit (0); +} + +__attribute__((noinline)) static void callme () +{ + CFI_ESCAPE; + force_unwind (); +} + +__attribute__((noinline)) static void doit () +{ + char dummy __attribute__((cleanup (handler))); + callme (); +} + +int main() +{ + doit (); + abort (); +} diff --git a/tests/run-backtrace-core-i386.sh b/tests/run-backtrace-core-i386.sh new file mode 100755 index 0000000..7294ec3 --- /dev/null +++ b/tests/run-backtrace-core-i386.sh @@ -0,0 +1,20 @@ +#! /bin/bash +# Copyright (C) 2013 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/backtrace-subr.sh + +check_core i386 diff --git a/tests/run-backtrace-core-x86_64.sh b/tests/run-backtrace-core-x86_64.sh new file mode 100755 index 0000000..d00cd6d --- /dev/null +++ b/tests/run-backtrace-core-x86_64.sh @@ -0,0 +1,20 @@ +#! /bin/bash +# Copyright (C) 2013 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/backtrace-subr.sh + +check_core x86_64 diff --git a/tests/run-backtrace-data.sh b/tests/run-backtrace-data.sh new file mode 100755 index 0000000..30127c3 --- /dev/null +++ b/tests/run-backtrace-data.sh @@ -0,0 +1,24 @@ +#! /bin/bash +# Copyright (C) 2013 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/backtrace-subr.sh + +tempfiles data.{bt,err} +(set +ex; testrun ${abs_builddir}/backtrace-data 1>data.bt 2>data.err; true) +cat data.{bt,err} +check_unsupported data.err data +check_all data.{bt,err} data diff --git a/tests/run-backtrace-dwarf.sh b/tests/run-backtrace-dwarf.sh new file mode 100755 index 0000000..b24215e --- /dev/null +++ b/tests/run-backtrace-dwarf.sh @@ -0,0 +1,20 @@ +#! /bin/bash +# Copyright (C) 2013 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/test-subr.sh + +testrun ${abs_builddir}/backtrace-dwarf diff --git a/tests/run-backtrace-native-biarch.sh b/tests/run-backtrace-native-biarch.sh new file mode 100755 index 0000000..3a407c8 --- /dev/null +++ b/tests/run-backtrace-native-biarch.sh @@ -0,0 +1,24 @@ +#! /bin/bash +# Copyright (C) 2013 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +if test -n "$ELFUTILS_DISABLE_BIARCH"; then + exit 77 +fi + +. $srcdir/backtrace-subr.sh + +check_native backtrace-child-biarch diff --git a/tests/run-backtrace-native-core-biarch.sh b/tests/run-backtrace-native-core-biarch.sh new file mode 100755 index 0000000..fbd8025 --- /dev/null +++ b/tests/run-backtrace-native-core-biarch.sh @@ -0,0 +1,24 @@ +#! /bin/bash +# Copyright (C) 2013 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +if test -n "$ELFUTILS_DISABLE_BIARCH"; then + exit 77 +fi + +. $srcdir/backtrace-subr.sh + +check_native_core backtrace-child-biarch diff --git a/tests/run-backtrace-native-core.sh b/tests/run-backtrace-native-core.sh new file mode 100755 index 0000000..cb025a5 --- /dev/null +++ b/tests/run-backtrace-native-core.sh @@ -0,0 +1,20 @@ +#! /bin/bash +# Copyright (C) 2013 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/backtrace-subr.sh + +check_native_core backtrace-child diff --git a/tests/run-backtrace-native.sh b/tests/run-backtrace-native.sh new file mode 100755 index 0000000..ddae345 --- /dev/null +++ b/tests/run-backtrace-native.sh @@ -0,0 +1,20 @@ +#! /bin/bash +# Copyright (C) 2013 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/backtrace-subr.sh + +check_native backtrace-child