Skip to content

[z/OS] Add backtrace support for z/OS. #121826

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 9, 2025
Merged

Conversation

redstar
Copy link
Member

@redstar redstar commented Jan 6, 2025

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

@llvmbot
Copy link
Member

llvmbot commented Jan 6, 2025

@llvm/pr-subscribers-llvm-support

Author: Kai Nacke (redstar)

Changes

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


Full diff: https://github.com/llvm/llvm-project/pull/121826.diff

1 Files Affected:

  • (modified) llvm/lib/Support/Unix/Signals.inc (+81)
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 *) {

@redstar redstar self-assigned this Jan 6, 2025
@redstar redstar requested review from MaskRay and arsenm January 6, 2025 20:23
Copy link

github-actions bot commented Jan 6, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

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
@redstar redstar force-pushed the knacke/zosbacktrace branch from df700ff to 2992483 Compare January 9, 2025 16:31
@redstar redstar merged commit ca10dea into llvm:main Jan 9, 2025
5 of 7 checks passed
BaiXilin pushed a commit to BaiXilin/llvm-fix-vnni-instr-types that referenced this pull request Jan 12, 2025
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants