|
79 | 79 | #undef HAVE__UNWIND_BACKTRACE
|
80 | 80 | #endif
|
81 | 81 | #endif
|
| 82 | +#if ENABLE_BACKTRACES && defined(__MVS__) |
| 83 | +#include "llvm/Support/ConvertEBCDIC.h" |
| 84 | +#include <__le_cwi.h> |
| 85 | +#endif |
82 | 86 |
|
83 | 87 | using namespace llvm;
|
84 | 88 |
|
@@ -708,13 +712,86 @@ static int unwindBacktrace(void **StackTrace, int MaxEntries) {
|
708 | 712 | }
|
709 | 713 | #endif
|
710 | 714 |
|
| 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 | + |
711 | 785 | // In the case of a program crash or fault, print out a stack trace so that the
|
712 | 786 | // user has an indication of why and where we died.
|
713 | 787 | //
|
714 | 788 | // On glibc systems we have the 'backtrace' function, which works nicely, but
|
715 | 789 | // doesn't demangle symbols.
|
716 | 790 | void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) {
|
717 | 791 | #if ENABLE_BACKTRACES
|
| 792 | +#ifdef __MVS__ |
| 793 | + zosbacktrace(OS); |
| 794 | +#else |
718 | 795 | static void *StackTrace[256];
|
719 | 796 | int depth = 0;
|
720 | 797 | #if defined(HAVE_BACKTRACE)
|
@@ -791,6 +868,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) {
|
791 | 868 | backtrace_symbols_fd(StackTrace, Depth, STDERR_FILENO);
|
792 | 869 | #endif
|
793 | 870 | #endif
|
| 871 | +#endif |
794 | 872 | }
|
795 | 873 |
|
796 | 874 | static void PrintStackTraceSignalHandler(void *) {
|
|
0 commit comments