1 //===----------------------------------------------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 // Test that _Unwind_Backtrace() walks up from a signal handler and produces
10 // a correct traceback when the function raising the signal does not save
11 // the link register or does not store the stack back chain.
13 // REQUIRES: target={{.+}}-aix{{.*}}
15 // Test when the function raising the signal does not save the link register
16 // RUN: %{cxx} -x c++ %s -o %t.exe -DCXX_CODE %{flags} %{compile_flags}
17 // RUN: %{exec} %t.exe
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.exe
34 #include <sys/debug.h>
37 #define NAME_ARRAY_SIZE 10
38 #define NAMES_EXPECTED 6
40 const char* namesExpected[] = {"handler", "abc", "bar", "foo", "main",
42 char *namesObtained[NAME_ARRAY_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
46 // Get the function name from traceback table.
47 char *getFuncName(uintptr_t pc, uint16_t *nameLen) {
48 uint32_t *p = reinterpret_cast<uint32_t *>(pc);
50 // Keep looking forward until a word of 0 is found. The traceback
51 // table starts at the following word.
54 tbtable *TBTable = reinterpret_cast<tbtable *>(p + 1);
56 if (!TBTable->tb.name_present)
59 // Get to the optional portion of the traceback table.
60 p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);
62 // Skip field parminfo if it exists.
63 if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
66 // Skip field tb_offset if it exists.
67 if (TBTable->tb.has_tboff)
70 // Skip field hand_mask if it exists.
71 if (TBTable->tb.int_hndl)
74 // Skip fields ctl_info and ctl_info_disp if they exist.
75 if (TBTable->tb.has_ctl)
78 *nameLen = *reinterpret_cast<uint16_t *>(p);
79 return reinterpret_cast<char *>(p) + sizeof(uint16_t);
82 _Unwind_Reason_Code callBack(struct _Unwind_Context *uc, void *arg) {
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;
91 extern "C" void handler(int signum) {
93 // Walk stack frames for traceback.
94 _Unwind_Backtrace(callBack, NULL);
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]);
107 // abc() is in assembly. It raises signal SIGSEGV and does not store
108 // the stack back chain.
109 extern "C" void abc();
112 volatile int *null = 0;
114 // abc() raises signal SIGSEGV and does not save the link register.
115 extern "C" __attribute__((noinline)) void abc() {
116 // Produce a SIGSEGV.
121 extern "C" __attribute__((noinline)) void bar() {
125 extern "C" __attribute__((noinline)) void foo() {
130 // Set signal handler for SIGSEGV.
131 signal(SIGSEGV, handler);
135 #else // Assembly code for abc().
136 // This assembly code is similar to the following C code but it saves the
147 .globl abc[DS] # -- Begin function abc
151 .vbyte 8, .abc # @abc
159 ld 3, L..C0(2) # @badp
168 .vbyte 4, 0x00000000 # Traceback table begin
169 .byte 0x00 # Version = 0
170 .byte 0x09 # Language = CPlusPlus
171 .byte 0x20 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue
172 # +HasTraceBackTableOffset, -IsInternalProcedure
173 # -HasControlledStorage, -IsTOCless
174 # -IsFloatingPointPresent
175 # -IsFloatingPointOperationLogOrAbortEnabled
176 .byte 0x61 # -IsInterruptHandler, +IsFunctionNamePresent, +IsAllocaUsed
177 # OnConditionDirective = 0, -IsCRSaved, +IsLRSaved
178 .byte 0x00 # -IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0
179 .byte 0x01 # -HasExtensionTable, -HasVectorInfo, NumOfGPRsSaved = 1
180 .byte 0x00 # NumberOfFixedParms = 0
181 .byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack
182 .vbyte 4, L..abc0-.abc # Function size
183 .vbyte 2, 0x0003 # Function name len = 3
184 .byte "abc" # Function Name
185 .byte 0x1f # AllocaUsed
188 .globl badp[RW] # @badp
193 .tc badp[TC],badp[RW]
197 .globl abc[DS] # -- Begin function abc
201 .vbyte 4, .abc # @abc
209 lwz 3, L..C0(2) # @badp
218 .vbyte 4, 0x00000000 # Traceback table begin
219 .byte 0x00 # Version = 0
220 .byte 0x09 # Language = CPlusPlus
221 .byte 0x20 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue
222 # +HasTraceBackTableOffset, -IsInternalProcedure
223 # -HasControlledStorage, -IsTOCless
224 # -IsFloatingPointPresent
225 # -IsFloatingPointOperationLogOrAbortEnabled
226 .byte 0x61 # -IsInterruptHandler, +IsFunctionNamePresent, +IsAllocaUsed
227 # OnConditionDirective = 0, -IsCRSaved, +IsLRSaved
228 .byte 0x00 # -IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0
229 .byte 0x01 # -HasExtensionTable, -HasVectorInfo, NumOfGPRsSaved = 1
230 .byte 0x00 # NumberOfFixedParms = 0
231 .byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack
232 .vbyte 4, L..abc0-.abc # Function size
233 .vbyte 2, 0x0003 # Function name len = 3
234 .byte "abc" # Function Name
235 .byte 0x1f # AllocaUsed
238 .globl badp[RW] # @badp
243 .tc badp[TC],badp[RW]