[llvm] [z/OS] Add backtrace support for z/OS. (PR #121826)
Kai Nacke via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 7 07:08:45 PST 2025
https://github.com/redstar updated https://github.com/llvm/llvm-project/pull/121826
>From 7406f5bd95d772b5b16599106e9fd318dbc29287 Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Mon, 6 Jan 2025 14:17:58 -0500
Subject: [PATCH 1/4] [z/OS] Add backtrace support for z/OS.
The system call `__CELQTBCK()` is used to build a backtrace like
on other systems. The collected information are the address of the PC,
the address of the entry point (EP), the difference between both
addresses (+EP), the dynamic storage area (DSA aka the stack
pointer), and the function name.
The system call is described here:
https://www.ibm.com/docs/en/zos/3.1.0?topic=cwicsa6a-celqtbck-also-known-as-celqtbck-64-bit-traceback-service
---
llvm/lib/Support/Unix/Signals.inc | 81 +++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc
index 088ca33e3c8c56..2a1977b2c94a02 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -79,6 +79,10 @@
#undef HAVE__UNWIND_BACKTRACE
#endif
#endif
+#if ENABLE_BACKTRACES && defined(__MVS__)
+#include "llvm/Support/ConvertEBCDIC.h"
+#include <__le_cwi.h>
+#endif
using namespace llvm;
@@ -708,6 +712,79 @@ static int unwindBacktrace(void **StackTrace, int MaxEntries) {
}
#endif
+#if ENABLE_BACKTRACES && defined(__MVS__)
+void zosbacktrace(raw_ostream &OS) {
+ // A function name in the PPA1 can have length 16k.
+ constexpr size_t MAX_ENTRY_NAME = UINT16_MAX;
+ // Limit all other strings to 8 byte.
+ constexpr size_t MAX_OTHER = 8;
+ void *dsaptr; // Input
+ int32_t dsa_format = -1; // Input/Output
+ void *caaptr = _gtca(); // Input
+ int32_t member_id;
+ char compile_unit_name[MAX_OTHER];
+ int32_t compile_unit_name_length = sizeof(compile_unit_name); // Input/Output
+ void *compile_unit_address; // Output
+ void *call_instruction_address = 0; // Input/Output
+ char entry_name[MAX_ENTRY_NAME]; // Output
+ int32_t entry_name_length = sizeof(entry_name); // Input/Output
+ void *entry_address; // Output
+ void *callers_instruction_address; // Output
+ void *callers_dsaptr; // Output
+ int32_t callers_dsa_format; // Output
+ char statement_id[MAX_OTHER]; // Output
+ int32_t statement_id_length = sizeof(statement_id); // Input/Output
+ void *cibptr; // Output
+ int32_t main_program; // Output
+ _FEEDBACK fc; // Output
+
+ // The DSA pointer is the value of the stack pointer r4. __builtin_frame_address()
+ // returns a pointer to the stack frame, so the stack bias has to be considered
+ // to get the expected DSA value.
+ dsaptr = static_cast<char *>(__builtin_frame_address(0)) - 2048;
+ int count = 0;
+ OS << " DSA Adr EP +EP DSA "
+ " Entry\n";
+ while (1) {
+ compile_unit_name_length = sizeof(compile_unit_name);
+ entry_name_length = sizeof(entry_name);
+ statement_id_length = sizeof(statement_id);
+ // See
+ // https://www.ibm.com/docs/en/zos/3.1.0?topic=cwicsa6a-celqtbck-also-known-as-celqtbck-64-bit-traceback-service
+ // for documentation of the parameters.
+ __CELQTBCK(&dsaptr, &dsa_format, &caaptr, &member_id, &compile_unit_name[0],
+ &compile_unit_name_length, &compile_unit_address,
+ &call_instruction_address, &entry_name[0], &entry_name_length,
+ &entry_address, &callers_instruction_address, &callers_dsaptr,
+ &callers_dsa_format, &statement_id[0], &statement_id_length,
+ &cibptr, &main_program, &fc);
+ if (fc.tok_sev) {
+ OS << format("Error! Severity %d Message %d\n", fc.tok_sev, fc.tok_msgno);
+ break;
+ }
+
+ if (count) { // Omit first entry.
+ uintptr_t diff = reinterpret_cast<uintptr_t>(call_instruction_address) -
+ reinterpret_cast<uintptr_t>(entry_address);
+ OS << format(" %3d. 0x%016X", count, call_instruction_address);
+ OS << format(" 0x%016X +0x%08X 0x%016X", entry_address, diff, dsaptr);
+ SmallString<256> Str;
+ ConverterEBCDIC::convertToUTF8(StringRef(entry_name, entry_name_length),
+ Str);
+ OS << format(" %s", Str.c_str());
+ OS << "\n";
+ }
+ count++;
+ if (callers_dsaptr) {
+ dsaptr = callers_dsaptr;
+ dsa_format = callers_dsa_format;
+ call_instruction_address = callers_instruction_address;
+ } else
+ break;
+ }
+}
+#endif
+
// In the case of a program crash or fault, print out a stack trace so that the
// user has an indication of why and where we died.
//
@@ -715,6 +792,9 @@ static int unwindBacktrace(void **StackTrace, int MaxEntries) {
// doesn't demangle symbols.
void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) {
#if ENABLE_BACKTRACES
+#ifdef __MVS__
+ zosbacktrace(OS);
+#else
static void *StackTrace[256];
int depth = 0;
#if defined(HAVE_BACKTRACE)
@@ -791,6 +871,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) {
backtrace_symbols_fd(StackTrace, Depth, STDERR_FILENO);
#endif
#endif
+#endif
}
static void PrintStackTraceSignalHandler(void *) {
>From 5d0426310aeb01dd016985142cc45e973a541835 Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Mon, 6 Jan 2025 15:54:46 -0500
Subject: [PATCH 2/4] clang-format changes
---
llvm/lib/Support/Unix/Signals.inc | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc
index 2a1977b2c94a02..5237323257f070 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -718,9 +718,9 @@ void zosbacktrace(raw_ostream &OS) {
constexpr size_t MAX_ENTRY_NAME = UINT16_MAX;
// Limit all other strings to 8 byte.
constexpr size_t MAX_OTHER = 8;
- void *dsaptr; // Input
- int32_t dsa_format = -1; // Input/Output
- void *caaptr = _gtca(); // Input
+ void *dsaptr; // Input
+ int32_t dsa_format = -1; // Input/Output
+ void *caaptr = _gtca(); // Input
int32_t member_id;
char compile_unit_name[MAX_OTHER];
int32_t compile_unit_name_length = sizeof(compile_unit_name); // Input/Output
@@ -738,9 +738,9 @@ void zosbacktrace(raw_ostream &OS) {
int32_t main_program; // Output
_FEEDBACK fc; // Output
- // The DSA pointer is the value of the stack pointer r4. __builtin_frame_address()
- // returns a pointer to the stack frame, so the stack bias has to be considered
- // to get the expected DSA value.
+ // The DSA pointer is the value of the stack pointer r4.
+ // __builtin_frame_address() returns a pointer to the stack frame, so the
+ // stack bias has to be considered to get the expected DSA value.
dsaptr = static_cast<char *>(__builtin_frame_address(0)) - 2048;
int count = 0;
OS << " DSA Adr EP +EP DSA "
>From 9b9de19cdcd795f67be1d9e88fe6d2debbca5a23 Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Tue, 7 Jan 2025 10:06:51 -0500
Subject: [PATCH 3/4] Address reviewer comments
---
llvm/lib/Support/Unix/Signals.inc | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc
index 5237323257f070..19e454eeb381ea 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -725,7 +725,7 @@ void zosbacktrace(raw_ostream &OS) {
char compile_unit_name[MAX_OTHER];
int32_t compile_unit_name_length = sizeof(compile_unit_name); // Input/Output
void *compile_unit_address; // Output
- void *call_instruction_address = 0; // Input/Output
+ void *call_instruction_address = nullptr; // Input/Output
char entry_name[MAX_ENTRY_NAME]; // Output
int32_t entry_name_length = sizeof(entry_name); // Input/Output
void *entry_address; // Output
@@ -741,7 +741,7 @@ void zosbacktrace(raw_ostream &OS) {
// The DSA pointer is the value of the stack pointer r4.
// __builtin_frame_address() returns a pointer to the stack frame, so the
// stack bias has to be considered to get the expected DSA value.
- dsaptr = static_cast<char *>(__builtin_frame_address(0)) - 2048;
+ void *dsaptr = static_cast<char *>(__builtin_frame_address(0)) - 2048;
int count = 0;
OS << " DSA Adr EP +EP DSA "
" Entry\n";
@@ -759,7 +759,8 @@ void zosbacktrace(raw_ostream &OS) {
&callers_dsa_format, &statement_id[0], &statement_id_length,
&cibptr, &main_program, &fc);
if (fc.tok_sev) {
- OS << format("Error! Severity %d Message %d\n", fc.tok_sev, fc.tok_msgno);
+ OS << format("error: CELQTBCK returned severity %d message %d\n",
+ fc.tok_sev, fc.tok_msgno);
break;
}
@@ -772,9 +773,9 @@ void zosbacktrace(raw_ostream &OS) {
ConverterEBCDIC::convertToUTF8(StringRef(entry_name, entry_name_length),
Str);
OS << format(" %s", Str.c_str());
- OS << "\n";
+ OS << '\n';
}
- count++;
+ ++count;
if (callers_dsaptr) {
dsaptr = callers_dsaptr;
dsa_format = callers_dsa_format;
>From f37ec9b1d1fb954bd4d1d01457a2b5ef0258a078 Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Tue, 7 Jan 2025 10:08:29 -0500
Subject: [PATCH 4/4] Do not declare variable twice.
---
llvm/lib/Support/Unix/Signals.inc | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc
index 19e454eeb381ea..e0ec3fcbac80bf 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -718,7 +718,6 @@ void zosbacktrace(raw_ostream &OS) {
constexpr size_t MAX_ENTRY_NAME = UINT16_MAX;
// Limit all other strings to 8 byte.
constexpr size_t MAX_OTHER = 8;
- void *dsaptr; // Input
int32_t dsa_format = -1; // Input/Output
void *caaptr = _gtca(); // Input
int32_t member_id;
More information about the llvm-commits
mailing list