Skip to content

Commit ca10dea

Browse files
authored
[z/OS] Add backtrace support for z/OS. (#121826)
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
1 parent 5f70fea commit ca10dea

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

llvm/lib/Support/Unix/Signals.inc

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@
7979
#undef HAVE__UNWIND_BACKTRACE
8080
#endif
8181
#endif
82+
#if ENABLE_BACKTRACES && defined(__MVS__)
83+
#include "llvm/Support/ConvertEBCDIC.h"
84+
#include <__le_cwi.h>
85+
#endif
8286

8387
using namespace llvm;
8488

@@ -708,13 +712,86 @@ static int unwindBacktrace(void **StackTrace, int MaxEntries) {
708712
}
709713
#endif
710714

715+
#if ENABLE_BACKTRACES && defined(__MVS__)
716+
static void zosbacktrace(raw_ostream &OS) {
717+
// A function name in the PPA1 can have length 16k.
718+
constexpr size_t MAX_ENTRY_NAME = UINT16_MAX;
719+
// Limit all other strings to 8 byte.
720+
constexpr size_t MAX_OTHER = 8;
721+
int32_t dsa_format = -1; // Input/Output
722+
void *caaptr = _gtca(); // Input
723+
int32_t member_id; // Output
724+
char compile_unit_name[MAX_OTHER]; // Output
725+
void *compile_unit_address; // Output
726+
void *call_instruction_address = nullptr; // Input/Output
727+
char entry_name[MAX_ENTRY_NAME]; // Output
728+
void *entry_address; // Output
729+
void *callers_instruction_address; // Output
730+
void *callers_dsaptr; // Output
731+
int32_t callers_dsa_format; // Output
732+
char statement_id[MAX_OTHER]; // Output
733+
void *cibptr; // Output
734+
int32_t main_program; // Output
735+
_FEEDBACK fc; // Output
736+
737+
// The DSA pointer is the value of the stack pointer r4.
738+
// __builtin_frame_address() returns a pointer to the stack frame, so the
739+
// stack bias has to be considered to get the expected DSA value.
740+
void *dsaptr = static_cast<char *>(__builtin_frame_address(0)) - 2048;
741+
int count = 0;
742+
OS << " DSA Adr EP +EP DSA "
743+
" Entry\n";
744+
while (1) {
745+
// After the call, these variables contain the length of the string.
746+
int32_t compile_unit_name_length = sizeof(compile_unit_name);
747+
int32_t entry_name_length = sizeof(entry_name);
748+
int32_t statement_id_length = sizeof(statement_id);
749+
// See
750+
// https://www.ibm.com/docs/en/zos/3.1.0?topic=cwicsa6a-celqtbck-also-known-as-celqtbck-64-bit-traceback-service
751+
// for documentation of the parameters.
752+
__CELQTBCK(&dsaptr, &dsa_format, &caaptr, &member_id, &compile_unit_name[0],
753+
&compile_unit_name_length, &compile_unit_address,
754+
&call_instruction_address, &entry_name[0], &entry_name_length,
755+
&entry_address, &callers_instruction_address, &callers_dsaptr,
756+
&callers_dsa_format, &statement_id[0], &statement_id_length,
757+
&cibptr, &main_program, &fc);
758+
if (fc.tok_sev) {
759+
OS << format("error: CELQTBCK returned severity %d message %d\n",
760+
fc.tok_sev, fc.tok_msgno);
761+
break;
762+
}
763+
764+
if (count) { // Omit first entry.
765+
uintptr_t diff = reinterpret_cast<uintptr_t>(call_instruction_address) -
766+
reinterpret_cast<uintptr_t>(entry_address);
767+
OS << format(" %3d. 0x%016lX", count, call_instruction_address);
768+
OS << format(" 0x%016lX +0x%08lX 0x%016lX", entry_address, diff, dsaptr);
769+
SmallString<256> Str;
770+
ConverterEBCDIC::convertToUTF8(StringRef(entry_name, entry_name_length),
771+
Str);
772+
OS << ' ' << Str << '\n';
773+
}
774+
++count;
775+
if (callers_dsaptr) {
776+
dsaptr = callers_dsaptr;
777+
dsa_format = callers_dsa_format;
778+
call_instruction_address = callers_instruction_address;
779+
} else
780+
break;
781+
}
782+
}
783+
#endif
784+
711785
// In the case of a program crash or fault, print out a stack trace so that the
712786
// user has an indication of why and where we died.
713787
//
714788
// On glibc systems we have the 'backtrace' function, which works nicely, but
715789
// doesn't demangle symbols.
716790
void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) {
717791
#if ENABLE_BACKTRACES
792+
#ifdef __MVS__
793+
zosbacktrace(OS);
794+
#else
718795
static void *StackTrace[256];
719796
int depth = 0;
720797
#if defined(HAVE_BACKTRACE)
@@ -791,6 +868,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) {
791868
backtrace_symbols_fd(StackTrace, Depth, STDERR_FILENO);
792869
#endif
793870
#endif
871+
#endif
794872
}
795873

796874
static void PrintStackTraceSignalHandler(void *) {

0 commit comments

Comments
 (0)