File: aix_signal_unwind.pass.sh.S

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,998,492 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (245 lines) | stat: -rw-r--r-- 8,255 bytes parent folder | download | duplicates (14)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
//===----------------------------------------------------------------------===//
//
// 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