diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc index 088ca33e3c8c5..50d6248ba6af8 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,76 @@ static int unwindBacktrace(void **StackTrace, int MaxEntries) { } #endif +#if ENABLE_BACKTRACES && defined(__MVS__) +static 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; + int32_t dsa_format = -1; // Input/Output + void *caaptr = _gtca(); // Input + int32_t member_id; // Output + char compile_unit_name[MAX_OTHER]; // Output + void *compile_unit_address; // Output + void *call_instruction_address = nullptr; // Input/Output + char entry_name[MAX_ENTRY_NAME]; // 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 + 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. + void *dsaptr = static_cast(__builtin_frame_address(0)) - 2048; + int count = 0; + OS << " DSA Adr EP +EP DSA " + " Entry\n"; + while (1) { + // After the call, these variables contain the length of the string. + int32_t compile_unit_name_length = sizeof(compile_unit_name); + int32_t entry_name_length = sizeof(entry_name); + int32_t 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: CELQTBCK returned severity %d message %d\n", + fc.tok_sev, fc.tok_msgno); + break; + } + + if (count) { // Omit first entry. + uintptr_t diff = reinterpret_cast(call_instruction_address) - + reinterpret_cast(entry_address); + OS << format(" %3d. 0x%016lX", count, call_instruction_address); + OS << format(" 0x%016lX +0x%08lX 0x%016lX", entry_address, diff, dsaptr); + SmallString<256> Str; + ConverterEBCDIC::convertToUTF8(StringRef(entry_name, entry_name_length), + Str); + OS << ' ' << Str << '\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 +789,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 +868,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) { backtrace_symbols_fd(StackTrace, Depth, STDERR_FILENO); #endif #endif +#endif } static void PrintStackTraceSignalHandler(void *) {