247 lines · plain
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// Test that _Unwind_Backtrace() walks up from a signal handler and produces10// a correct traceback when the function raising the signal does not save11// the link register or does not store the stack back chain.12 13// REQUIRES: target={{.+}}-aix{{.*}}14 15// Test when the function raising the signal does not save the link register16// RUN: %{cxx} -x c++ %s -o %t.exe -DCXX_CODE %{flags} %{compile_flags}17// RUN: %{exec} %t.exe18 19// Test when the function raising the signal does not store stack back chain.20// RUN: %{cxx} -x c++ -c %s -o %t1.o -DCXX_CODE -DNOBACKCHAIN %{flags} \21// RUN: %{compile_flags}22// RUN: %{cxx} -c %s -o %t2.o %{flags} %{compile_flags}23// RUN: %{cxx} -o %t1.exe %t1.o %t2.o %{flags} %{link_flags}24// RUN: %{exec} %t1.exe25 26#ifdef CXX_CODE27 28#undef NDEBUG29#include <assert.h>30#include <signal.h>31#include <stdio.h>32#include <stdlib.h>33#include <string.h>34#include <sys/debug.h>35#include <unwind.h>36 37#define NAME_ARRAY_SIZE 1038#define NAMES_EXPECTED 639 40const char* namesExpected[] = {"handler", "abc", "bar", "foo", "main",41 "__start"};42char *namesObtained[NAME_ARRAY_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};43 44int funcIndex = 0;45 46// Get the function name from traceback table.47char *getFuncName(uintptr_t pc, uint16_t *nameLen) {48 uint32_t *p = reinterpret_cast<uint32_t *>(pc);49 50 // Keep looking forward until a word of 0 is found. The traceback51 // table starts at the following word.52 while (*p)53 ++p;54 tbtable *TBTable = reinterpret_cast<tbtable *>(p + 1);55 56 if (!TBTable->tb.name_present)57 return NULL;58 59 // Get to the optional portion of the traceback table.60 p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);61 62 // Skip field parminfo if it exists.63 if (TBTable->tb.fixedparms || TBTable->tb.floatparms)64 ++p;65 66 // Skip field tb_offset if it exists.67 if (TBTable->tb.has_tboff)68 ++p;69 70 // Skip field hand_mask if it exists.71 if (TBTable->tb.int_hndl)72 ++p;73 74 // Skip fields ctl_info and ctl_info_disp if they exist.75 if (TBTable->tb.has_ctl)76 p += 1 + *p;77 78 *nameLen = *reinterpret_cast<uint16_t *>(p);79 return reinterpret_cast<char *>(p) + sizeof(uint16_t);80}81 82_Unwind_Reason_Code callBack(struct _Unwind_Context *uc, void *arg) {83 (void)arg;84 uint16_t nameLen;85 uintptr_t ip = _Unwind_GetIP(uc);86 if (funcIndex < NAME_ARRAY_SIZE)87 namesObtained[funcIndex++] = strndup(getFuncName(ip, &nameLen), nameLen);88 return _URC_NO_REASON;89}90 91extern "C" void handler(int signum) {92 (void)signum;93 // Walk stack frames for traceback.94 _Unwind_Backtrace(callBack, NULL);95 96 // Verify the traceback.97 assert(funcIndex <= NAMES_EXPECTED && "Obtained names more than expected");98 for (int i = 0; i < funcIndex; ++i) {99 assert(!strcmp(namesExpected[i], namesObtained[i]) &&100 "Function names do not match");101 free(namesObtained[i]);102 }103 exit(0);104}105 106#ifdef NOBACKCHAIN107// abc() is in assembly. It raises signal SIGSEGV and does not store108// the stack back chain.109extern "C" void abc();110 111#else112volatile int *null = 0;113 114// abc() raises signal SIGSEGV and does not save the link register.115extern "C" __attribute__((noinline)) void abc() {116 // Produce a SIGSEGV.117 *null = 0;118}119#endif120 121extern "C" __attribute__((noinline)) void bar() {122 abc();123}124 125extern "C" __attribute__((noinline)) void foo() {126 bar();127}128 129int main(int, char**) {130 // Set signal handler for SIGSEGV.131 signal(SIGSEGV, handler);132 foo();133 return 0;134}135 136#else // Assembly code for abc().137// This assembly code is similar to the following C code but it saves the138// link register.139//140// int *badp = 0;141// void abc() {142// *badp = 0;143// }144 145#ifdef __64BIT__146 .csect [PR],5147 .file "abc.c"148 .globl abc[DS] # -- Begin function abc149 .globl .abc150 .align 4151 .csect abc[DS],3152 .vbyte 8, .abc # @abc153 .vbyte 8, TOC[TC0]154 .vbyte 8, 0155 .csect [PR],5156.abc:157# %bb.0: # %entry158 mflr 0159 std 0, 16(1)160 ld 3, L..C0(2) # @badp161 bl $+4162 ld 4, 0(3)163 li 3, 0164 stw 3, 0(4)165 ld 0, 16(1)166 mtlr 0167 blr168L..abc0:169 .vbyte 4, 0x00000000 # Traceback table begin170 .byte 0x00 # Version = 0171 .byte 0x09 # Language = CPlusPlus172 .byte 0x20 # -IsGlobalLinkage, -IsOutOfLineEpilogOrPrologue173 # +HasTraceBackTableOffset, -IsInternalProcedure174 # -HasControlledStorage, -IsTOCless175 # -IsFloatingPointPresent176 # -IsFloatingPointOperationLogOrAbortEnabled177 .byte 0x61 # -IsInterruptHandler, +IsFunctionNamePresent, +IsAllocaUsed178 # OnConditionDirective = 0, -IsCRSaved, +IsLRSaved179 .byte 0x00 # -IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0180 .byte 0x01 # -HasExtensionTable, -HasVectorInfo, NumOfGPRsSaved = 1181 .byte 0x00 # NumberOfFixedParms = 0182 .byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack183 .vbyte 4, L..abc0-.abc # Function size184 .vbyte 2, 0x0003 # Function name len = 3185 .byte "abc" # Function Name186 .byte 0x1f # AllocaUsed187 # -- End function188 .csect badp[RW],3189 .globl badp[RW] # @badp190 .align 3191 .vbyte 8, 0192 .toc193L..C0:194 .tc badp[TC],badp[RW]195#else196 .csect [PR],5197 .file "abc.c"198 .globl abc[DS] # -- Begin function abc199 .globl .abc200 .align 4201 .csect abc[DS],2202 .vbyte 4, .abc # @abc203 .vbyte 4, TOC[TC0]204 .vbyte 4, 0205 .csect [PR],5206.abc:207# %bb.0: # %entry208 mflr 0209 stw 0, 8(1)210 lwz 3, L..C0(2) # @badp211 bl $+4212 lwz 4, 0(3)213 li 3, 0214 stw 3, 0(4)215 lwz 0, 8(1)216 mtlr 0217 blr218L..abc0:219 .vbyte 4, 0x00000000 # Traceback table begin220 .byte 0x00 # Version = 0221 .byte 0x09 # Language = CPlusPlus222 .byte 0x20 # -IsGlobalLinkage, -IsOutOfLineEpilogOrPrologue223 # +HasTraceBackTableOffset, -IsInternalProcedure224 # -HasControlledStorage, -IsTOCless225 # -IsFloatingPointPresent226 # -IsFloatingPointOperationLogOrAbortEnabled227 .byte 0x61 # -IsInterruptHandler, +IsFunctionNamePresent, +IsAllocaUsed228 # OnConditionDirective = 0, -IsCRSaved, +IsLRSaved229 .byte 0x00 # -IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0230 .byte 0x01 # -HasExtensionTable, -HasVectorInfo, NumOfGPRsSaved = 1231 .byte 0x00 # NumberOfFixedParms = 0232 .byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack233 .vbyte 4, L..abc0-.abc # Function size234 .vbyte 2, 0x0003 # Function name len = 3235 .byte "abc" # Function Name236 .byte 0x1f # AllocaUsed237 # -- End function238 .csect badp[RW],2239 .globl badp[RW] # @badp240 .align 2241 .vbyte 4, 0242 .toc243L..C0:244 .tc badp[TC],badp[RW]245#endif // __64BIT__246#endif // CXX_CODE247