mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 03:56:41 +00:00

This patch fixes/unifies AIX target triples used in libc++, libc++abi, and libunwind LIT tests. (cherry picked from commit 2d3655037ccfa276cb0949c2ce0cff56985f6637)
246 lines
8.1 KiB
ArmAsm
246 lines
8.1 KiB
ArmAsm
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Test that _Unwind_Backtrace() walks up from a signal handler and produces
|
|
// a correct traceback when the function raising the signal does not save
|
|
// the link register or does not store the stack back chain.
|
|
|
|
// REQUIRES: target={{.+}}-aix{{.*}}
|
|
|
|
// Test when the function raising the signal does not save the link register
|
|
// RUN: %{cxx} -x c++ %s -o %t.exe -DCXX_CODE %{flags} %{compile_flags}
|
|
// RUN: %{exec} %t.exe
|
|
|
|
// Test when the function raising the signal does not store stack back chain.
|
|
// RUN: %{cxx} -x c++ -c %s -o %t1.o -DCXX_CODE -DNOBACKCHAIN %{flags} \
|
|
// RUN: %{compile_flags}
|
|
// RUN: %{cxx} -c %s -o %t2.o %{flags} %{compile_flags}
|
|
// RUN: %{cxx} -o %t1.exe %t1.o %t2.o %{flags} %{link_flags}
|
|
// RUN: %{exec} %t1.exe
|
|
|
|
#ifdef CXX_CODE
|
|
|
|
#undef NDEBUG
|
|
#include <assert.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/debug.h>
|
|
#include <unwind.h>
|
|
|
|
#define NAME_ARRAY_SIZE 10
|
|
#define NAMES_EXPECTED 6
|
|
|
|
const char* namesExpected[] = {"handler", "abc", "bar", "foo", "main",
|
|
"__start"};
|
|
char *namesObtained[NAME_ARRAY_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
|
int funcIndex = 0;
|
|
|
|
// Get the function name from traceback table.
|
|
char *getFuncName(uintptr_t pc, uint16_t *nameLen) {
|
|
uint32_t *p = reinterpret_cast<uint32_t *>(pc);
|
|
|
|
// Keep looking forward until a word of 0 is found. The traceback
|
|
// table starts at the following word.
|
|
while (*p)
|
|
++p;
|
|
tbtable *TBTable = reinterpret_cast<tbtable *>(p + 1);
|
|
|
|
if (!TBTable->tb.name_present)
|
|
return NULL;
|
|
|
|
// Get to the optional portion of the traceback table.
|
|
p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);
|
|
|
|
// Skip field parminfo if it exists.
|
|
if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
|
|
++p;
|
|
|
|
// Skip field tb_offset if it exists.
|
|
if (TBTable->tb.has_tboff)
|
|
++p;
|
|
|
|
// Skip field hand_mask if it exists.
|
|
if (TBTable->tb.int_hndl)
|
|
++p;
|
|
|
|
// Skip fields ctl_info and ctl_info_disp if they exist.
|
|
if (TBTable->tb.has_ctl)
|
|
p += 1 + *p;
|
|
|
|
*nameLen = *reinterpret_cast<uint16_t *>(p);
|
|
return reinterpret_cast<char *>(p) + sizeof(uint16_t);
|
|
}
|
|
|
|
_Unwind_Reason_Code callBack(struct _Unwind_Context *uc, void *arg) {
|
|
(void)arg;
|
|
uint16_t nameLen;
|
|
uintptr_t ip = _Unwind_GetIP(uc);
|
|
if (funcIndex < NAME_ARRAY_SIZE)
|
|
namesObtained[funcIndex++] = strndup(getFuncName(ip, &nameLen), nameLen);
|
|
return _URC_NO_REASON;
|
|
}
|
|
|
|
extern "C" void handler(int signum) {
|
|
(void)signum;
|
|
// Walk stack frames for traceback.
|
|
_Unwind_Backtrace(callBack, NULL);
|
|
|
|
// Verify the traceback.
|
|
assert(funcIndex <= NAMES_EXPECTED && "Obtained names more than expected");
|
|
for (int i = 0; i < funcIndex; ++i) {
|
|
assert(!strcmp(namesExpected[i], namesObtained[i]) &&
|
|
"Function names do not match");
|
|
free(namesObtained[i]);
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
#ifdef NOBACKCHAIN
|
|
// abc() is in assembly. It raises signal SIGSEGV and does not store
|
|
// the stack back chain.
|
|
extern "C" void abc();
|
|
|
|
#else
|
|
volatile int *null = 0;
|
|
|
|
// abc() raises signal SIGSEGV and does not save the link register.
|
|
extern "C" __attribute__((noinline)) void abc() {
|
|
// Produce a SIGSEGV.
|
|
*null = 0;
|
|
}
|
|
#endif
|
|
|
|
extern "C" __attribute__((noinline)) void bar() {
|
|
abc();
|
|
}
|
|
|
|
extern "C" __attribute__((noinline)) void foo() {
|
|
bar();
|
|
}
|
|
|
|
int main() {
|
|
// Set signal handler for SIGSEGV.
|
|
signal(SIGSEGV, handler);
|
|
foo();
|
|
}
|
|
|
|
#else // Assembly code for abc().
|
|
// This assembly code is similar to the following C code but it saves the
|
|
// link register.
|
|
//
|
|
// int *badp = 0;
|
|
// void abc() {
|
|
// *badp = 0;
|
|
// }
|
|
|
|
#ifdef __64BIT__
|
|
.csect [PR],5
|
|
.file "abc.c"
|
|
.globl abc[DS] # -- Begin function abc
|
|
.globl .abc
|
|
.align 4
|
|
.csect abc[DS],3
|
|
.vbyte 8, .abc # @abc
|
|
.vbyte 8, TOC[TC0]
|
|
.vbyte 8, 0
|
|
.csect [PR],5
|
|
.abc:
|
|
# %bb.0: # %entry
|
|
mflr 0
|
|
std 0, 16(1)
|
|
ld 3, L..C0(2) # @badp
|
|
bl $+4
|
|
ld 4, 0(3)
|
|
li 3, 0
|
|
stw 3, 0(4)
|
|
ld 0, 16(1)
|
|
mtlr 0
|
|
blr
|
|
L..abc0:
|
|
.vbyte 4, 0x00000000 # Traceback table begin
|
|
.byte 0x00 # Version = 0
|
|
.byte 0x09 # Language = CPlusPlus
|
|
.byte 0x20 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue
|
|
# +HasTraceBackTableOffset, -IsInternalProcedure
|
|
# -HasControlledStorage, -IsTOCless
|
|
# -IsFloatingPointPresent
|
|
# -IsFloatingPointOperationLogOrAbortEnabled
|
|
.byte 0x61 # -IsInterruptHandler, +IsFunctionNamePresent, +IsAllocaUsed
|
|
# OnConditionDirective = 0, -IsCRSaved, +IsLRSaved
|
|
.byte 0x00 # -IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0
|
|
.byte 0x01 # -HasExtensionTable, -HasVectorInfo, NumOfGPRsSaved = 1
|
|
.byte 0x00 # NumberOfFixedParms = 0
|
|
.byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack
|
|
.vbyte 4, L..abc0-.abc # Function size
|
|
.vbyte 2, 0x0003 # Function name len = 3
|
|
.byte "abc" # Function Name
|
|
.byte 0x1f # AllocaUsed
|
|
# -- End function
|
|
.csect badp[RW],3
|
|
.globl badp[RW] # @badp
|
|
.align 3
|
|
.vbyte 8, 0
|
|
.toc
|
|
L..C0:
|
|
.tc badp[TC],badp[RW]
|
|
#else
|
|
.csect [PR],5
|
|
.file "abc.c"
|
|
.globl abc[DS] # -- Begin function abc
|
|
.globl .abc
|
|
.align 4
|
|
.csect abc[DS],2
|
|
.vbyte 4, .abc # @abc
|
|
.vbyte 4, TOC[TC0]
|
|
.vbyte 4, 0
|
|
.csect [PR],5
|
|
.abc:
|
|
# %bb.0: # %entry
|
|
mflr 0
|
|
stw 0, 8(1)
|
|
lwz 3, L..C0(2) # @badp
|
|
bl $+4
|
|
lwz 4, 0(3)
|
|
li 3, 0
|
|
stw 3, 0(4)
|
|
lwz 0, 8(1)
|
|
mtlr 0
|
|
blr
|
|
L..abc0:
|
|
.vbyte 4, 0x00000000 # Traceback table begin
|
|
.byte 0x00 # Version = 0
|
|
.byte 0x09 # Language = CPlusPlus
|
|
.byte 0x20 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue
|
|
# +HasTraceBackTableOffset, -IsInternalProcedure
|
|
# -HasControlledStorage, -IsTOCless
|
|
# -IsFloatingPointPresent
|
|
# -IsFloatingPointOperationLogOrAbortEnabled
|
|
.byte 0x61 # -IsInterruptHandler, +IsFunctionNamePresent, +IsAllocaUsed
|
|
# OnConditionDirective = 0, -IsCRSaved, +IsLRSaved
|
|
.byte 0x00 # -IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0
|
|
.byte 0x01 # -HasExtensionTable, -HasVectorInfo, NumOfGPRsSaved = 1
|
|
.byte 0x00 # NumberOfFixedParms = 0
|
|
.byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack
|
|
.vbyte 4, L..abc0-.abc # Function size
|
|
.vbyte 2, 0x0003 # Function name len = 3
|
|
.byte "abc" # Function Name
|
|
.byte 0x1f # AllocaUsed
|
|
# -- End function
|
|
.csect badp[RW],2
|
|
.globl badp[RW] # @badp
|
|
.align 2
|
|
.vbyte 4, 0
|
|
.toc
|
|
L..C0:
|
|
.tc badp[TC],badp[RW]
|
|
#endif // __64BIT__
|
|
#endif // CXX_CODE
|