Author: Daniel Kiss Date: 2020-09-16T23:53:36+02:00 New Revision: 23bef7ee9923b1262326981960397e8cd95d6923
URL: https://github.com/llvm/llvm-project/commit/23bef7ee9923b1262326981960397e8cd95d6923 DIFF: https://github.com/llvm/llvm-project/commit/23bef7ee9923b1262326981960397e8cd95d6923.diff LOG: [libunwind] Support for leaf function unwinding. Unwinding leaf function is useful in cases when the backtrace finds a leaf function for example when it caused a signal. This patch also add the support for the DW_CFA_undefined because it marks the end of the frames. Ryan Prichard provided code for the tests. Reviewed By: #libunwind, mstorsjo Differential Revision: https://reviews.llvm.org/D83573 Added: libunwind/test/signal_unwind.pass.cpp libunwind/test/unwind_leaffunction.pass.cpp Modified: libunwind/src/DwarfInstructions.hpp libunwind/src/DwarfParser.hpp libunwind/test/lit.site.cfg.in Removed: ################################################################################ diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp index ee98f538d437..c39cabe1f783 100644 --- a/libunwind/src/DwarfInstructions.hpp +++ b/libunwind/src/DwarfInstructions.hpp @@ -93,7 +93,8 @@ typename A::pint_t DwarfInstructions<A, R>::getSavedRegister( case CFI_Parser<A>::kRegisterInRegister: return registers.getRegister((int)savedReg.value); - + case CFI_Parser<A>::kRegisterUndefined: + return 0; case CFI_Parser<A>::kRegisterUnused: case CFI_Parser<A>::kRegisterOffsetFromCFA: // FIX ME @@ -117,6 +118,7 @@ double DwarfInstructions<A, R>::getSavedFloatRegister( case CFI_Parser<A>::kRegisterIsExpression: case CFI_Parser<A>::kRegisterUnused: + case CFI_Parser<A>::kRegisterUndefined: case CFI_Parser<A>::kRegisterOffsetFromCFA: case CFI_Parser<A>::kRegisterInRegister: // FIX ME @@ -140,6 +142,7 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister( case CFI_Parser<A>::kRegisterIsExpression: case CFI_Parser<A>::kRegisterUnused: + case CFI_Parser<A>::kRegisterUndefined: case CFI_Parser<A>::kRegisterOffsetFromCFA: case CFI_Parser<A>::kRegisterInRegister: // FIX ME @@ -190,6 +193,10 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, prolog.savedRegisters[i])); else return UNW_EBADREG; + } else if (i == (int)cieInfo.returnAddressRegister) { + // Leaf function keeps the return address in register and there is no + // explicit intructions how to restore it. + returnAddress = registers.getRegister(cieInfo.returnAddressRegister); } } diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp index c98c4f92a6ad..1ce2cf2943a2 100644 --- a/libunwind/src/DwarfParser.hpp +++ b/libunwind/src/DwarfParser.hpp @@ -69,6 +69,7 @@ class CFI_Parser { }; enum RegisterSavedWhere { kRegisterUnused, + kRegisterUndefined, kRegisterInCFA, kRegisterOffsetFromCFA, kRegisterInRegister, @@ -503,7 +504,7 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions, "malformed DW_CFA_undefined DWARF unwind, reg too big"); return false; } - results->setRegisterLocation(reg, kRegisterUnused, initialState); + results->setRegisterLocation(reg, kRegisterUndefined, initialState); _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); break; case DW_CFA_same_value: diff --git a/libunwind/test/lit.site.cfg.in b/libunwind/test/lit.site.cfg.in index 8ff770fe29bc..84dae3c2bfb0 100644 --- a/libunwind/test/lit.site.cfg.in +++ b/libunwind/test/lit.site.cfg.in @@ -44,6 +44,10 @@ config.test_source_root = os.path.join(config.libunwind_src_root, 'test') # Allow expanding substitutions that are based on other substitutions config.recursiveExpansionLimit = 10 +# Make symbols available in the tests. +config.test_compiler_flags += " -funwind-tables " +config.test_linker_flags += " -Wl,--export-dynamic " + # Infer the test_exec_root from the build directory. config.test_exec_root = os.path.join(config.libunwind_obj_root, 'test') diff --git a/libunwind/test/signal_unwind.pass.cpp b/libunwind/test/signal_unwind.pass.cpp new file mode 100644 index 000000000000..295dd75bb726 --- /dev/null +++ b/libunwind/test/signal_unwind.pass.cpp @@ -0,0 +1,44 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Ensure that the unwinder can cope with the signal handler. + +#include <assert.h> +#include <dlfcn.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include <unwind.h> + +_Unwind_Reason_Code frame_handler(struct _Unwind_Context* ctx, void* arg) { + (void)arg; + Dl_info info = { 0, 0, 0, 0 }; + assert(dladdr((void*)_Unwind_GetIP(ctx), &info)); + + // Unwind util the main is reached, above frames deeped on the platfrom and architecture. + if(info.dli_sname && !strcmp("main", info.dli_sname)) { + _Exit(0); + } + return _URC_NO_REASON; +} + +void signal_handler(int signum) { + (void)signum; + _Unwind_Backtrace(frame_handler, NULL); + _Exit(-1); +} + +int main() { + signal(SIGUSR1, signal_handler); + kill(getpid(), SIGUSR1); + return -2; +} diff --git a/libunwind/test/unwind_leaffunction.pass.cpp b/libunwind/test/unwind_leaffunction.pass.cpp new file mode 100644 index 000000000000..b8a114516d0a --- /dev/null +++ b/libunwind/test/unwind_leaffunction.pass.cpp @@ -0,0 +1,50 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Ensure that leaf function can be unwund. + +#include <assert.h> +#include <dlfcn.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include <unwind.h> + +_Unwind_Reason_Code frame_handler(struct _Unwind_Context* ctx, void* arg) { + (void)arg; + Dl_info info = { 0, 0, 0, 0 }; + assert(dladdr((void*)_Unwind_GetIP(ctx), &info)); + + // Unwind util the main is reached, above frames deeped on the platfrom and architecture. + if(info.dli_sname && !strcmp("main", info.dli_sname)) { + _Exit(0); + } + return _URC_NO_REASON; +} + +void signal_handler(int signum) { + (void)signum; + _Unwind_Backtrace(frame_handler, NULL); + _Exit(-1); +} + +int* faultyPointer = NULL; + +__attribute__((noinline)) void crashing_leaf_func(void) { + *faultyPointer = 0; +} + +int main() { + signal(SIGSEGV, signal_handler); + crashing_leaf_func(); + return -2; +} \ No newline at end of file _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits