Commit 3b14d80a authored by Vedant Kumar's avatar Vedant Kumar
Browse files

[MachCore] Report arm64 thread exception state

A MachO userspace corefile may contain LC_THREAD commands which specify
thread exception state.

For arm64* only (for now), report a human-readable version of this state
as the thread stop reason, instead of 'SIGSTOP'.

As a follow-up, similar functionality can be implemented for x86 cores
by translating the trapno/err exception registers.

rdar://82898146

Differential Revision: https://reviews.llvm.org/D109795
parent bcb2591b
Loading
Loading
Loading
Loading
+50 −0
Original line number Diff line number Diff line
/*===-- AppleArm64ExceptionClass.def ---------------------------*- C++ -*-=== *\
|*
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|* See https://llvm.org/LICENSE.txt for license information.
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|*
\*===----------------------------------------------------------------------===*/

// Defines ESR exception classes for Apple arm64* targets.
// These largely map 1:1 to the exception classes defined in ARM's architecture
// reference manual, but there are some Apple-specific additions.

#ifndef APPLE_ARM64_EXCEPTION_CLASS
#error "APPLE_ARM64_EXCEPTION_CLASS(Name, Code) not defined."
#endif

APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_UNCATEGORIZED, 0x00)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_WFI_WFE, 0x01)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCR_MRC_CP15_TRAP, 0x03)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCRR_MRRC_CP15_TRAP, 0x04)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCR_MRC_CP14_TRAP, 0x05)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_LDC_STC_CP14_TRAP, 0x06)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_TRAP_SIMD_FP, 0x07)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PTRAUTH_INSTR_TRAP, 0x09)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCRR_MRRC_CP14_TRAP, 0x0c)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_ILLEGAL_INSTR_SET, 0x0e)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SVC_32, 0x11)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SVC_64, 0x15)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MSR_TRAP, 0x18)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PAC_FAIL, 0x1C)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_IABORT_EL0, 0x20)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_IABORT_EL1, 0x21)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PC_ALIGN, 0x22)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_DABORT_EL0, 0x24)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_DABORT_EL1, 0x25)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SP_ALIGN, 0x26)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_FLOATING_POINT_32, 0x28)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_FLOATING_POINT_64, 0x2C)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SERROR_INTERRUPT, 0x2F)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BKPT_REG_MATCH_EL0, 0x30)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BKPT_REG_MATCH_EL1, 0x31)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SW_STEP_DEBUG_EL0, 0x32)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SW_STEP_DEBUG_EL1, 0x33)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_WATCHPT_MATCH_EL0, 0x34)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_WATCHPT_MATCH_EL1, 0x35)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BKPT_AARCH32, 0x38)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BRK_AARCH64, 0x3C)
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PRIV, 0x3F)

#undef APPLE_ARM64_EXCEPTION_CLASS
+50 −0
Original line number Diff line number Diff line
//===-- AppleArm64ExceptionClass.h ------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_TARGET_APPLEARM64EXCEPTIONCLASS_H
#define LLDB_TARGET_APPLEARM64EXCEPTIONCLASS_H

#include <cstdint>

namespace lldb_private {

enum class AppleArm64ExceptionClass : unsigned {
#define APPLE_ARM64_EXCEPTION_CLASS(Name, Code) Name = Code,
#include "AppleArm64ExceptionClass.def"
};

/// Get the Apple ARM64 exception class encoded within \p esr.
inline AppleArm64ExceptionClass getAppleArm64ExceptionClass(uint32_t esr) {
  /*
   * Exception Syndrome Register
   *
   *  31  26 25 24               0
   * +------+--+------------------+
   * |  EC  |IL|       ISS        |
   * +------+--+------------------+
   *
   * EC  - Exception Class
   * IL  - Instruction Length
   * ISS - Instruction Specific Syndrome
   */
  return static_cast<AppleArm64ExceptionClass>(esr >> 26);
}

inline const char *toString(AppleArm64ExceptionClass EC) {
  switch (EC) {
#define APPLE_ARM64_EXCEPTION_CLASS(Name, Code)                                \
  case AppleArm64ExceptionClass::Name:                                         \
    return #Name;
#include "AppleArm64ExceptionClass.def"
  }
  return "Unknown Exception Class";
}

} // namespace lldb_private

#endif // LLDB_TARGET_APPLEARM64EXCEPTIONCLASS_H
+1 −0
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ module lldb_Wrapper {
    requires cplusplus

    umbrella "Target"
    textual header "Target/AppleArm64ExceptionClass.def"
    module * { export * }
  }
}
+6 −5
Original line number Diff line number Diff line
@@ -745,13 +745,14 @@ public:
      PrintRegisterValue(reg_ctx, "sp", nullptr, 8, data);
      PrintRegisterValue(reg_ctx, "pc", nullptr, 8, data);
      PrintRegisterValue(reg_ctx, "cpsr", nullptr, 4, data);
      data.PutHex32(0); // uint32_t pad at the end

      // Write out the EXC registers
      //            data.PutHex32 (EXCRegSet);
      //            data.PutHex32 (EXCWordCount);
      //            WriteRegister (reg_ctx, "far", NULL, 8, data);
      //            WriteRegister (reg_ctx, "esr", NULL, 4, data);
      //            WriteRegister (reg_ctx, "exception", NULL, 4, data);
      data.PutHex32(EXCRegSet);
      data.PutHex32(EXCWordCount);
      PrintRegisterValue(reg_ctx, "far", NULL, 8, data);
      PrintRegisterValue(reg_ctx, "esr", NULL, 4, data);
      PrintRegisterValue(reg_ctx, "exception", NULL, 4, data);
      return true;
    }
    return false;
+49 −1
Original line number Diff line number Diff line
@@ -9,7 +9,9 @@
#include "ThreadMachCore.h"

#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Host/SafeMachO.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/AppleArm64ExceptionClass.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
@@ -17,6 +19,7 @@
#include "lldb/Target/Unwind.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/StreamString.h"

@@ -88,10 +91,55 @@ ThreadMachCore::CreateRegisterContextForFrame(StackFrame *frame) {
  return reg_ctx_sp;
}

static bool IsCrashExceptionClass(AppleArm64ExceptionClass EC) {
  switch (EC) {
  case AppleArm64ExceptionClass::ESR_EC_UNCATEGORIZED:
  case AppleArm64ExceptionClass::ESR_EC_SVC_32:
  case AppleArm64ExceptionClass::ESR_EC_SVC_64:
    // In the ARM exception model, a process takes an exception when asking the
    // kernel to service a system call. Don't treat this like a crash.
    return false;
  default:
    return true;
  }
}

bool ThreadMachCore::CalculateStopInfo() {
  ProcessSP process_sp(GetProcess());
  if (process_sp) {
    SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, SIGSTOP));
    StopInfoSP stop_info;
    RegisterContextSP reg_ctx_sp = GetRegisterContext();

    if (reg_ctx_sp) {
      Target &target = process_sp->GetTarget();
      const ArchSpec arch_spec = target.GetArchitecture();
      const uint32_t cputype = arch_spec.GetMachOCPUType();

      if (cputype == llvm::MachO::CPU_TYPE_ARM64 ||
          cputype == llvm::MachO::CPU_TYPE_ARM64_32) {
        const RegisterInfo *esr_info = reg_ctx_sp->GetRegisterInfoByName("esr");
        const RegisterInfo *far_info = reg_ctx_sp->GetRegisterInfoByName("far");
        RegisterValue esr, far;
        if (reg_ctx_sp->ReadRegister(esr_info, esr) &&
            reg_ctx_sp->ReadRegister(far_info, far)) {
          const uint32_t esr_val = esr.GetAsUInt32();
          const AppleArm64ExceptionClass exception_class =
              getAppleArm64ExceptionClass(esr_val);
          if (IsCrashExceptionClass(exception_class)) {
            StreamString S;
            S.Printf("%s (fault address: 0x%" PRIx64 ")",
                     toString(exception_class), far.GetAsUInt64());
            stop_info =
                StopInfo::CreateStopReasonWithException(*this, S.GetData());
          }
        }
      }
    }

    // Set a stop reason for crashing threads only so that they get selected
    // preferentially.
    if (stop_info)
      SetStopInfo(stop_info);
    return true;
  }
  return false;
Loading