clayborg created this revision. clayborg added reviewers: labath, zturner, markmentovai, javed.absar. Herald added subscribers: chrib, kristof.beyls.
In this patch I add support for ARM and ARM64 break pad files. There are two flavors of ARM: Apple where FP is https://reviews.llvm.org/source/openmp/, and non Apple where FP is https://reviews.llvm.org/source/libunwind/. Added minimal tests that load up ARM64 and the two flavors or ARM core files with a single thread and known register values in each register. Each register is checked for the exact value. This is a fixed version of: https://reviews.llvm.org/D49750 The changes from https://reviews.llvm.org/D49750 are: - Don't init the m_arch in the Initialize call as a system info isn't required. This keeps the thread list, module list and other tests from failing - Added -Wextended-offsetof to Xcode project so we catch use extended usages of offsetof before submission - Fixed any extended offset of warnings https://reviews.llvm.org/D50336 Files: include/lldb/Target/Target.h lldb.xcodeproj/project.pbxproj packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/TestMiniDumpNew.py packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/arm-linux.dmp packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/arm-macos.dmp packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/arm64-macos.dmp source/Plugins/Process/minidump/MinidumpParser.cpp source/Plugins/Process/minidump/MinidumpParser.h source/Plugins/Process/minidump/ProcessMinidump.cpp source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h source/Plugins/Process/minidump/ThreadMinidump.cpp source/Target/Target.cpp
Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -1426,13 +1426,33 @@ } } -bool Target::SetArchitecture(const ArchSpec &arch_spec) { +bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET)); bool missing_local_arch = !m_arch.GetSpec().IsValid(); bool replace_local_arch = true; bool compatible_local_arch = false; ArchSpec other(arch_spec); + // Changing the architecture might mean that the currently selected platform + // isn't compatible. Set the platform correctly if we are asked to do so, + // otherwise assume the user will set the platform manually. + if (set_platform) { + if (other.IsValid()) { + auto platform_sp = GetPlatform(); + if (!platform_sp || + !platform_sp->IsCompatibleArchitecture(other, false, nullptr)) { + ArchSpec platform_arch; + auto arch_platform_sp = + Platform::GetPlatformForArchitecture(other, &platform_arch); + if (arch_platform_sp) { + SetPlatform(arch_platform_sp); + if (platform_arch.IsValid()) + other = platform_arch; + } + } + } + } + if (!missing_local_arch) { if (m_arch.GetSpec().IsCompatibleMatch(arch_spec)) { other.MergeFrom(m_arch.GetSpec()); Index: source/Plugins/Process/minidump/ThreadMinidump.cpp =================================================================== --- source/Plugins/Process/minidump/ThreadMinidump.cpp +++ source/Plugins/Process/minidump/ThreadMinidump.cpp @@ -11,6 +11,8 @@ #include "ThreadMinidump.h" #include "ProcessMinidump.h" +#include "RegisterContextMinidump_ARM.h" +#include "RegisterContextMinidump_ARM64.h" #include "RegisterContextMinidump_x86_32.h" #include "RegisterContextMinidump_x86_64.h" @@ -88,17 +90,24 @@ *this, reg_interface, gpregset, {})); break; } + case llvm::Triple::aarch64: { + DataExtractor data(m_gpregset_data.data(), m_gpregset_data.size(), + lldb::eByteOrderLittle, 8); + m_thread_reg_ctx_sp.reset(new RegisterContextMinidump_ARM64(*this, data)); + break; + } + case llvm::Triple::arm: { + DataExtractor data(m_gpregset_data.data(), m_gpregset_data.size(), + lldb::eByteOrderLittle, 8); + const bool apple = arch.GetTriple().getVendor() == llvm::Triple::Apple; + m_thread_reg_ctx_sp.reset( + new RegisterContextMinidump_ARM(*this, data, apple)); + break; + } default: break; } - if (!reg_interface) { - if (log) - log->Printf("elf-core::%s:: Architecture(%d) not supported", - __FUNCTION__, arch.GetMachine()); - assert(false && "Architecture not supported"); - } - reg_ctx_sp = m_thread_reg_ctx_sp; } else if (m_unwinder_ap) { reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame(frame); Index: source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h =================================================================== --- source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h +++ source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h @@ -0,0 +1,85 @@ +//===-- RegisterContextMinidump_ARM64.h -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextMinidump_ARM64_h_ +#define liblldb_RegisterContextMinidump_ARM64_h_ + +// Project includes +#include "MinidumpTypes.h" + +// Other libraries and framework includes +#include "Plugins/Process/Utility/RegisterInfoInterface.h" +#include "lldb/Target/RegisterContext.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitmaskEnum.h" + +// C includes +// C++ includes + +namespace lldb_private { + +namespace minidump { + +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + +class RegisterContextMinidump_ARM64 : public lldb_private::RegisterContext { +public: + RegisterContextMinidump_ARM64(lldb_private::Thread &thread, + const DataExtractor &data); + + ~RegisterContextMinidump_ARM64() override = default; + + void InvalidateAllRegisters() override { + // Do nothing... registers are always valid... + } + + size_t GetRegisterCount() override; + + const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; + + size_t GetRegisterSetCount() override; + + const lldb_private::RegisterSet *GetRegisterSet(size_t set) override; + + const char *GetRegisterName(unsigned reg); + + bool ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + bool WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) override; + + // Reference: see breakpad/crashpad source + struct Context { + uint64_t context_flags; + uint64_t x[32]; + uint64_t pc; + uint32_t cpsr; + uint32_t fpsr; + uint32_t fpcr; + uint8_t v[32 * 16]; // 32 128-bit floating point registers + }; + +protected: + enum class Flags : uint32_t { + ARM64_Flag = 0x80000000, + Integer = ARM64_Flag | 0x00000002, + FloatingPoint = ARM64_Flag | 0x00000004, + LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ FloatingPoint) + }; + Context m_regs; +}; + +} // end namespace minidump +} // end namespace lldb_private +#endif // liblldb_RegisterContextMinidump_ARM64_h_ Index: source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp =================================================================== --- source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp +++ source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp @@ -0,0 +1,836 @@ +//===-- RegisterContextMinidump_ARM64.cpp -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Project includes +#include "RegisterContextMinidump_ARM64.h" + +// Other libraries and framework includes +#include "Utility/ARM64_DWARF_Registers.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/lldb-enumerations.h" + +// C includes +#include <assert.h> + +// C++ includes + +using namespace lldb; +using namespace lldb_private; +using namespace minidump; + +#define INV LLDB_INVALID_REGNUM +#define OFFSET(r) (offsetof(RegisterContextMinidump_ARM64::Context, r)) + +#define DEF_X(i) \ + { \ + "x" #i, nullptr, 8, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \ + {INV, arm64_dwarf::x##i, INV, INV, reg_x##i}, nullptr, nullptr, \ + nullptr, 0 \ + } + +#define DEF_W(i) \ + { \ + "w" #i, nullptr, 4, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \ + {INV, INV, INV, INV, reg_w##i}, nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_X_ARG(i, n) \ + { \ + "x" #i, "arg" #n, 8, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \ + {INV, arm64_dwarf::x##i, LLDB_REGNUM_GENERIC_ARG1 + i, INV, reg_x##i}, \ + nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_V(i) \ + { \ + "v" #i, nullptr, 16, OFFSET(v) + i * 16, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, arm64_dwarf::v##i, INV, INV, reg_v##i}, \ + nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_D(i) \ + { \ + "d" #i, nullptr, 8, OFFSET(v) + i * 16, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_d##i}, nullptr, \ + nullptr, nullptr, 0 \ + } + +#define DEF_S(i) \ + { \ + "s" #i, nullptr, 4, OFFSET(v) + i * 16, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_s##i}, nullptr, \ + nullptr, nullptr, 0 \ + } + +#define DEF_H(i) \ + { \ + "h" #i, nullptr, 2, OFFSET(v) + i * 16, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_h##i}, nullptr, \ + nullptr, nullptr, 0 \ + } + +// Zero based LLDB register numbers for this register context +enum { + // General Purpose Registers + reg_x0 = 0, + reg_x1, + reg_x2, + reg_x3, + reg_x4, + reg_x5, + reg_x6, + reg_x7, + reg_x8, + reg_x9, + reg_x10, + reg_x11, + reg_x12, + reg_x13, + reg_x14, + reg_x15, + reg_x16, + reg_x17, + reg_x18, + reg_x19, + reg_x20, + reg_x21, + reg_x22, + reg_x23, + reg_x24, + reg_x25, + reg_x26, + reg_x27, + reg_x28, + reg_fp, + reg_lr, + reg_sp, + reg_pc, + reg_w0, + reg_w1, + reg_w2, + reg_w3, + reg_w4, + reg_w5, + reg_w6, + reg_w7, + reg_w8, + reg_w9, + reg_w10, + reg_w11, + reg_w12, + reg_w13, + reg_w14, + reg_w15, + reg_w16, + reg_w17, + reg_w18, + reg_w19, + reg_w20, + reg_w21, + reg_w22, + reg_w23, + reg_w24, + reg_w25, + reg_w26, + reg_w27, + reg_w28, + reg_w29, + reg_w30, + reg_w31, + reg_cpsr, + // Floating Point Registers + reg_fpsr, + reg_fpcr, + reg_v0, + reg_v1, + reg_v2, + reg_v3, + reg_v4, + reg_v5, + reg_v6, + reg_v7, + reg_v8, + reg_v9, + reg_v10, + reg_v11, + reg_v12, + reg_v13, + reg_v14, + reg_v15, + reg_v16, + reg_v17, + reg_v18, + reg_v19, + reg_v20, + reg_v21, + reg_v22, + reg_v23, + reg_v24, + reg_v25, + reg_v26, + reg_v27, + reg_v28, + reg_v29, + reg_v30, + reg_v31, + reg_d0, + reg_d1, + reg_d2, + reg_d3, + reg_d4, + reg_d5, + reg_d6, + reg_d7, + reg_d8, + reg_d9, + reg_d10, + reg_d11, + reg_d12, + reg_d13, + reg_d14, + reg_d15, + reg_d16, + reg_d17, + reg_d18, + reg_d19, + reg_d20, + reg_d21, + reg_d22, + reg_d23, + reg_d24, + reg_d25, + reg_d26, + reg_d27, + reg_d28, + reg_d29, + reg_d30, + reg_d31, + reg_s0, + reg_s1, + reg_s2, + reg_s3, + reg_s4, + reg_s5, + reg_s6, + reg_s7, + reg_s8, + reg_s9, + reg_s10, + reg_s11, + reg_s12, + reg_s13, + reg_s14, + reg_s15, + reg_s16, + reg_s17, + reg_s18, + reg_s19, + reg_s20, + reg_s21, + reg_s22, + reg_s23, + reg_s24, + reg_s25, + reg_s26, + reg_s27, + reg_s28, + reg_s29, + reg_s30, + reg_s31, + reg_h0, + reg_h1, + reg_h2, + reg_h3, + reg_h4, + reg_h5, + reg_h6, + reg_h7, + reg_h8, + reg_h9, + reg_h10, + reg_h11, + reg_h12, + reg_h13, + reg_h14, + reg_h15, + reg_h16, + reg_h17, + reg_h18, + reg_h19, + reg_h20, + reg_h21, + reg_h22, + reg_h23, + reg_h24, + reg_h25, + reg_h26, + reg_h27, + reg_h28, + reg_h29, + reg_h30, + reg_h31, + k_num_regs +}; + +// Register info definitions for this register context +static RegisterInfo g_reg_infos[] = { + DEF_X_ARG(0, 1), + DEF_X_ARG(1, 2), + DEF_X_ARG(2, 3), + DEF_X_ARG(3, 4), + DEF_X_ARG(4, 5), + DEF_X_ARG(5, 6), + DEF_X_ARG(6, 7), + DEF_X_ARG(7, 8), + DEF_X(8), + DEF_X(9), + DEF_X(10), + DEF_X(11), + DEF_X(12), + DEF_X(13), + DEF_X(14), + DEF_X(15), + DEF_X(16), + DEF_X(17), + DEF_X(18), + DEF_X(19), + DEF_X(20), + DEF_X(21), + DEF_X(22), + DEF_X(23), + DEF_X(24), + DEF_X(25), + DEF_X(26), + DEF_X(27), + DEF_X(28), + {"fp", + "x29", + 8, + OFFSET(x[29]), + eEncodingUint, + eFormatHex, + {INV, arm64_dwarf::x29, LLDB_REGNUM_GENERIC_FP, INV, reg_fp}, + nullptr, + nullptr, + nullptr, + 0}, + {"lr", + "x30", + 8, + OFFSET(x[30]), + eEncodingUint, + eFormatHex, + {INV, arm64_dwarf::x30, LLDB_REGNUM_GENERIC_RA, INV, reg_lr}, + nullptr, + nullptr, + nullptr, + 0}, + {"sp", + "x31", + 8, + OFFSET(x[31]), + eEncodingUint, + eFormatHex, + {INV, arm64_dwarf::x31, LLDB_REGNUM_GENERIC_SP, INV, reg_sp}, + nullptr, + nullptr, + nullptr, + 0}, + {"pc", + nullptr, + 8, + OFFSET(pc), + eEncodingUint, + eFormatHex, + {INV, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc}, + nullptr, + nullptr, + nullptr, + 0}, + // w0 - w31 + DEF_W(0), + DEF_W(1), + DEF_W(2), + DEF_W(3), + DEF_W(4), + DEF_W(5), + DEF_W(6), + DEF_W(7), + DEF_W(8), + DEF_W(9), + DEF_W(10), + DEF_W(11), + DEF_W(12), + DEF_W(13), + DEF_W(14), + DEF_W(15), + DEF_W(16), + DEF_W(17), + DEF_W(18), + DEF_W(19), + DEF_W(20), + DEF_W(21), + DEF_W(22), + DEF_W(23), + DEF_W(24), + DEF_W(25), + DEF_W(26), + DEF_W(27), + DEF_W(28), + DEF_W(29), + DEF_W(30), + DEF_W(31), + {"cpsr", + "psr", + 4, + OFFSET(cpsr), + eEncodingUint, + eFormatHex, + {INV, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr}, + nullptr, + nullptr, + nullptr, + 0}, + {"fpsr", + nullptr, + 4, + OFFSET(fpsr), + eEncodingUint, + eFormatHex, + {INV, INV, INV, INV, reg_fpsr}, + nullptr, + nullptr, + nullptr, + 0}, + {"fpcr", + nullptr, + 4, + OFFSET(fpcr), + eEncodingUint, + eFormatHex, + {INV, INV, INV, INV, reg_fpcr}, + nullptr, + nullptr, + nullptr, + 0}, + // v0 - v31 + DEF_V(0), + DEF_V(1), + DEF_V(2), + DEF_V(3), + DEF_V(4), + DEF_V(5), + DEF_V(6), + DEF_V(7), + DEF_V(8), + DEF_V(9), + DEF_V(10), + DEF_V(11), + DEF_V(12), + DEF_V(13), + DEF_V(14), + DEF_V(15), + DEF_V(16), + DEF_V(17), + DEF_V(18), + DEF_V(19), + DEF_V(20), + DEF_V(21), + DEF_V(22), + DEF_V(23), + DEF_V(24), + DEF_V(25), + DEF_V(26), + DEF_V(27), + DEF_V(28), + DEF_V(29), + DEF_V(30), + DEF_V(31), + // d0 - d31 + DEF_D(0), + DEF_D(1), + DEF_D(2), + DEF_D(3), + DEF_D(4), + DEF_D(5), + DEF_D(6), + DEF_D(7), + DEF_D(8), + DEF_D(9), + DEF_D(10), + DEF_D(11), + DEF_D(12), + DEF_D(13), + DEF_D(14), + DEF_D(15), + DEF_D(16), + DEF_D(17), + DEF_D(18), + DEF_D(19), + DEF_D(20), + DEF_D(21), + DEF_D(22), + DEF_D(23), + DEF_D(24), + DEF_D(25), + DEF_D(26), + DEF_D(27), + DEF_D(28), + DEF_D(29), + DEF_D(30), + DEF_D(31), + // s0 - s31 + DEF_S(0), + DEF_S(1), + DEF_S(2), + DEF_S(3), + DEF_S(4), + DEF_S(5), + DEF_S(6), + DEF_S(7), + DEF_S(8), + DEF_S(9), + DEF_S(10), + DEF_S(11), + DEF_S(12), + DEF_S(13), + DEF_S(14), + DEF_S(15), + DEF_S(16), + DEF_S(17), + DEF_S(18), + DEF_S(19), + DEF_S(20), + DEF_S(21), + DEF_S(22), + DEF_S(23), + DEF_S(24), + DEF_S(25), + DEF_S(26), + DEF_S(27), + DEF_S(28), + DEF_S(29), + DEF_S(30), + DEF_S(31), + // h0 - h31 + DEF_H(0), + DEF_H(1), + DEF_H(2), + DEF_H(3), + DEF_H(4), + DEF_H(5), + DEF_H(6), + DEF_H(7), + DEF_H(8), + DEF_H(9), + DEF_H(10), + DEF_H(11), + DEF_H(12), + DEF_H(13), + DEF_H(14), + DEF_H(15), + DEF_H(16), + DEF_H(17), + DEF_H(18), + DEF_H(19), + DEF_H(20), + DEF_H(21), + DEF_H(22), + DEF_H(23), + DEF_H(24), + DEF_H(25), + DEF_H(26), + DEF_H(27), + DEF_H(28), + DEF_H(29), + DEF_H(30), + DEF_H(31), +}; + +constexpr size_t k_num_reg_infos = llvm::array_lengthof(g_reg_infos); + +// ARM64 general purpose registers. +const uint32_t g_gpr_regnums[] = { + reg_x0, + reg_x1, + reg_x2, + reg_x3, + reg_x4, + reg_x5, + reg_x6, + reg_x7, + reg_x8, + reg_x9, + reg_x10, + reg_x11, + reg_x12, + reg_x13, + reg_x14, + reg_x15, + reg_x16, + reg_x17, + reg_x18, + reg_x19, + reg_x20, + reg_x21, + reg_x22, + reg_x23, + reg_x24, + reg_x25, + reg_x26, + reg_x27, + reg_x28, + reg_fp, + reg_lr, + reg_sp, + reg_w0, + reg_w1, + reg_w2, + reg_w3, + reg_w4, + reg_w5, + reg_w6, + reg_w7, + reg_w8, + reg_w9, + reg_w10, + reg_w11, + reg_w12, + reg_w13, + reg_w14, + reg_w15, + reg_w16, + reg_w17, + reg_w18, + reg_w19, + reg_w20, + reg_w21, + reg_w22, + reg_w23, + reg_w24, + reg_w25, + reg_w26, + reg_w27, + reg_w28, + reg_w29, + reg_w30, + reg_w31, + reg_pc, + reg_cpsr, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +const uint32_t g_fpu_regnums[] = { + reg_v0, + reg_v1, + reg_v2, + reg_v3, + reg_v4, + reg_v5, + reg_v6, + reg_v7, + reg_v8, + reg_v9, + reg_v10, + reg_v11, + reg_v12, + reg_v13, + reg_v14, + reg_v15, + reg_v16, + reg_v17, + reg_v18, + reg_v19, + reg_v20, + reg_v21, + reg_v22, + reg_v23, + reg_v24, + reg_v25, + reg_v26, + reg_v27, + reg_v28, + reg_v29, + reg_v30, + reg_v31, + reg_d0, + reg_d1, + reg_d2, + reg_d3, + reg_d4, + reg_d5, + reg_d6, + reg_d7, + reg_d8, + reg_d9, + reg_d10, + reg_d11, + reg_d12, + reg_d13, + reg_d14, + reg_d15, + reg_d16, + reg_d17, + reg_d18, + reg_d19, + reg_d20, + reg_d21, + reg_d22, + reg_d23, + reg_d24, + reg_d25, + reg_d26, + reg_d27, + reg_d28, + reg_d29, + reg_d30, + reg_d31, + reg_s0, + reg_s1, + reg_s2, + reg_s3, + reg_s4, + reg_s5, + reg_s6, + reg_s7, + reg_s8, + reg_s9, + reg_s10, + reg_s11, + reg_s12, + reg_s13, + reg_s14, + reg_s15, + reg_s16, + reg_s17, + reg_s18, + reg_s19, + reg_s20, + reg_s21, + reg_s22, + reg_s23, + reg_s24, + reg_s25, + reg_s26, + reg_s27, + reg_s28, + reg_s29, + reg_s30, + reg_s31, + reg_h0, + reg_h1, + reg_h2, + reg_h3, + reg_h4, + reg_h5, + reg_h6, + reg_h7, + reg_h8, + reg_h9, + reg_h10, + reg_h11, + reg_h12, + reg_h13, + reg_h14, + reg_h15, + reg_h16, + reg_h17, + reg_h18, + reg_h19, + reg_h20, + reg_h21, + reg_h22, + reg_h23, + reg_h24, + reg_h25, + reg_h26, + reg_h27, + reg_h28, + reg_h29, + reg_h30, + reg_h31, + reg_fpsr, + reg_fpcr, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +// Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1 +constexpr size_t k_num_gpr_regs = llvm::array_lengthof(g_gpr_regnums) - 1; +constexpr size_t k_num_fpu_regs = llvm::array_lengthof(g_fpu_regnums) - 1; + +static RegisterSet g_reg_sets[] = { + {"General Purpose Registers", "gpr", k_num_gpr_regs, g_gpr_regnums}, + {"Floating Point Registers", "fpu", k_num_fpu_regs, g_fpu_regnums}, +}; + +constexpr size_t k_num_reg_sets = llvm::array_lengthof(g_reg_sets); + +RegisterContextMinidump_ARM64::RegisterContextMinidump_ARM64( + Thread &thread, const DataExtractor &data) + : RegisterContext(thread, 0) { + lldb::offset_t offset = 0; + m_regs.context_flags = data.GetU64(&offset); + for (unsigned i = 0; i < 32; ++i) + m_regs.x[i] = data.GetU64(&offset); + m_regs.pc = data.GetU64(&offset); + m_regs.cpsr = data.GetU32(&offset); + m_regs.fpsr = data.GetU32(&offset); + m_regs.fpcr = data.GetU32(&offset); + auto regs_data = data.GetData(&offset, sizeof(m_regs.v)); + if (regs_data) + memcpy(m_regs.v, regs_data, sizeof(m_regs.v)); + assert(k_num_regs == k_num_reg_infos); +} +size_t RegisterContextMinidump_ARM64::GetRegisterCount() { return k_num_regs; } + +const RegisterInfo * +RegisterContextMinidump_ARM64::GetRegisterInfoAtIndex(size_t reg) { + if (reg < k_num_reg_infos) + return &g_reg_infos[reg]; + return nullptr; +} + +size_t RegisterContextMinidump_ARM64::GetRegisterSetCount() { + return k_num_reg_sets; +} + +const RegisterSet *RegisterContextMinidump_ARM64::GetRegisterSet(size_t set) { + if (set < k_num_reg_sets) + return &g_reg_sets[set]; + return nullptr; +} + +const char *RegisterContextMinidump_ARM64::GetRegisterName(unsigned reg) { + if (reg < k_num_reg_infos) + return g_reg_infos[reg].name; + return nullptr; +} + +bool RegisterContextMinidump_ARM64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + reg_value.SetFromMemoryData( + reg_info, (const uint8_t *)&m_regs + reg_info->byte_offset, + reg_info->byte_size, lldb::eByteOrderLittle, error); + return error.Success(); +} + +bool RegisterContextMinidump_ARM64::WriteRegister(const RegisterInfo *, + const RegisterValue &) { + return false; +} + +uint32_t RegisterContextMinidump_ARM64::ConvertRegisterKindToRegisterNumber( + lldb::RegisterKind kind, uint32_t num) { + for (size_t i = 0; i < k_num_regs; ++i) { + if (g_reg_infos[i].kinds[kind] == num) + return i; + } + return LLDB_INVALID_REGNUM; +} Index: source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h =================================================================== --- source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h +++ source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h @@ -0,0 +1,95 @@ +//===-- RegisterContextMinidump_ARM.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextMinidump_ARM_h_ +#define liblldb_RegisterContextMinidump_ARM_h_ + +// Project includes +#include "MinidumpTypes.h" + +// Other libraries and framework includes +#include "Plugins/Process/Utility/RegisterInfoInterface.h" + +#include "lldb/Target/RegisterContext.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitmaskEnum.h" + +// C includes +// C++ includes + +namespace lldb_private { + +namespace minidump { + +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + +class RegisterContextMinidump_ARM : public lldb_private::RegisterContext { +public: + RegisterContextMinidump_ARM(lldb_private::Thread &thread, + const DataExtractor &data, bool apple); + + ~RegisterContextMinidump_ARM() override = default; + + void InvalidateAllRegisters() override { + // Do nothing... registers are always valid... + } + + size_t GetRegisterCount() override; + + const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; + + size_t GetRegisterSetCount() override; + + const lldb_private::RegisterSet *GetRegisterSet(size_t set) override; + + const char *GetRegisterName(unsigned reg); + + bool ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + bool WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) override; + + // Reference: see breakpad/crashpad source + struct QRegValue { + uint64_t lo; + uint64_t hi; + }; + + struct Context { + uint32_t context_flags; + uint32_t r[16]; + uint32_t cpsr; + uint64_t fpscr; + union { + uint64_t d[32]; + uint32_t s[32]; + QRegValue q[16]; + }; + uint32_t extra[8]; + }; + +protected: + enum class Flags : uint32_t { + ARM_Flag = 0x40000000, + Integer = ARM_Flag | 0x00000002, + FloatingPoint = ARM_Flag | 0x00000004, + LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ FloatingPoint) + }; + Context m_regs; + const bool m_apple; // True if this is an Apple ARM where FP is R7 +}; + +} // end namespace minidump +} // end namespace lldb_private +#endif // liblldb_RegisterContextMinidump_ARM_h_ Index: source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp =================================================================== --- source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp +++ source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp @@ -0,0 +1,534 @@ +//===-- RegisterContextMinidump_ARM.cpp -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Project includes +#include "RegisterContextMinidump_ARM.h" + +// Other libraries and framework includes +#include "Utility/ARM_DWARF_Registers.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/lldb-enumerations.h" + +// C includes +#include <assert.h> + +// C++ includes + +using namespace lldb; +using namespace lldb_private; +using namespace minidump; + +#define INV LLDB_INVALID_REGNUM +#define OFFSET(r) (offsetof(RegisterContextMinidump_ARM::Context, r)) + +#define DEF_R(i) \ + { \ + "r" #i, nullptr, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \ + {INV, dwarf_r##i, INV, INV, reg_r##i}, nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_R_ARG(i, n) \ + { \ + "r" #i, "arg" #n, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \ + {INV, dwarf_r##i, LLDB_REGNUM_GENERIC_ARG1 + i, INV, reg_r##i}, \ + nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_D(i) \ + { \ + "d" #i, nullptr, 8, OFFSET(d) + i * 8, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, dwarf_d##i, INV, INV, reg_d##i}, \ + nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_S(i) \ + { \ + "s" #i, nullptr, 4, OFFSET(s) + i * 4, eEncodingIEEE754, eFormatFloat, \ + {INV, dwarf_s##i, INV, INV, reg_s##i}, nullptr, nullptr, nullptr, 0 \ + } + +#define DEF_Q(i) \ + { \ + "q" #i, nullptr, 16, OFFSET(q) + i * 16, eEncodingVector, \ + eFormatVectorOfUInt8, {INV, dwarf_q##i, INV, INV, reg_q##i}, \ + nullptr, nullptr, nullptr, 0 \ + } + +// Zero based LLDB register numbers for this register context +enum { + // General Purpose Registers + reg_r0, + reg_r1, + reg_r2, + reg_r3, + reg_r4, + reg_r5, + reg_r6, + reg_r7, + reg_r8, + reg_r9, + reg_r10, + reg_r11, + reg_r12, + reg_sp, + reg_lr, + reg_pc, + reg_cpsr, + // Floating Point Registers + reg_fpscr, + reg_d0, + reg_d1, + reg_d2, + reg_d3, + reg_d4, + reg_d5, + reg_d6, + reg_d7, + reg_d8, + reg_d9, + reg_d10, + reg_d11, + reg_d12, + reg_d13, + reg_d14, + reg_d15, + reg_d16, + reg_d17, + reg_d18, + reg_d19, + reg_d20, + reg_d21, + reg_d22, + reg_d23, + reg_d24, + reg_d25, + reg_d26, + reg_d27, + reg_d28, + reg_d29, + reg_d30, + reg_d31, + reg_s0, + reg_s1, + reg_s2, + reg_s3, + reg_s4, + reg_s5, + reg_s6, + reg_s7, + reg_s8, + reg_s9, + reg_s10, + reg_s11, + reg_s12, + reg_s13, + reg_s14, + reg_s15, + reg_s16, + reg_s17, + reg_s18, + reg_s19, + reg_s20, + reg_s21, + reg_s22, + reg_s23, + reg_s24, + reg_s25, + reg_s26, + reg_s27, + reg_s28, + reg_s29, + reg_s30, + reg_s31, + reg_q0, + reg_q1, + reg_q2, + reg_q3, + reg_q4, + reg_q5, + reg_q6, + reg_q7, + reg_q8, + reg_q9, + reg_q10, + reg_q11, + reg_q12, + reg_q13, + reg_q14, + reg_q15, + k_num_regs +}; + +static RegisterInfo g_reg_info_apple_fp = { + "fp", + "r7", + 4, + OFFSET(r) + 7 * 4, + eEncodingUint, + eFormatHex, + {INV, dwarf_r7, LLDB_REGNUM_GENERIC_FP, INV, reg_r7}, + nullptr, + nullptr, + nullptr, + 0}; + +static RegisterInfo g_reg_info_fp = { + "fp", + "r11", + 4, + OFFSET(r) + 11 * 4, + eEncodingUint, + eFormatHex, + {INV, dwarf_r11, LLDB_REGNUM_GENERIC_FP, INV, reg_r11}, + nullptr, + nullptr, + nullptr, + 0}; + +// Register info definitions for this register context +static RegisterInfo g_reg_infos[] = { + DEF_R_ARG(0, 1), + DEF_R_ARG(1, 2), + DEF_R_ARG(2, 3), + DEF_R_ARG(3, 4), + DEF_R(4), + DEF_R(5), + DEF_R(6), + DEF_R(7), + DEF_R(8), + DEF_R(9), + DEF_R(10), + DEF_R(11), + DEF_R(12), + {"sp", + "r13", + 4, + OFFSET(r) + 13 * 4, + eEncodingUint, + eFormatHex, + {INV, dwarf_sp, LLDB_REGNUM_GENERIC_SP, INV, reg_sp}, + nullptr, + nullptr, + nullptr, + 0}, + {"lr", + "r14", + 4, + OFFSET(r) + 14 * 4, + eEncodingUint, + eFormatHex, + {INV, dwarf_lr, LLDB_REGNUM_GENERIC_RA, INV, reg_lr}, + nullptr, + nullptr, + nullptr, + 0}, + {"pc", + "r15", + 4, + OFFSET(r) + 15 * 4, + eEncodingUint, + eFormatHex, + {INV, dwarf_pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc}, + nullptr, + nullptr, + nullptr, + 0}, + {"cpsr", + "psr", + 4, + OFFSET(cpsr), + eEncodingUint, + eFormatHex, + {INV, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr}, + nullptr, + nullptr, + nullptr, + 0}, + {"fpscr", + nullptr, + 8, + OFFSET(fpscr), + eEncodingUint, + eFormatHex, + {INV, INV, INV, INV, reg_fpscr}, + nullptr, + nullptr, + nullptr, + 0}, + DEF_D(0), + DEF_D(1), + DEF_D(2), + DEF_D(3), + DEF_D(4), + DEF_D(5), + DEF_D(6), + DEF_D(7), + DEF_D(8), + DEF_D(9), + DEF_D(10), + DEF_D(11), + DEF_D(12), + DEF_D(13), + DEF_D(14), + DEF_D(15), + DEF_D(16), + DEF_D(17), + DEF_D(18), + DEF_D(19), + DEF_D(20), + DEF_D(21), + DEF_D(22), + DEF_D(23), + DEF_D(24), + DEF_D(25), + DEF_D(26), + DEF_D(27), + DEF_D(28), + DEF_D(29), + DEF_D(30), + DEF_D(31), + DEF_S(0), + DEF_S(1), + DEF_S(2), + DEF_S(3), + DEF_S(4), + DEF_S(5), + DEF_S(6), + DEF_S(7), + DEF_S(8), + DEF_S(9), + DEF_S(10), + DEF_S(11), + DEF_S(12), + DEF_S(13), + DEF_S(14), + DEF_S(15), + DEF_S(16), + DEF_S(17), + DEF_S(18), + DEF_S(19), + DEF_S(20), + DEF_S(21), + DEF_S(22), + DEF_S(23), + DEF_S(24), + DEF_S(25), + DEF_S(26), + DEF_S(27), + DEF_S(28), + DEF_S(29), + DEF_S(30), + DEF_S(31), + DEF_Q(0), + DEF_Q(1), + DEF_Q(2), + DEF_Q(3), + DEF_Q(4), + DEF_Q(5), + DEF_Q(6), + DEF_Q(7), + DEF_Q(8), + DEF_Q(9), + DEF_Q(10), + DEF_Q(11), + DEF_Q(12), + DEF_Q(13), + DEF_Q(14), + DEF_Q(15)}; + +constexpr size_t k_num_reg_infos = llvm::array_lengthof(g_reg_infos); + +// ARM general purpose registers. +const uint32_t g_gpr_regnums[] = { + reg_r0, + reg_r1, + reg_r2, + reg_r3, + reg_r4, + reg_r5, + reg_r6, + reg_r7, + reg_r8, + reg_r9, + reg_r10, + reg_r11, + reg_r12, + reg_sp, + reg_lr, + reg_pc, + reg_cpsr, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +const uint32_t g_fpu_regnums[] = { + reg_fpscr, + reg_d0, + reg_d1, + reg_d2, + reg_d3, + reg_d4, + reg_d5, + reg_d6, + reg_d7, + reg_d8, + reg_d9, + reg_d10, + reg_d11, + reg_d12, + reg_d13, + reg_d14, + reg_d15, + reg_d16, + reg_d17, + reg_d18, + reg_d19, + reg_d20, + reg_d21, + reg_d22, + reg_d23, + reg_d24, + reg_d25, + reg_d26, + reg_d27, + reg_d28, + reg_d29, + reg_d30, + reg_d31, + reg_s0, + reg_s1, + reg_s2, + reg_s3, + reg_s4, + reg_s5, + reg_s6, + reg_s7, + reg_s8, + reg_s9, + reg_s10, + reg_s11, + reg_s12, + reg_s13, + reg_s14, + reg_s15, + reg_s16, + reg_s17, + reg_s18, + reg_s19, + reg_s20, + reg_s21, + reg_s22, + reg_s23, + reg_s24, + reg_s25, + reg_s26, + reg_s27, + reg_s28, + reg_s29, + reg_s30, + reg_s31, + reg_q0, + reg_q1, + reg_q2, + reg_q3, + reg_q4, + reg_q5, + reg_q6, + reg_q7, + reg_q8, + reg_q9, + reg_q10, + reg_q11, + reg_q12, + reg_q13, + reg_q14, + reg_q15, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +// Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1 +constexpr size_t k_num_gpr_regs = llvm::array_lengthof(g_gpr_regnums) - 1; +constexpr size_t k_num_fpu_regs = llvm::array_lengthof(g_fpu_regnums) - 1; + +static RegisterSet g_reg_sets[] = { + {"General Purpose Registers", "gpr", k_num_gpr_regs, g_gpr_regnums}, + {"Floating Point Registers", "fpu", k_num_fpu_regs, g_fpu_regnums}, +}; + +constexpr size_t k_num_reg_sets = llvm::array_lengthof(g_reg_sets); + +RegisterContextMinidump_ARM::RegisterContextMinidump_ARM( + Thread &thread, const DataExtractor &data, bool apple) + : RegisterContext(thread, 0), m_apple(apple) { + lldb::offset_t offset = 0; + m_regs.context_flags = data.GetU32(&offset); + for (unsigned i = 0; i < llvm::array_lengthof(m_regs.r); ++i) + m_regs.r[i] = data.GetU32(&offset); + m_regs.cpsr = data.GetU32(&offset); + m_regs.fpscr = data.GetU64(&offset); + for (unsigned i = 0; i < llvm::array_lengthof(m_regs.d); ++i) + m_regs.d[i] = data.GetU64(&offset); + lldbassert(k_num_regs == k_num_reg_infos); +} + +size_t RegisterContextMinidump_ARM::GetRegisterCount() { return k_num_regs; } + +const RegisterInfo * +RegisterContextMinidump_ARM::GetRegisterInfoAtIndex(size_t reg) { + if (reg < k_num_reg_infos) { + if (m_apple) { + if (reg == reg_r7) + return &g_reg_info_apple_fp; + } else { + if (reg == reg_r11) + return &g_reg_info_fp; + } + return &g_reg_infos[reg]; + } + return nullptr; +} + +size_t RegisterContextMinidump_ARM::GetRegisterSetCount() { + return k_num_reg_sets; +} + +const RegisterSet *RegisterContextMinidump_ARM::GetRegisterSet(size_t set) { + if (set < k_num_reg_sets) + return &g_reg_sets[set]; + return nullptr; +} + +const char *RegisterContextMinidump_ARM::GetRegisterName(unsigned reg) { + if (reg < k_num_reg_infos) + return g_reg_infos[reg].name; + return nullptr; +} + +bool RegisterContextMinidump_ARM::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + reg_value.SetFromMemoryData( + reg_info, (const uint8_t *)&m_regs + reg_info->byte_offset, + reg_info->byte_size, lldb::eByteOrderLittle, error); + return error.Success(); +} + +bool RegisterContextMinidump_ARM::WriteRegister(const RegisterInfo *, + const RegisterValue &) { + return false; +} + +uint32_t RegisterContextMinidump_ARM::ConvertRegisterKindToRegisterNumber( + lldb::RegisterKind kind, uint32_t num) { + for (size_t i = 0; i < k_num_regs; ++i) { + if (g_reg_infos[i].kinds[kind] == num) + return i; + } + return LLDB_INVALID_REGNUM; +} Index: source/Plugins/Process/minidump/ProcessMinidump.cpp =================================================================== --- source/Plugins/Process/minidump/ProcessMinidump.cpp +++ source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -29,6 +29,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Threading.h" +#include "Plugins/Process/Utility/StopInfoMachException.h" // C includes // C++ includes @@ -174,19 +175,21 @@ switch (arch.GetMachine()) { case llvm::Triple::x86: case llvm::Triple::x86_64: - // supported + case llvm::Triple::arm: + case llvm::Triple::aarch64: + // Any supported architectures must be listed here and also supported in + // ThreadMinidump::CreateRegisterContextForFrame(). break; - default: error.SetErrorStringWithFormat("unsupported minidump architecture: %s", arch.GetArchitectureName()); return error; } + GetTarget().SetArchitecture(arch, true /*set_platform*/); m_thread_list = m_minidump_parser.GetThreads(); m_active_exception = m_minidump_parser.GetExceptionStream(); ReadModuleList(); - GetTarget().SetArchitecture(arch); llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid(); if (!pid) { @@ -229,6 +232,11 @@ if (arch.GetTriple().getOS() == llvm::Triple::Linux) { stop_info = StopInfo::CreateStopReasonWithSignal( *stop_thread, m_active_exception->exception_record.exception_code); + } else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) { + stop_info = StopInfoMachException::CreateStopReasonWithMachException( + *stop_thread, m_active_exception->exception_record.exception_code, 2, + m_active_exception->exception_record.exception_flags, + m_active_exception->exception_record.exception_address, 0); } else { std::string desc; llvm::raw_string_ostream desc_stream(desc); Index: source/Plugins/Process/minidump/MinidumpParser.h =================================================================== --- source/Plugins/Process/minidump/MinidumpParser.h +++ source/Plugins/Process/minidump/MinidumpParser.h @@ -98,6 +98,7 @@ private: lldb::DataBufferSP m_data_sp; llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> m_directory_map; + ArchSpec m_arch; }; } // end namespace minidump Index: source/Plugins/Process/minidump/MinidumpParser.cpp =================================================================== --- source/Plugins/Process/minidump/MinidumpParser.cpp +++ source/Plugins/Process/minidump/MinidumpParser.cpp @@ -146,11 +146,15 @@ } ArchSpec MinidumpParser::GetArchitecture() { - ArchSpec arch_spec; + + if (m_arch.IsValid()) + return m_arch; + + // Set the architecture in m_arch const MinidumpSystemInfo *system_info = GetSystemInfo(); if (!system_info) - return arch_spec; + return m_arch; // TODO what to do about big endiand flavors of arm ? // TODO set the arm subarch stuff if the minidump has info about it @@ -196,19 +200,29 @@ break; case MinidumpOSPlatform::MacOSX: triple.setOS(llvm::Triple::OSType::MacOSX); + triple.setVendor(llvm::Triple::Apple); break; + case MinidumpOSPlatform::IOS: + triple.setOS(llvm::Triple::OSType::IOS); + triple.setVendor(llvm::Triple::Apple); + break; case MinidumpOSPlatform::Android: triple.setOS(llvm::Triple::OSType::Linux); triple.setEnvironment(llvm::Triple::EnvironmentType::Android); break; - default: + default: { triple.setOS(llvm::Triple::OSType::UnknownOS); + std::string csd_version; + if (auto s = GetMinidumpString(system_info->csd_version_rva)) + csd_version = *s; + if (csd_version.find("Linux") != std::string::npos) + triple.setOS(llvm::Triple::OSType::Linux); break; + } } - - arch_spec.SetTriple(triple); - - return arch_spec; + m_arch.SetTriple(triple); + + return m_arch; } const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() { Index: packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/TestMiniDumpNew.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/TestMiniDumpNew.py +++ packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/TestMiniDumpNew.py @@ -189,6 +189,161 @@ stop_description = thread.GetStopDescription(256) self.assertEqual(stop_description, "") + def check_register_unsigned(self, set, name, expected): + reg_value = set.GetChildMemberWithName(name) + self.assertTrue(reg_value.IsValid(), + 'Verify we have a register named "%s"' % (name)) + self.assertEqual(reg_value.GetValueAsUnsigned(), expected, + 'Verify "%s" == %i' % (name, expected)) + + def check_register_string_value(self, set, name, expected, format): + reg_value = set.GetChildMemberWithName(name) + self.assertTrue(reg_value.IsValid(), + 'Verify we have a register named "%s"' % (name)) + if format is not None: + reg_value.SetFormat(format) + self.assertEqual(reg_value.GetValue(), expected, + 'Verify "%s" has string value "%s"' % (name, + expected)) + + def test_arm64_registers(self): + """Test ARM64 registers from a breakpad created minidump.""" + # target create -c arm64-macos.dmp + self.dbg.CreateTarget(None) + self.target = self.dbg.GetSelectedTarget() + self.process = self.target.LoadCore("arm64-macos.dmp") + self.check_state() + self.assertEqual(self.process.GetNumThreads(), 1) + thread = self.process.GetThreadAtIndex(0) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonNone) + stop_description = thread.GetStopDescription(256) + self.assertEqual(stop_description, "") + registers = thread.GetFrameAtIndex(0).GetRegisters() + # Verify the GPR registers are all correct + # Verify x0 - x31 register values + gpr = registers.GetValueAtIndex(0) + for i in range(32): + v = i+1 | i+2 << 32 | i+3 << 48 + w = i+1 + self.check_register_unsigned(gpr, 'x%i' % (i), v) + self.check_register_unsigned(gpr, 'w%i' % (i), w) + # Verify arg1 - arg8 register values + for i in range(1, 9): + v = i | i+1 << 32 | i+2 << 48 + self.check_register_unsigned(gpr, 'arg%i' % (i), v) + i = 29 + v = i+1 | i+2 << 32 | i+3 << 48 + self.check_register_unsigned(gpr, 'fp', v) + i = 30 + v = i+1 | i+2 << 32 | i+3 << 48 + self.check_register_unsigned(gpr, 'lr', v) + i = 31 + v = i+1 | i+2 << 32 | i+3 << 48 + self.check_register_unsigned(gpr, 'sp', v) + self.check_register_unsigned(gpr, 'pc', 0x1000) + self.check_register_unsigned(gpr, 'cpsr', 0x11223344) + self.check_register_unsigned(gpr, 'psr', 0x11223344) + + # Verify the FPR registers are all correct + fpr = registers.GetValueAtIndex(1) + for i in range(32): + v = "0x" + d = "0x" + s = "0x" + h = "0x" + for j in range(i+15, i-1, -1): + v += "%2.2x" % (j) + for j in range(i+7, i-1, -1): + d += "%2.2x" % (j) + for j in range(i+3, i-1, -1): + s += "%2.2x" % (j) + for j in range(i+1, i-1, -1): + h += "%2.2x" % (j) + self.check_register_string_value(fpr, "v%i" % (i), v, + lldb.eFormatHex) + self.check_register_string_value(fpr, "d%i" % (i), d, + lldb.eFormatHex) + self.check_register_string_value(fpr, "s%i" % (i), s, + lldb.eFormatHex) + self.check_register_string_value(fpr, "h%i" % (i), h, + lldb.eFormatHex) + self.check_register_unsigned(gpr, 'fpsr', 0x55667788) + self.check_register_unsigned(gpr, 'fpcr', 0x99aabbcc) + + def verify_arm_registers(self, apple=False): + """ + Verify values of all ARM registers from a breakpad created + minidump. + """ + self.dbg.CreateTarget(None) + self.target = self.dbg.GetSelectedTarget() + if apple: + self.process = self.target.LoadCore("arm-macos.dmp") + else: + self.process = self.target.LoadCore("arm-linux.dmp") + self.check_state() + self.assertEqual(self.process.GetNumThreads(), 1) + thread = self.process.GetThreadAtIndex(0) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonNone) + stop_description = thread.GetStopDescription(256) + self.assertEqual(stop_description, "") + registers = thread.GetFrameAtIndex(0).GetRegisters() + # Verify the GPR registers are all correct + # Verify x0 - x31 register values + gpr = registers.GetValueAtIndex(0) + for i in range(1, 16): + self.check_register_unsigned(gpr, 'r%i' % (i), i+1) + # Verify arg1 - arg4 register values + for i in range(1, 5): + self.check_register_unsigned(gpr, 'arg%i' % (i), i) + if apple: + self.check_register_unsigned(gpr, 'fp', 0x08) + else: + self.check_register_unsigned(gpr, 'fp', 0x0c) + self.check_register_unsigned(gpr, 'lr', 0x0f) + self.check_register_unsigned(gpr, 'sp', 0x0e) + self.check_register_unsigned(gpr, 'pc', 0x10) + self.check_register_unsigned(gpr, 'cpsr', 0x11223344) + + # Verify the FPR registers are all correct + fpr = registers.GetValueAtIndex(1) + # Check d0 - d31 + self.check_register_unsigned(gpr, 'fpscr', 0x55667788aabbccdd) + for i in range(32): + value = (i+1) | (i+1) << 8 | (i+1) << 32 | (i+1) << 48 + self.check_register_unsigned(fpr, "d%i" % (i), value) + # Check s0 - s31 + for i in range(32): + i_val = (i >> 1) + 1 + if i & 1: + value = "%#8.8x" % (i_val | i_val << 16) + else: + value = "%#8.8x" % (i_val | i_val << 8) + self.check_register_string_value(fpr, "s%i" % (i), value, + lldb.eFormatHex) + # Check q0 - q15 + for i in range(15): + a = i * 2 + 1 + b = a + 1 + value = ("0x00%2.2x00%2.2x0000%2.2x%2.2x" + "00%2.2x00%2.2x0000%2.2x%2.2x") % (b, b, b, b, a, a, a, a) + self.check_register_string_value(fpr, "q%i" % (i), value, + lldb.eFormatHex) + + def test_linux_arm_registers(self): + """Test Linux ARM registers from a breakpad created minidump. + + The frame pointer is R11 for linux. + """ + self.verify_arm_registers(apple=False) + + def test_apple_arm_registers(self): + """Test Apple ARM registers from a breakpad created minidump. + + The frame pointer is R7 for linux. + """ + self.verify_arm_registers(apple=True) + def do_test_deeper_stack(self, binary, core, pid): target = self.dbg.CreateTarget(binary) process = target.LoadCore(core) Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -65,7 +65,6 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ - 228B1B672113340200E61C70 /* ClangHighlighter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 58A080AB2112AABB00D5580F /* ClangHighlighter.cpp */; }; 268900E813353E6F00698AC0 /* ABI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 497E7B9D1188F6690065CCA1 /* ABI.cpp */; }; 26DB3E161379E7AD0080DC73 /* ABIMacOSX_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DB3E071379E7AD0080DC73 /* ABIMacOSX_arm.cpp */; }; 26DB3E191379E7AD0080DC73 /* ABIMacOSX_arm64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DB3E0B1379E7AD0080DC73 /* ABIMacOSX_arm64.cpp */; }; @@ -159,8 +158,7 @@ 268900D313353E6F00698AC0 /* ClangExternalASTSourceCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26E69030129C6BEF00DDECD9 /* ClangExternalASTSourceCallbacks.cpp */; }; 4966DCC4148978A10028481B /* ClangExternalASTSourceCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4966DCC3148978A10028481B /* ClangExternalASTSourceCommon.cpp */; }; 2689005F13353E0E00698AC0 /* ClangFunctionCaller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3DA118FB96F00E575D0 /* ClangFunctionCaller.cpp */; }; - 58A080AC2112AABB00D5580F /* ClangHighlighter.cpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 58A080AB2112AABB00D5580F /* ClangHighlighter.cpp */; }; - 58A080AE2112AAC500D5580F /* ClangHighlighter.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 58A080AD2112AAC500D5580F /* ClangHighlighter.h */; }; + 228B1B672113340200E61C70 /* ClangHighlighter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 58A080AB2112AABB00D5580F /* ClangHighlighter.cpp */; }; 4CD44D5820C603CB0003557C /* ClangHost.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD44D5620C603A80003557C /* ClangHost.cpp */; }; 4959511F1A1BC4BC00F6F8FC /* ClangModulesDeclVendor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4959511E1A1BC4BC00F6F8FC /* ClangModulesDeclVendor.cpp */; }; 2689006313353E0E00698AC0 /* ClangPersistentVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49D4FE871210B61C00CDB854 /* ClangPersistentVariables.cpp */; }; @@ -665,6 +663,10 @@ 26474CBE18D0CB2D0073DEBA /* RegisterContextMach_i386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26474CB818D0CB2D0073DEBA /* RegisterContextMach_i386.cpp */; }; 26474CC018D0CB2D0073DEBA /* RegisterContextMach_x86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26474CBA18D0CB2D0073DEBA /* RegisterContextMach_x86_64.cpp */; }; 26474CC918D0CB5B0073DEBA /* RegisterContextMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26474CC218D0CB5B0073DEBA /* RegisterContextMemory.cpp */; }; + 2619C4852107A9A2009CDE81 /* RegisterContextMinidump_ARM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2619C4812107A9A1009CDE81 /* RegisterContextMinidump_ARM.cpp */; }; + 2619C4872107A9A2009CDE81 /* RegisterContextMinidump_ARM.h in Headers */ = {isa = PBXBuildFile; fileRef = 2619C4832107A9A2009CDE81 /* RegisterContextMinidump_ARM.h */; }; + 2619C4842107A9A2009CDE81 /* RegisterContextMinidump_ARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2619C4802107A9A1009CDE81 /* RegisterContextMinidump_ARM64.cpp */; }; + 2619C4862107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h in Headers */ = {isa = PBXBuildFile; fileRef = 2619C4822107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h */; }; 947CF7761DC7B20D00EF980B /* RegisterContextMinidump_x86_32.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 947CF7741DC7B20D00EF980B /* RegisterContextMinidump_x86_32.cpp */; }; AFD65C811D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFD65C7F1D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp */; }; AFD65C821D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = AFD65C801D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.h */; }; @@ -2542,6 +2544,10 @@ 26474CC218D0CB5B0073DEBA /* RegisterContextMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContextMemory.cpp; path = Utility/RegisterContextMemory.cpp; sourceTree = "<group>"; }; 262D24E513FB8710002D1960 /* RegisterContextMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextMemory.h; path = Utility/RegisterContextMemory.h; sourceTree = "<group>"; }; 26474CC318D0CB5B0073DEBA /* RegisterContextMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextMemory.h; path = Utility/RegisterContextMemory.h; sourceTree = "<group>"; }; + 2619C4812107A9A1009CDE81 /* RegisterContextMinidump_ARM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMinidump_ARM.cpp; sourceTree = "<group>"; }; + 2619C4832107A9A2009CDE81 /* RegisterContextMinidump_ARM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextMinidump_ARM.h; sourceTree = "<group>"; }; + 2619C4802107A9A1009CDE81 /* RegisterContextMinidump_ARM64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMinidump_ARM64.cpp; sourceTree = "<group>"; }; + 2619C4822107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextMinidump_ARM64.h; sourceTree = "<group>"; }; 947CF7741DC7B20D00EF980B /* RegisterContextMinidump_x86_32.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMinidump_x86_32.cpp; sourceTree = "<group>"; }; 947CF7721DC7B20300EF980B /* RegisterContextMinidump_x86_32.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RegisterContextMinidump_x86_32.h; sourceTree = "<group>"; }; AFD65C7F1D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMinidump_x86_64.cpp; sourceTree = "<group>"; }; @@ -3787,6 +3793,10 @@ 23E2E5351D9048E7006F38BB /* minidump */ = { isa = PBXGroup; children = ( + 2619C4812107A9A1009CDE81 /* RegisterContextMinidump_ARM.cpp */, + 2619C4832107A9A2009CDE81 /* RegisterContextMinidump_ARM.h */, + 2619C4802107A9A1009CDE81 /* RegisterContextMinidump_ARM64.cpp */, + 2619C4822107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h */, AFD65C7F1D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp */, AFD65C801D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.h */, 23E2E5361D9048FB006F38BB /* CMakeLists.txt */, @@ -6939,8 +6949,10 @@ AF6CA6681FBBAF37005A0DC3 /* ArchSpec.h in Headers */, AF235EB41FBE7858009C5541 /* RegisterInfoPOSIX_ppc64le.h in Headers */, AF2E02A41FA2CEAF00A86C34 /* ArchitectureArm.h in Headers */, + 2619C4872107A9A2009CDE81 /* RegisterContextMinidump_ARM.h in Headers */, 267F685A1CC02EBE0086832B /* RegisterInfos_s390x.h in Headers */, 267F68541CC02E920086832B /* RegisterContextLinux_s390x.h in Headers */, + 2619C4862107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h in Headers */, AF235EB11FBE77B6009C5541 /* RegisterContextPOSIX_ppc64le.h in Headers */, 267F68501CC02E270086832B /* RegisterContextPOSIXCore_s390x.h in Headers */, 4984BA181B979C08008658D4 /* ExpressionVariable.h in Headers */, @@ -7643,6 +7655,7 @@ 2689002113353DDE00698AC0 /* CommandObjectQuit.cpp in Sources */, 2689002213353DDE00698AC0 /* CommandObjectRegister.cpp in Sources */, 26BC17AF18C7F4CB00D2196D /* RegisterContextPOSIXCore_x86_64.cpp in Sources */, + 2619C4842107A9A2009CDE81 /* RegisterContextMinidump_ARM64.cpp in Sources */, 2689002313353DDE00698AC0 /* CommandObjectScript.cpp in Sources */, 2689002413353DDE00698AC0 /* CommandObjectSettings.cpp in Sources */, 2689002513353DDE00698AC0 /* CommandObjectSource.cpp in Sources */, @@ -7723,6 +7736,7 @@ 2689005113353E0400698AC0 /* StringList.cpp in Sources */, 2689005213353E0400698AC0 /* Timer.cpp in Sources */, 2689005413353E0400698AC0 /* UserSettingsController.cpp in Sources */, + 2619C4852107A9A2009CDE81 /* RegisterContextMinidump_ARM.cpp in Sources */, 23059A0719532B96007B8189 /* LinuxSignals.cpp in Sources */, 8CCB017E19BA28A80009FD44 /* ThreadCollection.cpp in Sources */, 9A77AD541E64E2760025CE04 /* RegisterInfoPOSIX_arm.cpp in Sources */, @@ -9347,12 +9361,14 @@ "-Wglobal-constructors", "$(OTHER_CFLAGS)", "-DLIBXML2_DEFINED", + "-Wextended-offsetof", ); "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*]" = ( "-fno-rtti", "-Wglobal-constructors", "$(OTHER_CFLAGS)", "-DLIBXML2_DEFINED", + "-Wextended-offsetof", ); OTHER_LDFLAGS = ""; PATH = /opt/local/bin; @@ -9404,12 +9420,14 @@ "-Wglobal-constructors", "$(OTHER_CFLAGS)", "-DLIBXML2_DEFINED", + "-Wextended-offsetof", ); "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*]" = ( "-fno-rtti", "-Wglobal-constructors", "$(OTHER_CFLAGS)", "-DLIBXML2_DEFINED", + "-Wextended-offsetof", ); OTHER_LDFLAGS = ""; PATH = /opt/local/bin; @@ -9461,12 +9479,14 @@ "-Wglobal-constructors", "$(OTHER_CFLAGS)", "-DLIBXML2_DEFINED", + "-Wextended-offsetof", ); "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*]" = ( "-fno-rtti", "-Wglobal-constructors", "$(OTHER_CFLAGS)", "-DLIBXML2_DEFINED", + "-Wextended-offsetof", ); OTHER_LDFLAGS = ""; PATH = /opt/local/bin; @@ -10468,12 +10488,14 @@ "-Wglobal-constructors", "$(OTHER_CFLAGS)", "-DLIBXML2_DEFINED", + "-Wextended-offsetof", ); "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*]" = ( "-fno-rtti", "-Wglobal-constructors", "$(OTHER_CFLAGS)", "-DLIBXML2_DEFINED", + "-Wextended-offsetof", ); OTHER_LDFLAGS = ""; PATH = /opt/local/bin; Index: include/lldb/Target/Target.h =================================================================== --- include/lldb/Target/Target.h +++ include/lldb/Target/Target.h @@ -913,28 +913,30 @@ /// Set the architecture for this target. /// /// If the current target has no Images read in, then this just sets the - /// architecture, which will - /// be used to select the architecture of the ExecutableModule when that is - /// set. - /// If the current target has an ExecutableModule, then calling - /// SetArchitecture with a different + /// architecture, which will be used to select the architecture of the + /// ExecutableModule when that is set. If the current target has an + /// ExecutableModule, then calling SetArchitecture with a different /// architecture from the currently selected one will reset the - /// ExecutableModule to that slice - /// of the file backing the ExecutableModule. If the file backing the - /// ExecutableModule does not - /// contain a fork of this architecture, then this code will return false, and - /// the architecture - /// won't be changed. - /// If the input arch_spec is the same as the already set architecture, this - /// is a no-op. + /// ExecutableModule to that slice of the file backing the ExecutableModule. + /// If the file backing the ExecutableModule does not contain a fork of this + /// architecture, then this code will return false, and the architecture + /// won't be changed. If the input arch_spec is the same as the already set + /// architecture, this is a no-op. /// /// @param[in] arch_spec /// The new architecture. /// + /// @param[in] set_platform + /// If \b true, then the platform will be adjusted if the currently + /// selected platform is not compatible with the archicture being set. + /// If \b false, then just the architecture will be set even if the + /// currently selected platform isn't compatible (in case it might be + /// manually set following this function call). + /// /// @return /// \b true if the architecture was successfully set, \bfalse otherwise. //------------------------------------------------------------------ - bool SetArchitecture(const ArchSpec &arch_spec); + bool SetArchitecture(const ArchSpec &arch_spec, bool set_platform = false); bool MergeArchitecture(const ArchSpec &arch_spec);
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits