80 lines · cpp
1// -*- C++ -*-2//===----------------------------------------------------------------------===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10// Ensure that leaf function can be unwund.11// REQUIRES: target={{(aarch64|loongarch64|riscv64|s390x|x86_64)-.+}}12// UNSUPPORTED: target={{.*-windows.*}}13 14// TODO: Figure out why this fails with Memory Sanitizer.15// XFAIL: msan16 17// Note: this test fails on musl because:18//19// (a) musl disables emission of unwind information for its build, and20// (b) musl's signal trampolines don't include unwind information21//22// XFAIL: target={{.*}}-musl23 24#undef NDEBUG25#include <assert.h>26#include <signal.h>27#include <stdio.h>28#include <stdlib.h>29#include <string.h>30#include <sys/types.h>31#include <unistd.h>32#include <unwind.h>33 34// Using __attribute__((section("main_func"))) is ELF specific, but then35// this entire test is marked as requiring Linux, so we should be good.36//37// We don't use dladdr() because on musl it's a no-op when statically linked.38extern char __start_main_func;39extern char __stop_main_func;40 41_Unwind_Reason_Code frame_handler(struct _Unwind_Context* ctx, void* arg) {42 (void)arg;43 44 // Unwind until the main is reached, above frames depend on the platform and45 // architecture.46 uintptr_t ip = _Unwind_GetIP(ctx);47 if (ip >= (uintptr_t)&__start_main_func &&48 ip < (uintptr_t)&__stop_main_func) {49 _Exit(0);50 }51 52 return _URC_NO_REASON;53}54 55void signal_handler(int signum) {56 (void)signum;57 _Unwind_Backtrace(frame_handler, NULL);58 _Exit(-1);59}60 61__attribute__((noinline)) void crashing_leaf_func(int do_trap) {62 // libunwind searches for the address before the return address which points63 // to the trap instruction. We make the trap conditional and prevent inlining64 // of the function to ensure that the compiler doesn't remove the `ret`65 // instruction altogether.66 //67 // It's also important that the trap instruction isn't the first instruction68 // in the function (which it isn't because of the branch) for other unwinders69 // that also decrement pc.70 if (do_trap)71 __builtin_trap();72}73 74__attribute__((section("main_func"))) int main(int, char **) {75 signal(SIGTRAP, signal_handler);76 signal(SIGILL, signal_handler);77 crashing_leaf_func(1);78 return -2;79}80