diff options
Diffstat (limited to 'source/Plugins')
103 files changed, 7910 insertions, 2176 deletions
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp index a9f8f3b668dcc..5073b13f09ab7 100644 --- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp +++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp @@ -801,6 +801,36 @@ ABIMacOSX_arm::RegisterIsVolatile (const RegisterInfo *reg_info) break; } } + else if (name[0] == 'q') + { + switch (name[1]) + { + case '1': + switch (name[2]) + { + case '\0': + return true; // q1 is volatile + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + return true; // q10-q15 are volatile + default: + break; + }; + case '0': + case '2': + case '3': + return name[2] == '\0'; // q0-q3 are volatile + case '8': + case '9': + return name[2] == '\0'; // q8-q9 are volatile + default: + break; + } + } else if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') return true; } diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h index 6f7b339e28a2a..eee43943d73ac 100644 --- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h +++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h @@ -53,13 +53,7 @@ public: virtual bool RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info); - - virtual bool - StackUsesFrames () - { - return true; - } - + virtual bool CallFrameAddressIsValid (lldb::addr_t cfa) { @@ -88,12 +82,6 @@ public: return pc & ~(lldb::addr_t)1; } - virtual bool - FunctionCallsChangeCFA () - { - return false; - } - virtual const lldb_private::RegisterInfo * GetRegisterInfoArray (uint32_t &count); diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp index 8f7962d095fc1..465257db31d89 100644 --- a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp +++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp @@ -440,11 +440,11 @@ ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueO } const uint32_t type_flags = return_value_type.GetTypeInfo (NULL); - if (type_flags & ClangASTType::eTypeIsScalar || - type_flags & ClangASTType::eTypeIsPointer) + if (type_flags & eTypeIsScalar || + type_flags & eTypeIsPointer) { - if (type_flags & ClangASTType::eTypeIsInteger || - type_flags & ClangASTType::eTypeIsPointer ) + if (type_flags & eTypeIsInteger || + type_flags & eTypeIsPointer ) { // Extract the register context so we can read arguments from registers lldb::offset_t offset = 0; @@ -477,9 +477,9 @@ ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueO error.SetErrorString("We don't support returning longer than 128 bit integer values at present."); } } - else if (type_flags & ClangASTType::eTypeIsFloat) + else if (type_flags & eTypeIsFloat) { - if (type_flags & ClangASTType::eTypeIsComplex) + if (type_flags & eTypeIsComplex) { // Don't handle complex yet. error.SetErrorString ("returning complex float values are not supported"); @@ -519,7 +519,7 @@ ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueO } } } - else if (type_flags & ClangASTType::eTypeIsVector) + else if (type_flags & eTypeIsVector) { if (byte_size > 0) { @@ -874,14 +874,14 @@ ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_ const size_t byte_size = return_clang_type.GetByteSize(); const uint32_t type_flags = return_clang_type.GetTypeInfo (NULL); - if (type_flags & ClangASTType::eTypeIsScalar || - type_flags & ClangASTType::eTypeIsPointer) + if (type_flags & eTypeIsScalar || + type_flags & eTypeIsPointer) { value.SetValueType(Value::eValueTypeScalar); bool success = false; - if (type_flags & ClangASTType::eTypeIsInteger || - type_flags & ClangASTType::eTypeIsPointer ) + if (type_flags & eTypeIsInteger || + type_flags & eTypeIsPointer ) { // Extract the register context so we can read arguments from registers if (byte_size <= 8) @@ -890,7 +890,7 @@ ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_ if (x0_reg_info) { uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, 0); - const bool is_signed = (type_flags & ClangASTType::eTypeIsSigned) != 0; + const bool is_signed = (type_flags & eTypeIsSigned) != 0; switch (byte_size) { default: @@ -965,9 +965,9 @@ ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_ } } } - else if (type_flags & ClangASTType::eTypeIsFloat) + else if (type_flags & eTypeIsFloat) { - if (type_flags & ClangASTType::eTypeIsComplex) + if (type_flags & eTypeIsComplex) { // Don't handle complex yet. } @@ -1010,7 +1010,7 @@ ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_ ConstString("")); } - else if (type_flags & ClangASTType::eTypeIsVector) + else if (type_flags & eTypeIsVector) { if (byte_size > 0) { @@ -1046,8 +1046,8 @@ ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_ } } } - else if (type_flags & ClangASTType::eTypeIsStructUnion || - type_flags & ClangASTType::eTypeIsClass) + else if (type_flags & eTypeIsStructUnion || + type_flags & eTypeIsClass) { DataExtractor data; diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h index 0753b23ce2a20..6cce6a6f11741 100644 --- a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h +++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h @@ -46,15 +46,7 @@ public: virtual bool RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info); - - - virtual bool - StackUsesFrames () - { - // MacOSX uses frame pointers. - return true; - } - + // The arm64 ABI requires that stack frames be 16 byte aligned. // When there is a trap handler on the stack, e.g. _sigtramp in userland // code, we've seen that the stack pointer is often not aligned properly @@ -87,12 +79,6 @@ public: return true; } - virtual bool - FunctionCallsChangeCFA () - { - return false; - } - virtual const lldb_private::RegisterInfo * GetRegisterInfoArray (uint32_t &count); diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h index 43784a5c91116..d81b7a7e684b0 100644 --- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h +++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h @@ -64,13 +64,7 @@ public: virtual bool RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info); - - virtual bool - StackUsesFrames () - { - return true; - } - + // The Darwin i386 ABI requires that stack frames be 16 byte aligned. // When there is a trap handler on the stack, e.g. _sigtramp in userland // code, we've seen that the stack pointer is often not aligned properly @@ -102,12 +96,6 @@ public: return pc <= UINT32_MAX; } - virtual bool - FunctionCallsChangeCFA () - { - return true; - } - virtual const lldb_private::RegisterInfo * GetRegisterInfoArray (uint32_t &count); diff --git a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h index 989c4a16710a0..1550a38c4f3b2 100644 --- a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h +++ b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h @@ -75,13 +75,7 @@ public: virtual bool RegisterIsVolatile ( const lldb_private::RegisterInfo *reg_info ); - - virtual bool - StackUsesFrames ( void ) - { - return true; - } - + virtual bool CallFrameAddressIsValid ( lldb::addr_t cfa ) { @@ -101,12 +95,6 @@ public: return true; } - virtual bool - FunctionCallsChangeCFA ( void ) - { - return true; - } - virtual const lldb_private::RegisterInfo * GetRegisterInfoArray ( uint32_t &count ); diff --git a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp new file mode 100644 index 0000000000000..adb3313d1a306 --- /dev/null +++ b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp @@ -0,0 +1,1120 @@ +//===-- ABISysV_ppc.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ABISysV_ppc.h" + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Core/ValueObjectMemory.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" + +using namespace lldb; +using namespace lldb_private; + +enum gcc_dwarf_regnums +{ + gcc_dwarf_r0 = 0, + gcc_dwarf_r1, + gcc_dwarf_r2, + gcc_dwarf_r3, + gcc_dwarf_r4, + gcc_dwarf_r5, + gcc_dwarf_r6, + gcc_dwarf_r7, + gcc_dwarf_r8, + gcc_dwarf_r9, + gcc_dwarf_r10, + gcc_dwarf_r11, + gcc_dwarf_r12, + gcc_dwarf_r13, + gcc_dwarf_r14, + gcc_dwarf_r15, + gcc_dwarf_r16, + gcc_dwarf_r17, + gcc_dwarf_r18, + gcc_dwarf_r19, + gcc_dwarf_r20, + gcc_dwarf_r21, + gcc_dwarf_r22, + gcc_dwarf_r23, + gcc_dwarf_r24, + gcc_dwarf_r25, + gcc_dwarf_r26, + gcc_dwarf_r27, + gcc_dwarf_r28, + gcc_dwarf_r29, + gcc_dwarf_r30, + gcc_dwarf_r31, + gcc_dwarf_f0, + gcc_dwarf_f1, + gcc_dwarf_f2, + gcc_dwarf_f3, + gcc_dwarf_f4, + gcc_dwarf_f5, + gcc_dwarf_f6, + gcc_dwarf_f7, + gcc_dwarf_f8, + gcc_dwarf_f9, + gcc_dwarf_f10, + gcc_dwarf_f11, + gcc_dwarf_f12, + gcc_dwarf_f13, + gcc_dwarf_f14, + gcc_dwarf_f15, + gcc_dwarf_f16, + gcc_dwarf_f17, + gcc_dwarf_f18, + gcc_dwarf_f19, + gcc_dwarf_f20, + gcc_dwarf_f21, + gcc_dwarf_f22, + gcc_dwarf_f23, + gcc_dwarf_f24, + gcc_dwarf_f25, + gcc_dwarf_f26, + gcc_dwarf_f27, + gcc_dwarf_f28, + gcc_dwarf_f29, + gcc_dwarf_f30, + gcc_dwarf_f31, + gcc_dwarf_cr, + gcc_dwarf_fpscr, + gcc_dwarf_xer = 101, + gcc_dwarf_lr = 108, + gcc_dwarf_ctr, + gcc_dwarf_pc, + gcc_dwarf_cfa, +}; + +enum gdb_regnums +{ + gdb_r0 = 0, + gdb_r1, + gdb_r2, + gdb_r3, + gdb_r4, + gdb_r5, + gdb_r6, + gdb_r7, + gdb_r8, + gdb_r9, + gdb_r10, + gdb_r11, + gdb_r12, + gdb_r13, + gdb_r14, + gdb_r15, + gdb_r16, + gdb_r17, + gdb_r18, + gdb_r19, + gdb_r20, + gdb_r21, + gdb_r22, + gdb_r23, + gdb_r24, + gdb_r25, + gdb_r26, + gdb_r27, + gdb_r28, + gdb_r29, + gdb_r30, + gdb_r31, + gdb_lr, + gdb_cr, + gdb_xer, + gdb_ctr, + gdb_pc, +}; + + +// Note that the size and offset will be updated by platform-specific classes. +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, 8, 0, eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4}, NULL, NULL } +static const RegisterInfo +g_register_infos[] = +{ + // General purpose registers. GCC, DWARF, Generic, GDB + DEFINE_GPR(r0, NULL, gcc_dwarf_r0, gcc_dwarf_r0, LLDB_INVALID_REGNUM, gdb_r0), + DEFINE_GPR(r1, "sp", gcc_dwarf_r1, gcc_dwarf_r1, LLDB_REGNUM_GENERIC_SP, gdb_r1), + DEFINE_GPR(r2, NULL, gcc_dwarf_r2, gcc_dwarf_r2, LLDB_INVALID_REGNUM, gdb_r2), + DEFINE_GPR(r3, "arg1",gcc_dwarf_r3, gcc_dwarf_r3, LLDB_REGNUM_GENERIC_ARG1, gdb_r3), + DEFINE_GPR(r4, "arg2",gcc_dwarf_r4, gcc_dwarf_r4, LLDB_REGNUM_GENERIC_ARG2 ,gdb_r4), + DEFINE_GPR(r5, "arg3",gcc_dwarf_r5, gcc_dwarf_r5, LLDB_REGNUM_GENERIC_ARG3, gdb_r5), + DEFINE_GPR(r6, "arg4",gcc_dwarf_r6, gcc_dwarf_r6, LLDB_REGNUM_GENERIC_ARG4, gdb_r6), + DEFINE_GPR(r7, "arg5",gcc_dwarf_r7, gcc_dwarf_r7, LLDB_REGNUM_GENERIC_ARG5, gdb_r7), + DEFINE_GPR(r8, "arg6",gcc_dwarf_r8, gcc_dwarf_r8, LLDB_REGNUM_GENERIC_ARG6, gdb_r8), + DEFINE_GPR(r9, "arg7",gcc_dwarf_r9, gcc_dwarf_r9, LLDB_REGNUM_GENERIC_ARG7, gdb_r9), + DEFINE_GPR(r10, "arg8",gcc_dwarf_r10, gcc_dwarf_r10, LLDB_REGNUM_GENERIC_ARG8, gdb_r10), + DEFINE_GPR(r11, NULL, gcc_dwarf_r11, gcc_dwarf_r11, LLDB_INVALID_REGNUM, gdb_r11), + DEFINE_GPR(r12, NULL, gcc_dwarf_r12, gcc_dwarf_r12, LLDB_INVALID_REGNUM, gdb_r12), + DEFINE_GPR(r13, NULL, gcc_dwarf_r13, gcc_dwarf_r13, LLDB_INVALID_REGNUM, gdb_r13), + DEFINE_GPR(r14, NULL, gcc_dwarf_r14, gcc_dwarf_r14, LLDB_INVALID_REGNUM, gdb_r14), + DEFINE_GPR(r15, NULL, gcc_dwarf_r15, gcc_dwarf_r15, LLDB_INVALID_REGNUM, gdb_r15), + DEFINE_GPR(r16, NULL, gcc_dwarf_r16, gcc_dwarf_r16, LLDB_INVALID_REGNUM, gdb_r16), + DEFINE_GPR(r17, NULL, gcc_dwarf_r17, gcc_dwarf_r17, LLDB_INVALID_REGNUM, gdb_r17), + DEFINE_GPR(r18, NULL, gcc_dwarf_r18, gcc_dwarf_r18, LLDB_INVALID_REGNUM, gdb_r18), + DEFINE_GPR(r19, NULL, gcc_dwarf_r19, gcc_dwarf_r19, LLDB_INVALID_REGNUM, gdb_r19), + DEFINE_GPR(r20, NULL, gcc_dwarf_r20, gcc_dwarf_r20, LLDB_INVALID_REGNUM, gdb_r20), + DEFINE_GPR(r21, NULL, gcc_dwarf_r21, gcc_dwarf_r21, LLDB_INVALID_REGNUM, gdb_r21), + DEFINE_GPR(r22, NULL, gcc_dwarf_r22, gcc_dwarf_r22, LLDB_INVALID_REGNUM, gdb_r22), + DEFINE_GPR(r23, NULL, gcc_dwarf_r23, gcc_dwarf_r23, LLDB_INVALID_REGNUM, gdb_r23), + DEFINE_GPR(r24, NULL, gcc_dwarf_r24, gcc_dwarf_r24, LLDB_INVALID_REGNUM, gdb_r24), + DEFINE_GPR(r25, NULL, gcc_dwarf_r25, gcc_dwarf_r25, LLDB_INVALID_REGNUM, gdb_r25), + DEFINE_GPR(r26, NULL, gcc_dwarf_r26, gcc_dwarf_r26, LLDB_INVALID_REGNUM, gdb_r26), + DEFINE_GPR(r27, NULL, gcc_dwarf_r27, gcc_dwarf_r27, LLDB_INVALID_REGNUM, gdb_r27), + DEFINE_GPR(r28, NULL, gcc_dwarf_r28, gcc_dwarf_r28, LLDB_INVALID_REGNUM, gdb_r28), + DEFINE_GPR(r29, NULL, gcc_dwarf_r29, gcc_dwarf_r29, LLDB_INVALID_REGNUM, gdb_r29), + DEFINE_GPR(r30, NULL, gcc_dwarf_r30, gcc_dwarf_r30, LLDB_INVALID_REGNUM, gdb_r30), + DEFINE_GPR(r31, NULL, gcc_dwarf_r31, gcc_dwarf_r31, LLDB_INVALID_REGNUM, gdb_r31), + DEFINE_GPR(lr, "lr", gcc_dwarf_lr, gcc_dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_lr), + DEFINE_GPR(cr, "cr", gcc_dwarf_cr, gcc_dwarf_cr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), + DEFINE_GPR(xer, "xer", gcc_dwarf_xer, gcc_dwarf_xer, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(ctr, "ctr", gcc_dwarf_ctr, gcc_dwarf_ctr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(pc, "pc", gcc_dwarf_pc, gcc_dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), + { NULL, NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_cfa, gcc_dwarf_cfa, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, NULL, NULL}, +}; + +static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); + +const lldb_private::RegisterInfo * +ABISysV_ppc::GetRegisterInfoArray (uint32_t &count) +{ + count = k_num_register_infos; + return g_register_infos; +} + + +size_t +ABISysV_ppc::GetRedZoneSize () const +{ + return 224; +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ +ABISP +ABISysV_ppc::CreateInstance (const ArchSpec &arch) +{ + static ABISP g_abi_sp; + if (arch.GetTriple().getArch() == llvm::Triple::ppc) + { + if (!g_abi_sp) + g_abi_sp.reset (new ABISysV_ppc); + return g_abi_sp; + } + return ABISP(); +} + +bool +ABISysV_ppc::PrepareTrivialCall (Thread &thread, + addr_t sp, + addr_t func_addr, + addr_t return_addr, + llvm::ArrayRef<addr_t> args) const +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + { + StreamString s; + s.Printf("ABISysV_ppc::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64, + thread.GetID(), + (uint64_t)sp, + (uint64_t)func_addr, + (uint64_t)return_addr); + + for (size_t i = 0; i < args.size(); ++i) + s.Printf (", arg%zd = 0x%" PRIx64, i + 1, args[i]); + s.PutCString (")"); + log->PutCString(s.GetString().c_str()); + } + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + const RegisterInfo *reg_info = NULL; + + if (args.size() > 8) // TODO handle more than 8 arguments + return false; + + for (size_t i = 0; i < args.size(); ++i) + { + reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); + if (log) + log->Printf("About to write arg%zd (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // First, align the SP + + if (log) + log->Printf("16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, (uint64_t)sp, (uint64_t)(sp & ~0xfull)); + + sp &= ~(0xfull); // 16-byte alignment + + sp -= 8; + + Error error; + const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + ProcessSP process_sp (thread.GetProcess()); + + RegisterValue reg_value; + +#if 0 + // This code adds an extra frame so that we don't lose the function that we came from + // by pushing the PC and the FP and then writing the current FP to point to the FP value + // we just pushed. It is disabled for now until the stack backtracing code can be debugged. + + // Save current PC + const RegisterInfo *fp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); + if (reg_ctx->ReadRegister(pc_reg_info, reg_value)) + { + if (log) + log->Printf("Pushing the current PC onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64()); + + if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error)) + return false; + + sp -= 8; + + // Save current FP + if (reg_ctx->ReadRegister(fp_reg_info, reg_value)) + { + if (log) + log->Printf("Pushing the current FP onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64()); + + if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error)) + return false; + } + // Setup FP backchain + reg_value.SetUInt64 (sp); + + if (log) + log->Printf("Writing FP: 0x%" PRIx64 " (for FP backchain)", reg_value.GetAsUInt64()); + + if (!reg_ctx->WriteRegister(fp_reg_info, reg_value)) + { + return false; + } + + sp -= 8; + } +#endif + + if (log) + log->Printf("Pushing the return address onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, (uint64_t)return_addr); + + // Save return address onto the stack + if (!process_sp->WritePointerToMemory(sp, return_addr, error)) + return false; + + // %r1 is set to the actual stack value. + + if (log) + log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp); + + if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_info, sp)) + return false; + + // %pc is set to the address of the called function. + + if (log) + log->Printf("Writing IP: 0x%" PRIx64, (uint64_t)func_addr); + + if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr)) + return false; + + return true; +} + +static bool ReadIntegerArgument(Scalar &scalar, + unsigned int bit_width, + bool is_signed, + Thread &thread, + uint32_t *argument_register_ids, + unsigned int ¤t_argument_register, + addr_t ¤t_stack_argument) +{ + if (bit_width > 64) + return false; // Scalar can't hold large integer arguments + + if (current_argument_register < 6) + { + scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned(argument_register_ids[current_argument_register], 0); + current_argument_register++; + if (is_signed) + scalar.SignExtend (bit_width); + } + else + { + uint32_t byte_size = (bit_width + (8-1))/8; + Error error; + if (thread.GetProcess()->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, is_signed, scalar, error)) + { + current_stack_argument += byte_size; + return true; + } + return false; + } + return true; +} + +bool +ABISysV_ppc::GetArgumentValues (Thread &thread, + ValueList &values) const +{ + unsigned int num_values = values.GetSize(); + unsigned int value_index; + + // Extract the register context so we can read arguments from registers + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + + if (!reg_ctx) + return false; + + // Get the pointer to the first stack argument so we have a place to start + // when reading data + + addr_t sp = reg_ctx->GetSP(0); + + if (!sp) + return false; + + addr_t current_stack_argument = sp + 48; // jump over return address + + uint32_t argument_register_ids[8]; + + argument_register_ids[0] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1)->kinds[eRegisterKindLLDB]; + argument_register_ids[1] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2)->kinds[eRegisterKindLLDB]; + argument_register_ids[2] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG3)->kinds[eRegisterKindLLDB]; + argument_register_ids[3] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG4)->kinds[eRegisterKindLLDB]; + argument_register_ids[4] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG5)->kinds[eRegisterKindLLDB]; + argument_register_ids[5] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG6)->kinds[eRegisterKindLLDB]; + argument_register_ids[6] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG7)->kinds[eRegisterKindLLDB]; + argument_register_ids[7] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG8)->kinds[eRegisterKindLLDB]; + + unsigned int current_argument_register = 0; + + for (value_index = 0; + value_index < num_values; + ++value_index) + { + Value *value = values.GetValueAtIndex(value_index); + + if (!value) + return false; + + // We currently only support extracting values with Clang QualTypes. + // Do we care about others? + ClangASTType clang_type = value->GetClangType(); + if (!clang_type) + return false; + bool is_signed; + + if (clang_type.IsIntegerType (is_signed)) + { + ReadIntegerArgument(value->GetScalar(), + clang_type.GetBitSize(), + is_signed, + thread, + argument_register_ids, + current_argument_register, + current_stack_argument); + } + else if (clang_type.IsPointerType ()) + { + ReadIntegerArgument(value->GetScalar(), + clang_type.GetBitSize(), + false, + thread, + argument_register_ids, + current_argument_register, + current_stack_argument); + } + } + + return true; +} + +Error +ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp) +{ + Error error; + if (!new_value_sp) + { + error.SetErrorString("Empty value object for return value."); + return error; + } + + ClangASTType clang_type = new_value_sp->GetClangType(); + if (!clang_type) + { + error.SetErrorString ("Null clang type for return value."); + return error; + } + + Thread *thread = frame_sp->GetThread().get(); + + bool is_signed; + uint32_t count; + bool is_complex; + + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + bool set_it_simple = false; + if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType()) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0); + + DataExtractor data; + Error data_error; + size_t num_bytes = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) + { + error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString()); + return error; + } + lldb::offset_t offset = 0; + if (num_bytes <= 8) + { + uint64_t raw_value = data.GetMaxU64(&offset, num_bytes); + + if (reg_ctx->WriteRegisterFromUnsigned (reg_info, raw_value)) + set_it_simple = true; + } + else + { + error.SetErrorString("We don't support returning longer than 64 bit integer values at present."); + } + + } + else if (clang_type.IsFloatingPointType (count, is_complex)) + { + if (is_complex) + error.SetErrorString ("We don't support returning complex values at present"); + else + { + size_t bit_width = clang_type.GetBitSize(); + if (bit_width <= 64) + { + DataExtractor data; + Error data_error; + size_t num_bytes = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) + { + error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString()); + return error; + } + + unsigned char buffer[16]; + ByteOrder byte_order = data.GetByteOrder(); + + data.CopyByteOrderedData (0, num_bytes, buffer, 16, byte_order); + set_it_simple = true; + } + else + { + // FIXME - don't know how to do 80 bit long doubles yet. + error.SetErrorString ("We don't support returning float values > 64 bits at present"); + } + } + } + + if (!set_it_simple) + { + // Okay we've got a structure or something that doesn't fit in a simple register. + // We should figure out where it really goes, but we don't support this yet. + error.SetErrorString ("We only support setting simple integer and float return types at present."); + } + + return error; +} + + +ValueObjectSP +ABISysV_ppc::GetReturnValueObjectSimple (Thread &thread, + ClangASTType &return_clang_type) const +{ + ValueObjectSP return_valobj_sp; + Value value; + + if (!return_clang_type) + return return_valobj_sp; + + //value.SetContext (Value::eContextTypeClangType, return_value_type); + value.SetClangType (return_clang_type); + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return return_valobj_sp; + + const uint32_t type_flags = return_clang_type.GetTypeInfo (); + if (type_flags & eTypeIsScalar) + { + value.SetValueType(Value::eValueTypeScalar); + + bool success = false; + if (type_flags & eTypeIsInteger) + { + // Extract the register context so we can read arguments from registers + + const size_t byte_size = return_clang_type.GetByteSize(); + uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("r3", 0), 0); + const bool is_signed = (type_flags & eTypeIsSigned) != 0; + switch (byte_size) + { + default: + break; + + case sizeof(uint64_t): + if (is_signed) + value.GetScalar() = (int64_t)(raw_value); + else + value.GetScalar() = (uint64_t)(raw_value); + success = true; + break; + + case sizeof(uint32_t): + if (is_signed) + value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); + else + value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); + success = true; + break; + + case sizeof(uint16_t): + if (is_signed) + value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); + else + value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); + success = true; + break; + + case sizeof(uint8_t): + if (is_signed) + value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); + else + value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); + success = true; + break; + } + } + else if (type_flags & eTypeIsFloat) + { + if (type_flags & eTypeIsComplex) + { + // Don't handle complex yet. + } + else + { + const size_t byte_size = return_clang_type.GetByteSize(); + if (byte_size <= sizeof(long double)) + { + const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); + RegisterValue f1_value; + if (reg_ctx->ReadRegister (f1_info, f1_value)) + { + DataExtractor data; + if (f1_value.GetData(data)) + { + lldb::offset_t offset = 0; + if (byte_size == sizeof(float)) + { + value.GetScalar() = (float) data.GetFloat(&offset); + success = true; + } + else if (byte_size == sizeof(double)) + { + value.GetScalar() = (double) data.GetDouble(&offset); + success = true; + } + } + } + } + } + } + + if (success) + return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(), + value, + ConstString("")); + + } + else if (type_flags & eTypeIsPointer) + { + unsigned r3_id = reg_ctx->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB]; + value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0); + value.SetValueType(Value::eValueTypeScalar); + return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(), + value, + ConstString("")); + } + else if (type_flags & eTypeIsVector) + { + const size_t byte_size = return_clang_type.GetByteSize(); + if (byte_size > 0) + { + + const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v0", 0); + if (altivec_reg == NULL) + altivec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0); + if (altivec_reg) + { + if (byte_size <= altivec_reg->byte_size) + { + ProcessSP process_sp (thread.GetProcess()); + if (process_sp) + { + std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0)); + const ByteOrder byte_order = process_sp->GetByteOrder(); + RegisterValue reg_value; + if (reg_ctx->ReadRegister(altivec_reg, reg_value)) + { + Error error; + if (reg_value.GetAsMemoryData (altivec_reg, + heap_data_ap->GetBytes(), + heap_data_ap->GetByteSize(), + byte_order, + error)) + { + DataExtractor data (DataBufferSP (heap_data_ap.release()), + byte_order, + process_sp->GetTarget().GetArchitecture().GetAddressByteSize()); + return_valobj_sp = ValueObjectConstResult::Create (&thread, + return_clang_type, + ConstString(""), + data); + } + } + } + } + } + } + } + + return return_valobj_sp; +} + +ValueObjectSP +ABISysV_ppc::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_clang_type) const +{ + ValueObjectSP return_valobj_sp; + + if (!return_clang_type) + return return_valobj_sp; + + ExecutionContext exe_ctx (thread.shared_from_this()); + return_valobj_sp = GetReturnValueObjectSimple(thread, return_clang_type); + if (return_valobj_sp) + return return_valobj_sp; + + RegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); + if (!reg_ctx_sp) + return return_valobj_sp; + + const size_t bit_width = return_clang_type.GetBitSize(); + if (return_clang_type.IsAggregateType()) + { + Target *target = exe_ctx.GetTargetPtr(); + bool is_memory = true; + if (bit_width <= 128) + { + ByteOrder target_byte_order = target->GetArchitecture().GetByteOrder(); + DataBufferSP data_sp (new DataBufferHeap(16, 0)); + DataExtractor return_ext (data_sp, + target_byte_order, + target->GetArchitecture().GetAddressByteSize()); + + const RegisterInfo *r3_info = reg_ctx_sp->GetRegisterInfoByName("r3", 0); + const RegisterInfo *rdx_info = reg_ctx_sp->GetRegisterInfoByName("rdx", 0); + + RegisterValue r3_value, rdx_value; + reg_ctx_sp->ReadRegister (r3_info, r3_value); + reg_ctx_sp->ReadRegister (rdx_info, rdx_value); + + DataExtractor r3_data, rdx_data; + + r3_value.GetData(r3_data); + rdx_value.GetData(rdx_data); + + uint32_t fp_bytes = 0; // Tracks how much of the xmm registers we've consumed so far + uint32_t integer_bytes = 0; // Tracks how much of the r3/rds registers we've consumed so far + + const uint32_t num_children = return_clang_type.GetNumFields (); + + // Since we are in the small struct regime, assume we are not in memory. + is_memory = false; + + for (uint32_t idx = 0; idx < num_children; idx++) + { + std::string name; + uint64_t field_bit_offset = 0; + bool is_signed; + bool is_complex; + uint32_t count; + + ClangASTType field_clang_type = return_clang_type.GetFieldAtIndex (idx, name, &field_bit_offset, NULL, NULL); + const size_t field_bit_width = field_clang_type.GetBitSize(); + + // If there are any unaligned fields, this is stored in memory. + if (field_bit_offset % field_bit_width != 0) + { + is_memory = true; + break; + } + + uint32_t field_byte_width = field_bit_width/8; + uint32_t field_byte_offset = field_bit_offset/8; + + + DataExtractor *copy_from_extractor = NULL; + uint32_t copy_from_offset = 0; + + if (field_clang_type.IsIntegerType (is_signed) || field_clang_type.IsPointerType ()) + { + if (integer_bytes < 8) + { + if (integer_bytes + field_byte_width <= 8) + { + // This is in RAX, copy from register to our result structure: + copy_from_extractor = &r3_data; + copy_from_offset = integer_bytes; + integer_bytes += field_byte_width; + } + else + { + // The next field wouldn't fit in the remaining space, so we pushed it to rdx. + copy_from_extractor = &rdx_data; + copy_from_offset = 0; + integer_bytes = 8 + field_byte_width; + + } + } + else if (integer_bytes + field_byte_width <= 16) + { + copy_from_extractor = &rdx_data; + copy_from_offset = integer_bytes - 8; + integer_bytes += field_byte_width; + } + else + { + // The last field didn't fit. I can't see how that would happen w/o the overall size being + // greater than 16 bytes. For now, return a NULL return value object. + return return_valobj_sp; + } + } + else if (field_clang_type.IsFloatingPointType (count, is_complex)) + { + // Structs with long doubles are always passed in memory. + if (field_bit_width == 128) + { + is_memory = true; + break; + } + else if (field_bit_width == 64) + { + copy_from_offset = 0; + fp_bytes += field_byte_width; + } + else if (field_bit_width == 32) + { + // This one is kind of complicated. If we are in an "eightbyte" with another float, we'll + // be stuffed into an xmm register with it. If we are in an "eightbyte" with one or more ints, + // then we will be stuffed into the appropriate GPR with them. + bool in_gpr; + if (field_byte_offset % 8 == 0) + { + // We are at the beginning of one of the eightbytes, so check the next element (if any) + if (idx == num_children - 1) + in_gpr = false; + else + { + uint64_t next_field_bit_offset = 0; + ClangASTType next_field_clang_type = return_clang_type.GetFieldAtIndex (idx + 1, + name, + &next_field_bit_offset, + NULL, + NULL); + if (next_field_clang_type.IsIntegerType (is_signed)) + in_gpr = true; + else + { + copy_from_offset = 0; + in_gpr = false; + } + } + + } + else if (field_byte_offset % 4 == 0) + { + // We are inside of an eightbyte, so see if the field before us is floating point: + // This could happen if somebody put padding in the structure. + if (idx == 0) + in_gpr = false; + else + { + uint64_t prev_field_bit_offset = 0; + ClangASTType prev_field_clang_type = return_clang_type.GetFieldAtIndex (idx - 1, + name, + &prev_field_bit_offset, + NULL, + NULL); + if (prev_field_clang_type.IsIntegerType (is_signed)) + in_gpr = true; + else + { + copy_from_offset = 4; + in_gpr = false; + } + } + + } + else + { + is_memory = true; + continue; + } + + // Okay, we've figured out whether we are in GPR or XMM, now figure out which one. + if (in_gpr) + { + if (integer_bytes < 8) + { + // This is in RAX, copy from register to our result structure: + copy_from_extractor = &r3_data; + copy_from_offset = integer_bytes; + integer_bytes += field_byte_width; + } + else + { + copy_from_extractor = &rdx_data; + copy_from_offset = integer_bytes - 8; + integer_bytes += field_byte_width; + } + } + else + { + fp_bytes += field_byte_width; + } + } + } + + // These two tests are just sanity checks. If I somehow get the + // type calculation wrong above it is better to just return nothing + // than to assert or crash. + if (!copy_from_extractor) + return return_valobj_sp; + if (copy_from_offset + field_byte_width > copy_from_extractor->GetByteSize()) + return return_valobj_sp; + + copy_from_extractor->CopyByteOrderedData (copy_from_offset, + field_byte_width, + data_sp->GetBytes() + field_byte_offset, + field_byte_width, + target_byte_order); + } + + if (!is_memory) + { + // The result is in our data buffer. Let's make a variable object out of it: + return_valobj_sp = ValueObjectConstResult::Create (&thread, + return_clang_type, + ConstString(""), + return_ext); + } + } + + + // FIXME: This is just taking a guess, r3 may very well no longer hold the return storage location. + // If we are going to do this right, when we make a new frame we should check to see if it uses a memory + // return, and if we are at the first instruction and if so stash away the return location. Then we would + // only return the memory return value if we know it is valid. + + if (is_memory) + { + unsigned r3_id = reg_ctx_sp->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB]; + lldb::addr_t storage_addr = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0); + return_valobj_sp = ValueObjectMemory::Create (&thread, + "", + Address (storage_addr, NULL), + return_clang_type); + } + } + + return return_valobj_sp; +} + +bool +ABISysV_ppc::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t lr_reg_num = gcc_dwarf_lr; + uint32_t sp_reg_num = gcc_dwarf_r1; + uint32_t pc_reg_num = gcc_dwarf_pc; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our Call Frame Address is the stack pointer value + row->SetCFARegister (sp_reg_num); + + // The previous PC is in the LR + row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); + unwind_plan.AppendRow (row); + + // All other registers are the same. + + unwind_plan.SetSourceName ("ppc at-func-entry default"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + + return true; +} + +bool +ABISysV_ppc::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t sp_reg_num = gcc_dwarf_r1; + uint32_t pc_reg_num = gcc_dwarf_lr; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + const int32_t ptr_size = 4; + row->SetCFARegister (sp_reg_num); + row->SetCFAType(lldb_private::UnwindPlan::Row::CFAIsRegisterDereferenced); + + row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 1, true); + row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); + + unwind_plan.AppendRow (row); + unwind_plan.SetSourceName ("ppc default unwind plan"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); + unwind_plan.SetReturnAddressRegister(gcc_dwarf_lr); + return true; +} + +bool +ABISysV_ppc::RegisterIsVolatile (const RegisterInfo *reg_info) +{ + return !RegisterIsCalleeSaved (reg_info); +} + + + +// See "Register Usage" in the +// "System V Application Binary Interface" +// "64-bit PowerPC ELF Application Binary Interface Supplement" +// current version is 1.9 released 2004 at http://refspecs.linuxfoundation.org/ELF/ppc/PPC-elf64abi-1.9.pdf + +bool +ABISysV_ppc::RegisterIsCalleeSaved (const RegisterInfo *reg_info) +{ + if (reg_info) + { + // Preserved registers are : + // r1,r2,r13-r31 + // f14-f31 (not yet) + // v20-v31 (not yet) + // vrsave (not yet) + + const char *name = reg_info->name; + if (name[0] == 'r') + { + if ((name[1] == '1' || name[1] == '2') && name[2] == '\0') + return true; + if (name[1] == '1' && name[2] > '2') + return true; + if ((name[1] == '2' || name[1] == '3') && name[2] != '\0') + return true; + } + + if (name[0] == 'f' && name[1] >= '0' && name[1] <= '9') + { + if (name[3] == '1' && name[4] >= '4') + return true; + if ((name[3] == '2' || name[3] == '3') && name[4] != '\0') + return true; + } + + if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp + return true; + if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp + return true; + if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc + return true; + } + return false; +} + + + +void +ABISysV_ppc::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + "System V ABI for ppc targets", + CreateInstance); +} + +void +ABISysV_ppc::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +lldb_private::ConstString +ABISysV_ppc::GetPluginNameStatic() +{ + static ConstString g_name("sysv-ppc"); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +ABISysV_ppc::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +ABISysV_ppc::GetPluginVersion() +{ + return 1; +} + diff --git a/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h new file mode 100644 index 0000000000000..a7aad300e2979 --- /dev/null +++ b/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h @@ -0,0 +1,143 @@ +//===-- ABISysV_ppc.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_ABISysV_ppc_h_ +#define liblldb_ABISysV_ppc_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/ABI.h" + +class ABISysV_ppc : + public lldb_private::ABI +{ +public: + + ~ABISysV_ppc() + { + } + + virtual size_t + GetRedZoneSize () const; + + virtual bool + PrepareTrivialCall (lldb_private::Thread &thread, + lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef<lldb::addr_t> args) const; + + virtual bool + GetArgumentValues (lldb_private::Thread &thread, + lldb_private::ValueList &values) const; + + virtual lldb_private::Error + SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value); + +protected: + lldb::ValueObjectSP + GetReturnValueObjectSimple (lldb_private::Thread &thread, + lldb_private::ClangASTType &ast_type) const; + +public: + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl (lldb_private::Thread &thread, + lldb_private::ClangASTType &type) const; + + virtual bool + CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan); + + virtual bool + CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan); + + virtual bool + RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info); + + virtual bool + StackUsesFrames () + { + return true; + } + + // The SysV ppc ABI requires that stack frames be 16 byte aligned. + // When there is a trap handler on the stack, e.g. _sigtramp in userland + // code, we've seen that the stack pointer is often not aligned properly + // before the handler is invoked. This means that lldb will stop the unwind + // early -- before the function which caused the trap. + // + // To work around this, we relax that alignment to be just word-size (8-bytes). + // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // in other environments there can be a large number of different functions + // involved in async traps. + virtual bool + CallFrameAddressIsValid (lldb::addr_t cfa) + { + // Make sure the stack call frame addresses are 8 byte aligned + if (cfa & (8ull - 1ull)) + return false; // Not 8 byte aligned + if (cfa == 0) + return false; // Zero is not a valid stack address + return true; + } + + virtual bool + CodeAddressIsValid (lldb::addr_t pc) + { + // We have a 64 bit address space, so anything is valid as opcodes + // aren't fixed width... + return true; + } + + virtual bool + FunctionCallsChangeCFA () + { + return true; + } + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoArray (uint32_t &count); + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb::ABISP + CreateInstance (const lldb_private::ArchSpec &arch); + + static lldb_private::ConstString + GetPluginNameStatic(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + +protected: + void + CreateRegisterMapIfNeeded (); + + bool + RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info); + +private: + ABISysV_ppc() : lldb_private::ABI() { } // Call CreateInstance instead. +}; + +#endif // liblldb_ABI_h_ diff --git a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp new file mode 100644 index 0000000000000..46f1e1023f0a1 --- /dev/null +++ b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp @@ -0,0 +1,1124 @@ +//===-- ABISysV_ppc64.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ABISysV_ppc64.h" + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Core/ValueObjectMemory.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" + +using namespace lldb; +using namespace lldb_private; + +enum gcc_dwarf_regnums +{ + gcc_dwarf_r0 = 0, + gcc_dwarf_r1, + gcc_dwarf_r2, + gcc_dwarf_r3, + gcc_dwarf_r4, + gcc_dwarf_r5, + gcc_dwarf_r6, + gcc_dwarf_r7, + gcc_dwarf_r8, + gcc_dwarf_r9, + gcc_dwarf_r10, + gcc_dwarf_r11, + gcc_dwarf_r12, + gcc_dwarf_r13, + gcc_dwarf_r14, + gcc_dwarf_r15, + gcc_dwarf_r16, + gcc_dwarf_r17, + gcc_dwarf_r18, + gcc_dwarf_r19, + gcc_dwarf_r20, + gcc_dwarf_r21, + gcc_dwarf_r22, + gcc_dwarf_r23, + gcc_dwarf_r24, + gcc_dwarf_r25, + gcc_dwarf_r26, + gcc_dwarf_r27, + gcc_dwarf_r28, + gcc_dwarf_r29, + gcc_dwarf_r30, + gcc_dwarf_r31, + gcc_dwarf_f0, + gcc_dwarf_f1, + gcc_dwarf_f2, + gcc_dwarf_f3, + gcc_dwarf_f4, + gcc_dwarf_f5, + gcc_dwarf_f6, + gcc_dwarf_f7, + gcc_dwarf_f8, + gcc_dwarf_f9, + gcc_dwarf_f10, + gcc_dwarf_f11, + gcc_dwarf_f12, + gcc_dwarf_f13, + gcc_dwarf_f14, + gcc_dwarf_f15, + gcc_dwarf_f16, + gcc_dwarf_f17, + gcc_dwarf_f18, + gcc_dwarf_f19, + gcc_dwarf_f20, + gcc_dwarf_f21, + gcc_dwarf_f22, + gcc_dwarf_f23, + gcc_dwarf_f24, + gcc_dwarf_f25, + gcc_dwarf_f26, + gcc_dwarf_f27, + gcc_dwarf_f28, + gcc_dwarf_f29, + gcc_dwarf_f30, + gcc_dwarf_f31, + gcc_dwarf_cr, + gcc_dwarf_fpscr, + gcc_dwarf_xer = 101, + gcc_dwarf_lr = 108, + gcc_dwarf_ctr, + gcc_dwarf_pc, + gcc_dwarf_cfa, +}; + +enum gdb_regnums +{ + gdb_r0 = 0, + gdb_r1, + gdb_r2, + gdb_r3, + gdb_r4, + gdb_r5, + gdb_r6, + gdb_r7, + gdb_r8, + gdb_r9, + gdb_r10, + gdb_r11, + gdb_r12, + gdb_r13, + gdb_r14, + gdb_r15, + gdb_r16, + gdb_r17, + gdb_r18, + gdb_r19, + gdb_r20, + gdb_r21, + gdb_r22, + gdb_r23, + gdb_r24, + gdb_r25, + gdb_r26, + gdb_r27, + gdb_r28, + gdb_r29, + gdb_r30, + gdb_r31, + gdb_lr, + gdb_cr, + gdb_xer, + gdb_ctr, + gdb_pc, +}; + + +// Note that the size and offset will be updated by platform-specific classes. +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, 8, 0, eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4}, NULL, NULL } +static const RegisterInfo +g_register_infos[] = +{ + // General purpose registers. GCC, DWARF, Generic, GDB + DEFINE_GPR(r0, NULL, gcc_dwarf_r0, gcc_dwarf_r0, LLDB_INVALID_REGNUM, gdb_r0), + DEFINE_GPR(r1, "sp", gcc_dwarf_r1, gcc_dwarf_r1, LLDB_REGNUM_GENERIC_SP, gdb_r1), + DEFINE_GPR(r2, NULL, gcc_dwarf_r2, gcc_dwarf_r2, LLDB_INVALID_REGNUM, gdb_r2), + DEFINE_GPR(r3, "arg1",gcc_dwarf_r3, gcc_dwarf_r3, LLDB_REGNUM_GENERIC_ARG1, gdb_r3), + DEFINE_GPR(r4, "arg2",gcc_dwarf_r4, gcc_dwarf_r4, LLDB_REGNUM_GENERIC_ARG2 ,gdb_r4), + DEFINE_GPR(r5, "arg3",gcc_dwarf_r5, gcc_dwarf_r5, LLDB_REGNUM_GENERIC_ARG3, gdb_r5), + DEFINE_GPR(r6, "arg4",gcc_dwarf_r6, gcc_dwarf_r6, LLDB_REGNUM_GENERIC_ARG4, gdb_r6), + DEFINE_GPR(r7, "arg5",gcc_dwarf_r7, gcc_dwarf_r7, LLDB_REGNUM_GENERIC_ARG5, gdb_r7), + DEFINE_GPR(r8, "arg6",gcc_dwarf_r8, gcc_dwarf_r8, LLDB_REGNUM_GENERIC_ARG6, gdb_r8), + DEFINE_GPR(r9, "arg7",gcc_dwarf_r9, gcc_dwarf_r9, LLDB_REGNUM_GENERIC_ARG7, gdb_r9), + DEFINE_GPR(r10, "arg8",gcc_dwarf_r10, gcc_dwarf_r10, LLDB_REGNUM_GENERIC_ARG8, gdb_r10), + DEFINE_GPR(r11, NULL, gcc_dwarf_r11, gcc_dwarf_r11, LLDB_INVALID_REGNUM, gdb_r11), + DEFINE_GPR(r12, NULL, gcc_dwarf_r12, gcc_dwarf_r12, LLDB_INVALID_REGNUM, gdb_r12), + DEFINE_GPR(r13, NULL, gcc_dwarf_r13, gcc_dwarf_r13, LLDB_INVALID_REGNUM, gdb_r13), + DEFINE_GPR(r14, NULL, gcc_dwarf_r14, gcc_dwarf_r14, LLDB_INVALID_REGNUM, gdb_r14), + DEFINE_GPR(r15, NULL, gcc_dwarf_r15, gcc_dwarf_r15, LLDB_INVALID_REGNUM, gdb_r15), + DEFINE_GPR(r16, NULL, gcc_dwarf_r16, gcc_dwarf_r16, LLDB_INVALID_REGNUM, gdb_r16), + DEFINE_GPR(r17, NULL, gcc_dwarf_r17, gcc_dwarf_r17, LLDB_INVALID_REGNUM, gdb_r17), + DEFINE_GPR(r18, NULL, gcc_dwarf_r18, gcc_dwarf_r18, LLDB_INVALID_REGNUM, gdb_r18), + DEFINE_GPR(r19, NULL, gcc_dwarf_r19, gcc_dwarf_r19, LLDB_INVALID_REGNUM, gdb_r19), + DEFINE_GPR(r20, NULL, gcc_dwarf_r20, gcc_dwarf_r20, LLDB_INVALID_REGNUM, gdb_r20), + DEFINE_GPR(r21, NULL, gcc_dwarf_r21, gcc_dwarf_r21, LLDB_INVALID_REGNUM, gdb_r21), + DEFINE_GPR(r22, NULL, gcc_dwarf_r22, gcc_dwarf_r22, LLDB_INVALID_REGNUM, gdb_r22), + DEFINE_GPR(r23, NULL, gcc_dwarf_r23, gcc_dwarf_r23, LLDB_INVALID_REGNUM, gdb_r23), + DEFINE_GPR(r24, NULL, gcc_dwarf_r24, gcc_dwarf_r24, LLDB_INVALID_REGNUM, gdb_r24), + DEFINE_GPR(r25, NULL, gcc_dwarf_r25, gcc_dwarf_r25, LLDB_INVALID_REGNUM, gdb_r25), + DEFINE_GPR(r26, NULL, gcc_dwarf_r26, gcc_dwarf_r26, LLDB_INVALID_REGNUM, gdb_r26), + DEFINE_GPR(r27, NULL, gcc_dwarf_r27, gcc_dwarf_r27, LLDB_INVALID_REGNUM, gdb_r27), + DEFINE_GPR(r28, NULL, gcc_dwarf_r28, gcc_dwarf_r28, LLDB_INVALID_REGNUM, gdb_r28), + DEFINE_GPR(r29, NULL, gcc_dwarf_r29, gcc_dwarf_r29, LLDB_INVALID_REGNUM, gdb_r29), + DEFINE_GPR(r30, NULL, gcc_dwarf_r30, gcc_dwarf_r30, LLDB_INVALID_REGNUM, gdb_r30), + DEFINE_GPR(r31, NULL, gcc_dwarf_r31, gcc_dwarf_r31, LLDB_INVALID_REGNUM, gdb_r31), + DEFINE_GPR(lr, "lr", gcc_dwarf_lr, gcc_dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_lr), + DEFINE_GPR(cr, "cr", gcc_dwarf_cr, gcc_dwarf_cr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), + DEFINE_GPR(xer, "xer", gcc_dwarf_xer, gcc_dwarf_xer, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(ctr, "ctr", gcc_dwarf_ctr, gcc_dwarf_ctr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(pc, "pc", gcc_dwarf_pc, gcc_dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), + { NULL, NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_cfa, gcc_dwarf_cfa, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, NULL, NULL}, +}; + +static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); + +const lldb_private::RegisterInfo * +ABISysV_ppc64::GetRegisterInfoArray (uint32_t &count) +{ + count = k_num_register_infos; + return g_register_infos; +} + + +size_t +ABISysV_ppc64::GetRedZoneSize () const +{ + return 224; +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ +ABISP +ABISysV_ppc64::CreateInstance (const ArchSpec &arch) +{ + static ABISP g_abi_sp; + if (arch.GetTriple().getArch() == llvm::Triple::ppc64) + { + if (!g_abi_sp) + g_abi_sp.reset (new ABISysV_ppc64); + return g_abi_sp; + } + return ABISP(); +} + +bool +ABISysV_ppc64::PrepareTrivialCall (Thread &thread, + addr_t sp, + addr_t func_addr, + addr_t return_addr, + llvm::ArrayRef<addr_t> args) const +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + { + StreamString s; + s.Printf("ABISysV_ppc64::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64, + thread.GetID(), + (uint64_t)sp, + (uint64_t)func_addr, + (uint64_t)return_addr); + + for (size_t i = 0; i < args.size(); ++i) + s.Printf (", arg%zd = 0x%" PRIx64, i + 1, args[i]); + s.PutCString (")"); + log->PutCString(s.GetString().c_str()); + } + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + const RegisterInfo *reg_info = NULL; + + if (args.size() > 8) // TODO handle more than 8 arguments + return false; + + for (size_t i = 0; i < args.size(); ++i) + { + reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); + if (log) + log->Printf("About to write arg%zd (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // First, align the SP + + if (log) + log->Printf("16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, (uint64_t)sp, (uint64_t)(sp & ~0xfull)); + + sp &= ~(0xfull); // 16-byte alignment + + sp -= 8; + + Error error; + const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + ProcessSP process_sp (thread.GetProcess()); + + RegisterValue reg_value; + +#if 0 + // This code adds an extra frame so that we don't lose the function that we came from + // by pushing the PC and the FP and then writing the current FP to point to the FP value + // we just pushed. It is disabled for now until the stack backtracing code can be debugged. + + // Save current PC + const RegisterInfo *fp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); + if (reg_ctx->ReadRegister(pc_reg_info, reg_value)) + { + if (log) + log->Printf("Pushing the current PC onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64()); + + if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error)) + return false; + + sp -= 8; + + // Save current FP + if (reg_ctx->ReadRegister(fp_reg_info, reg_value)) + { + if (log) + log->Printf("Pushing the current FP onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64()); + + if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error)) + return false; + } + // Setup FP backchain + reg_value.SetUInt64 (sp); + + if (log) + log->Printf("Writing FP: 0x%" PRIx64 " (for FP backchain)", reg_value.GetAsUInt64()); + + if (!reg_ctx->WriteRegister(fp_reg_info, reg_value)) + { + return false; + } + + sp -= 8; + } +#endif + + if (log) + log->Printf("Pushing the return address onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, (uint64_t)return_addr); + + // Save return address onto the stack + if (!process_sp->WritePointerToMemory(sp, return_addr, error)) + return false; + + // %r1 is set to the actual stack value. + + if (log) + log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp); + + if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_info, sp)) + return false; + + // %pc is set to the address of the called function. + + if (log) + log->Printf("Writing IP: 0x%" PRIx64, (uint64_t)func_addr); + + if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr)) + return false; + + return true; +} + +static bool ReadIntegerArgument(Scalar &scalar, + unsigned int bit_width, + bool is_signed, + Thread &thread, + uint32_t *argument_register_ids, + unsigned int ¤t_argument_register, + addr_t ¤t_stack_argument) +{ + if (bit_width > 64) + return false; // Scalar can't hold large integer arguments + + if (current_argument_register < 6) + { + scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned(argument_register_ids[current_argument_register], 0); + current_argument_register++; + if (is_signed) + scalar.SignExtend (bit_width); + } + else + { + uint32_t byte_size = (bit_width + (8-1))/8; + Error error; + if (thread.GetProcess()->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, is_signed, scalar, error)) + { + current_stack_argument += byte_size; + return true; + } + return false; + } + return true; +} + +bool +ABISysV_ppc64::GetArgumentValues (Thread &thread, + ValueList &values) const +{ + unsigned int num_values = values.GetSize(); + unsigned int value_index; + + // Extract the register context so we can read arguments from registers + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + + if (!reg_ctx) + return false; + + // Get the pointer to the first stack argument so we have a place to start + // when reading data + + addr_t sp = reg_ctx->GetSP(0); + + if (!sp) + return false; + + addr_t current_stack_argument = sp + 48; // jump over return address + + uint32_t argument_register_ids[8]; + + argument_register_ids[0] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1)->kinds[eRegisterKindLLDB]; + argument_register_ids[1] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2)->kinds[eRegisterKindLLDB]; + argument_register_ids[2] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG3)->kinds[eRegisterKindLLDB]; + argument_register_ids[3] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG4)->kinds[eRegisterKindLLDB]; + argument_register_ids[4] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG5)->kinds[eRegisterKindLLDB]; + argument_register_ids[5] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG6)->kinds[eRegisterKindLLDB]; + argument_register_ids[6] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG7)->kinds[eRegisterKindLLDB]; + argument_register_ids[7] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG8)->kinds[eRegisterKindLLDB]; + + unsigned int current_argument_register = 0; + + for (value_index = 0; + value_index < num_values; + ++value_index) + { + Value *value = values.GetValueAtIndex(value_index); + + if (!value) + return false; + + // We currently only support extracting values with Clang QualTypes. + // Do we care about others? + ClangASTType clang_type = value->GetClangType(); + if (!clang_type) + return false; + bool is_signed; + + if (clang_type.IsIntegerType (is_signed)) + { + ReadIntegerArgument(value->GetScalar(), + clang_type.GetBitSize(), + is_signed, + thread, + argument_register_ids, + current_argument_register, + current_stack_argument); + } + else if (clang_type.IsPointerType ()) + { + ReadIntegerArgument(value->GetScalar(), + clang_type.GetBitSize(), + false, + thread, + argument_register_ids, + current_argument_register, + current_stack_argument); + } + } + + return true; +} + +Error +ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp) +{ + Error error; + if (!new_value_sp) + { + error.SetErrorString("Empty value object for return value."); + return error; + } + + ClangASTType clang_type = new_value_sp->GetClangType(); + if (!clang_type) + { + error.SetErrorString ("Null clang type for return value."); + return error; + } + + Thread *thread = frame_sp->GetThread().get(); + + bool is_signed; + uint32_t count; + bool is_complex; + + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + bool set_it_simple = false; + if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType()) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0); + + DataExtractor data; + Error data_error; + size_t num_bytes = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) + { + error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString()); + return error; + } + lldb::offset_t offset = 0; + if (num_bytes <= 8) + { + uint64_t raw_value = data.GetMaxU64(&offset, num_bytes); + + if (reg_ctx->WriteRegisterFromUnsigned (reg_info, raw_value)) + set_it_simple = true; + } + else + { + error.SetErrorString("We don't support returning longer than 64 bit integer values at present."); + } + + } + else if (clang_type.IsFloatingPointType (count, is_complex)) + { + if (is_complex) + error.SetErrorString ("We don't support returning complex values at present"); + else + { + size_t bit_width = clang_type.GetBitSize(); + if (bit_width <= 64) + { + DataExtractor data; + Error data_error; + size_t num_bytes = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) + { + error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString()); + return error; + } + + unsigned char buffer[16]; + ByteOrder byte_order = data.GetByteOrder(); + + data.CopyByteOrderedData (0, num_bytes, buffer, 16, byte_order); + set_it_simple = true; + } + else + { + // FIXME - don't know how to do 80 bit long doubles yet. + error.SetErrorString ("We don't support returning float values > 64 bits at present"); + } + } + } + + if (!set_it_simple) + { + // Okay we've got a structure or something that doesn't fit in a simple register. + // We should figure out where it really goes, but we don't support this yet. + error.SetErrorString ("We only support setting simple integer and float return types at present."); + } + + return error; +} + + +ValueObjectSP +ABISysV_ppc64::GetReturnValueObjectSimple (Thread &thread, + ClangASTType &return_clang_type) const +{ + ValueObjectSP return_valobj_sp; + Value value; + + if (!return_clang_type) + return return_valobj_sp; + + //value.SetContext (Value::eContextTypeClangType, return_value_type); + value.SetClangType (return_clang_type); + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return return_valobj_sp; + + const uint32_t type_flags = return_clang_type.GetTypeInfo (); + if (type_flags & eTypeIsScalar) + { + value.SetValueType(Value::eValueTypeScalar); + + bool success = false; + if (type_flags & eTypeIsInteger) + { + // Extract the register context so we can read arguments from registers + + const size_t byte_size = return_clang_type.GetByteSize(); + uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("r3", 0), 0); + const bool is_signed = (type_flags & eTypeIsSigned) != 0; + switch (byte_size) + { + default: + break; + + case sizeof(uint64_t): + if (is_signed) + value.GetScalar() = (int64_t)(raw_value); + else + value.GetScalar() = (uint64_t)(raw_value); + success = true; + break; + + case sizeof(uint32_t): + if (is_signed) + value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); + else + value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); + success = true; + break; + + case sizeof(uint16_t): + if (is_signed) + value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); + else + value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); + success = true; + break; + + case sizeof(uint8_t): + if (is_signed) + value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); + else + value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); + success = true; + break; + } + } + else if (type_flags & eTypeIsFloat) + { + if (type_flags & eTypeIsComplex) + { + // Don't handle complex yet. + } + else + { + const size_t byte_size = return_clang_type.GetByteSize(); + if (byte_size <= sizeof(long double)) + { + const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); + RegisterValue f1_value; + if (reg_ctx->ReadRegister (f1_info, f1_value)) + { + DataExtractor data; + if (f1_value.GetData(data)) + { + lldb::offset_t offset = 0; + if (byte_size == sizeof(float)) + { + value.GetScalar() = (float) data.GetFloat(&offset); + success = true; + } + else if (byte_size == sizeof(double)) + { + value.GetScalar() = (double) data.GetDouble(&offset); + success = true; + } + } + } + } + } + } + + if (success) + return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(), + value, + ConstString("")); + + } + else if (type_flags & eTypeIsPointer) + { + unsigned r3_id = reg_ctx->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB]; + value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0); + value.SetValueType(Value::eValueTypeScalar); + return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(), + value, + ConstString("")); + } + else if (type_flags & eTypeIsVector) + { + const size_t byte_size = return_clang_type.GetByteSize(); + if (byte_size > 0) + { + + const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v0", 0); + if (altivec_reg == NULL) + altivec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0); + if (altivec_reg) + { + if (byte_size <= altivec_reg->byte_size) + { + ProcessSP process_sp (thread.GetProcess()); + if (process_sp) + { + std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0)); + const ByteOrder byte_order = process_sp->GetByteOrder(); + RegisterValue reg_value; + if (reg_ctx->ReadRegister(altivec_reg, reg_value)) + { + Error error; + if (reg_value.GetAsMemoryData (altivec_reg, + heap_data_ap->GetBytes(), + heap_data_ap->GetByteSize(), + byte_order, + error)) + { + DataExtractor data (DataBufferSP (heap_data_ap.release()), + byte_order, + process_sp->GetTarget().GetArchitecture().GetAddressByteSize()); + return_valobj_sp = ValueObjectConstResult::Create (&thread, + return_clang_type, + ConstString(""), + data); + } + } + } + } + } + } + } + + return return_valobj_sp; +} + +ValueObjectSP +ABISysV_ppc64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_clang_type) const +{ + ValueObjectSP return_valobj_sp; + + if (!return_clang_type) + return return_valobj_sp; + + ExecutionContext exe_ctx (thread.shared_from_this()); + return_valobj_sp = GetReturnValueObjectSimple(thread, return_clang_type); + if (return_valobj_sp) + return return_valobj_sp; + + RegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); + if (!reg_ctx_sp) + return return_valobj_sp; + + const size_t bit_width = return_clang_type.GetBitSize(); + if (return_clang_type.IsAggregateType()) + { + Target *target = exe_ctx.GetTargetPtr(); + bool is_memory = true; + if (bit_width <= 128) + { + ByteOrder target_byte_order = target->GetArchitecture().GetByteOrder(); + DataBufferSP data_sp (new DataBufferHeap(16, 0)); + DataExtractor return_ext (data_sp, + target_byte_order, + target->GetArchitecture().GetAddressByteSize()); + + const RegisterInfo *r3_info = reg_ctx_sp->GetRegisterInfoByName("r3", 0); + const RegisterInfo *rdx_info = reg_ctx_sp->GetRegisterInfoByName("rdx", 0); + + RegisterValue r3_value, rdx_value; + reg_ctx_sp->ReadRegister (r3_info, r3_value); + reg_ctx_sp->ReadRegister (rdx_info, rdx_value); + + DataExtractor r3_data, rdx_data; + + r3_value.GetData(r3_data); + rdx_value.GetData(rdx_data); + + uint32_t fp_bytes = 0; // Tracks how much of the xmm registers we've consumed so far + uint32_t integer_bytes = 0; // Tracks how much of the r3/rds registers we've consumed so far + + const uint32_t num_children = return_clang_type.GetNumFields (); + + // Since we are in the small struct regime, assume we are not in memory. + is_memory = false; + + for (uint32_t idx = 0; idx < num_children; idx++) + { + std::string name; + uint64_t field_bit_offset = 0; + bool is_signed; + bool is_complex; + uint32_t count; + + ClangASTType field_clang_type = return_clang_type.GetFieldAtIndex (idx, name, &field_bit_offset, NULL, NULL); + const size_t field_bit_width = field_clang_type.GetBitSize(); + + // If there are any unaligned fields, this is stored in memory. + if (field_bit_offset % field_bit_width != 0) + { + is_memory = true; + break; + } + + uint32_t field_byte_width = field_bit_width/8; + uint32_t field_byte_offset = field_bit_offset/8; + + + DataExtractor *copy_from_extractor = NULL; + uint32_t copy_from_offset = 0; + + if (field_clang_type.IsIntegerType (is_signed) || field_clang_type.IsPointerType ()) + { + if (integer_bytes < 8) + { + if (integer_bytes + field_byte_width <= 8) + { + // This is in RAX, copy from register to our result structure: + copy_from_extractor = &r3_data; + copy_from_offset = integer_bytes; + integer_bytes += field_byte_width; + } + else + { + // The next field wouldn't fit in the remaining space, so we pushed it to rdx. + copy_from_extractor = &rdx_data; + copy_from_offset = 0; + integer_bytes = 8 + field_byte_width; + + } + } + else if (integer_bytes + field_byte_width <= 16) + { + copy_from_extractor = &rdx_data; + copy_from_offset = integer_bytes - 8; + integer_bytes += field_byte_width; + } + else + { + // The last field didn't fit. I can't see how that would happen w/o the overall size being + // greater than 16 bytes. For now, return a NULL return value object. + return return_valobj_sp; + } + } + else if (field_clang_type.IsFloatingPointType (count, is_complex)) + { + // Structs with long doubles are always passed in memory. + if (field_bit_width == 128) + { + is_memory = true; + break; + } + else if (field_bit_width == 64) + { + copy_from_offset = 0; + fp_bytes += field_byte_width; + } + else if (field_bit_width == 32) + { + // This one is kind of complicated. If we are in an "eightbyte" with another float, we'll + // be stuffed into an xmm register with it. If we are in an "eightbyte" with one or more ints, + // then we will be stuffed into the appropriate GPR with them. + bool in_gpr; + if (field_byte_offset % 8 == 0) + { + // We are at the beginning of one of the eightbytes, so check the next element (if any) + if (idx == num_children - 1) + in_gpr = false; + else + { + uint64_t next_field_bit_offset = 0; + ClangASTType next_field_clang_type = return_clang_type.GetFieldAtIndex (idx + 1, + name, + &next_field_bit_offset, + NULL, + NULL); + if (next_field_clang_type.IsIntegerType (is_signed)) + in_gpr = true; + else + { + copy_from_offset = 0; + in_gpr = false; + } + } + + } + else if (field_byte_offset % 4 == 0) + { + // We are inside of an eightbyte, so see if the field before us is floating point: + // This could happen if somebody put padding in the structure. + if (idx == 0) + in_gpr = false; + else + { + uint64_t prev_field_bit_offset = 0; + ClangASTType prev_field_clang_type = return_clang_type.GetFieldAtIndex (idx - 1, + name, + &prev_field_bit_offset, + NULL, + NULL); + if (prev_field_clang_type.IsIntegerType (is_signed)) + in_gpr = true; + else + { + copy_from_offset = 4; + in_gpr = false; + } + } + + } + else + { + is_memory = true; + continue; + } + + // Okay, we've figured out whether we are in GPR or XMM, now figure out which one. + if (in_gpr) + { + if (integer_bytes < 8) + { + // This is in RAX, copy from register to our result structure: + copy_from_extractor = &r3_data; + copy_from_offset = integer_bytes; + integer_bytes += field_byte_width; + } + else + { + copy_from_extractor = &rdx_data; + copy_from_offset = integer_bytes - 8; + integer_bytes += field_byte_width; + } + } + else + { + fp_bytes += field_byte_width; + } + } + } + + // These two tests are just sanity checks. If I somehow get the + // type calculation wrong above it is better to just return nothing + // than to assert or crash. + if (!copy_from_extractor) + return return_valobj_sp; + if (copy_from_offset + field_byte_width > copy_from_extractor->GetByteSize()) + return return_valobj_sp; + + copy_from_extractor->CopyByteOrderedData (copy_from_offset, + field_byte_width, + data_sp->GetBytes() + field_byte_offset, + field_byte_width, + target_byte_order); + } + + if (!is_memory) + { + // The result is in our data buffer. Let's make a variable object out of it: + return_valobj_sp = ValueObjectConstResult::Create (&thread, + return_clang_type, + ConstString(""), + return_ext); + } + } + + + // FIXME: This is just taking a guess, r3 may very well no longer hold the return storage location. + // If we are going to do this right, when we make a new frame we should check to see if it uses a memory + // return, and if we are at the first instruction and if so stash away the return location. Then we would + // only return the memory return value if we know it is valid. + + if (is_memory) + { + unsigned r3_id = reg_ctx_sp->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB]; + lldb::addr_t storage_addr = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0); + return_valobj_sp = ValueObjectMemory::Create (&thread, + "", + Address (storage_addr, NULL), + return_clang_type); + } + } + + return return_valobj_sp; +} + +bool +ABISysV_ppc64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t lr_reg_num = gcc_dwarf_lr; + uint32_t sp_reg_num = gcc_dwarf_r1; + uint32_t pc_reg_num = gcc_dwarf_pc; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our Call Frame Address is the stack pointer value + row->SetCFARegister (sp_reg_num); + + // The previous PC is in the LR + row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); + unwind_plan.AppendRow (row); + + // All other registers are the same. + + unwind_plan.SetSourceName ("ppc64 at-func-entry default"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + + return true; +} + +bool +ABISysV_ppc64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t sp_reg_num = gcc_dwarf_r1; + uint32_t pc_reg_num = gcc_dwarf_lr; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + const int32_t ptr_size = 8; + row->SetCFARegister (sp_reg_num); + row->SetCFAType(lldb_private::UnwindPlan::Row::CFAIsRegisterDereferenced); + + row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 2, true); + row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); + row->SetRegisterLocationToAtCFAPlusOffset(gcc_dwarf_cr, ptr_size, true); + + unwind_plan.AppendRow (row); + unwind_plan.SetSourceName ("ppc64 default unwind plan"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); + unwind_plan.SetReturnAddressRegister(gcc_dwarf_lr); + return true; +} + +bool +ABISysV_ppc64::RegisterIsVolatile (const RegisterInfo *reg_info) +{ + return !RegisterIsCalleeSaved (reg_info); +} + + + +// See "Register Usage" in the +// "System V Application Binary Interface" +// "64-bit PowerPC ELF Application Binary Interface Supplement" +// current version is 1.9 released 2004 at http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.pdf + +bool +ABISysV_ppc64::RegisterIsCalleeSaved (const RegisterInfo *reg_info) +{ + if (reg_info) + { + // Preserved registers are : + // r1,r2,r13-r31 + // cr2-cr4 (partially preserved) + // f14-f31 (not yet) + // v20-v31 (not yet) + // vrsave (not yet) + + const char *name = reg_info->name; + if (name[0] == 'r') + { + if ((name[1] == '1' || name[1] == '2') && name[2] == '\0') + return true; + if (name[1] == '1' && name[2] > '2') + return true; + if ((name[1] == '2' || name[1] == '3') && name[2] != '\0') + return true; + } + + if (name[0] == 'f' && name[1] >= '0' && name[2] <= '9') + { + if (name[2] == '\0') + return false; + if (name[1] == '1' && name[2] >= '4') + return true; + if ((name[1] == '2' || name[1] == '3') && name[2] != '\0') + return true; + } + + if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp + return true; + if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp + return true; + if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc + return true; + } + return false; +} + + + +void +ABISysV_ppc64::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + "System V ABI for ppc64 targets", + CreateInstance); +} + +void +ABISysV_ppc64::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +lldb_private::ConstString +ABISysV_ppc64::GetPluginNameStatic() +{ + static ConstString g_name("sysv-ppc64"); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +ABISysV_ppc64::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +ABISysV_ppc64::GetPluginVersion() +{ + return 1; +} + diff --git a/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h new file mode 100644 index 0000000000000..d77cb9f1efe3b --- /dev/null +++ b/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h @@ -0,0 +1,143 @@ +//===-- ABISysV_ppc64.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_ABISysV_ppc64_h_ +#define liblldb_ABISysV_ppc64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/ABI.h" + +class ABISysV_ppc64 : + public lldb_private::ABI +{ +public: + + ~ABISysV_ppc64() + { + } + + virtual size_t + GetRedZoneSize () const; + + virtual bool + PrepareTrivialCall (lldb_private::Thread &thread, + lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef<lldb::addr_t> args) const; + + virtual bool + GetArgumentValues (lldb_private::Thread &thread, + lldb_private::ValueList &values) const; + + virtual lldb_private::Error + SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value); + +protected: + lldb::ValueObjectSP + GetReturnValueObjectSimple (lldb_private::Thread &thread, + lldb_private::ClangASTType &ast_type) const; + +public: + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl (lldb_private::Thread &thread, + lldb_private::ClangASTType &type) const; + + virtual bool + CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan); + + virtual bool + CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan); + + virtual bool + RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info); + + virtual bool + StackUsesFrames () + { + return true; + } + + // The SysV ppc64 ABI requires that stack frames be 16 byte aligned. + // When there is a trap handler on the stack, e.g. _sigtramp in userland + // code, we've seen that the stack pointer is often not aligned properly + // before the handler is invoked. This means that lldb will stop the unwind + // early -- before the function which caused the trap. + // + // To work around this, we relax that alignment to be just word-size (8-bytes). + // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // in other environments there can be a large number of different functions + // involved in async traps. + virtual bool + CallFrameAddressIsValid (lldb::addr_t cfa) + { + // Make sure the stack call frame addresses are 8 byte aligned + if (cfa & (8ull - 1ull)) + return false; // Not 8 byte aligned + if (cfa == 0) + return false; // Zero is not a valid stack address + return true; + } + + virtual bool + CodeAddressIsValid (lldb::addr_t pc) + { + // We have a 64 bit address space, so anything is valid as opcodes + // aren't fixed width... + return true; + } + + virtual bool + FunctionCallsChangeCFA () + { + return true; + } + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoArray (uint32_t &count); + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb::ABISP + CreateInstance (const lldb_private::ArchSpec &arch); + + static lldb_private::ConstString + GetPluginNameStatic(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + +protected: + void + CreateRegisterMapIfNeeded (); + + bool + RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info); + +private: + ABISysV_ppc64() : lldb_private::ABI() { } // Call CreateInstance instead. +}; + +#endif // liblldb_ABI_h_ diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp index b537415bf055d..776e7fea67c76 100644 --- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp +++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp @@ -649,18 +649,18 @@ ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread, return return_valobj_sp; const uint32_t type_flags = return_clang_type.GetTypeInfo (); - if (type_flags & ClangASTType::eTypeIsScalar) + if (type_flags & eTypeIsScalar) { value.SetValueType(Value::eValueTypeScalar); bool success = false; - if (type_flags & ClangASTType::eTypeIsInteger) + if (type_flags & eTypeIsInteger) { // Extract the register context so we can read arguments from registers const size_t byte_size = return_clang_type.GetByteSize(); uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("rax", 0), 0); - const bool is_signed = (type_flags & ClangASTType::eTypeIsSigned) != 0; + const bool is_signed = (type_flags & eTypeIsSigned) != 0; switch (byte_size) { default: @@ -699,9 +699,9 @@ ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread, break; } } - else if (type_flags & ClangASTType::eTypeIsFloat) + else if (type_flags & eTypeIsFloat) { - if (type_flags & ClangASTType::eTypeIsComplex) + if (type_flags & eTypeIsComplex) { // Don't handle complex yet. } @@ -744,7 +744,7 @@ ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread, ConstString("")); } - else if (type_flags & ClangASTType::eTypeIsPointer) + else if (type_flags & eTypeIsPointer) { unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB]; value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0); @@ -753,7 +753,7 @@ ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread, value, ConstString("")); } - else if (type_flags & ClangASTType::eTypeIsVector) + else if (type_flags & eTypeIsVector) { const size_t byte_size = return_clang_type.GetByteSize(); if (byte_size > 0) diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h index 7fd1b6c4b0f3b..6fefcc2a9c747 100644 --- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h +++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h @@ -61,13 +61,7 @@ public: virtual bool RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info); - - virtual bool - StackUsesFrames () - { - return true; - } - + // The SysV x86_64 ABI requires that stack frames be 16 byte aligned. // When there is a trap handler on the stack, e.g. _sigtramp in userland // code, we've seen that the stack pointer is often not aligned properly @@ -97,12 +91,6 @@ public: return true; } - virtual bool - FunctionCallsChangeCFA () - { - return true; - } - virtual const lldb_private::RegisterInfo * GetRegisterInfoArray (uint32_t &count); //------------------------------------------------------------------ diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp index c14371d0589c8..97ddbef0e3074 100644 --- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp @@ -21,7 +21,6 @@ #include "llvm/MC/MCRelocationInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MemoryObject.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/ADT/SmallString.h" @@ -489,41 +488,19 @@ DisassemblerLLVMC::LLVMCDisassembler::~LLVMCDisassembler() { } -namespace { - // This is the memory object we use in GetInstruction. - class LLDBDisasmMemoryObject : public llvm::MemoryObject { - const uint8_t *m_bytes; - uint64_t m_size; - uint64_t m_base_PC; - public: - LLDBDisasmMemoryObject(const uint8_t *bytes, uint64_t size, uint64_t basePC) : - m_bytes(bytes), m_size(size), m_base_PC(basePC) {} - - uint64_t getBase() const { return m_base_PC; } - uint64_t getExtent() const { return m_size; } - - int readByte(uint64_t addr, uint8_t *byte) const { - if (addr - m_base_PC >= m_size) - return -1; - *byte = m_bytes[addr - m_base_PC]; - return 0; - } - }; -} // End Anonymous Namespace - uint64_t DisassemblerLLVMC::LLVMCDisassembler::GetMCInst (const uint8_t *opcode_data, size_t opcode_data_len, lldb::addr_t pc, llvm::MCInst &mc_inst) { - LLDBDisasmMemoryObject memory_object (opcode_data, opcode_data_len, pc); + llvm::ArrayRef<uint8_t> data(opcode_data, opcode_data_len); llvm::MCDisassembler::DecodeStatus status; uint64_t new_inst_size; status = m_disasm_ap->getInstruction(mc_inst, new_inst_size, - memory_object, + data, pc, llvm::nulls(), llvm::nulls()); @@ -832,11 +809,19 @@ const char *DisassemblerLLVMC::SymbolLookup (uint64_t value, value_so_addr.Dump (&ss, target, - Address::DumpStyleResolvedDescriptionNoModule, + Address::DumpStyleResolvedDescriptionNoFunctionArguments, Address::DumpStyleSectionNameOffset); if (!ss.GetString().empty()) { + // If Address::Dump returned a multi-line description, most commonly seen when we + // have multiple levels of inlined functions at an address, only show the first line. + std::string &str(ss.GetString()); + size_t first_eol_char = str.find_first_of ("\r\n"); + if (first_eol_char != std::string::npos) + { + str.erase (first_eol_char); + } m_inst->AppendComment(ss.GetString()); } } diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp index 0e203fe43a790..d8279e44e14ab 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -34,6 +34,13 @@ ResolveRendezvousAddress(Process *process) addr_t info_addr; Error error; + if (!process) + { + if (log) + log->Printf ("%s null process provided", __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + // Try to get it from our process. This might be a remote process and might // grab it via some remote-specific mechanism. info_location = process->GetImageInfoAddress(); @@ -43,7 +50,7 @@ ResolveRendezvousAddress(Process *process) // If the process fails to return an address, fall back to seeing if the local object file can help us find it. if (info_location == LLDB_INVALID_ADDRESS) { - Target *target = process ? &process->GetTarget() : nullptr; + Target *target = &process->GetTarget(); if (target) { ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); @@ -70,6 +77,9 @@ ResolveRendezvousAddress(Process *process) return LLDB_INVALID_ADDRESS; } + if (log) + log->Printf ("%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64, __FUNCTION__, process->GetAddressByteSize(), info_location); + info_addr = process->ReadPointerFromMemory(info_location, error); if (error.Fail()) { @@ -193,7 +203,7 @@ DYLDRendezvous::UpdateSOEntries() // state and take a snapshot of the currently loaded images. if (m_current.state == eAdd || m_current.state == eDelete) { - assert(m_previous.state == eConsistent); + assert(m_previous.state == eConsistent || (m_previous.state == eAdd && m_current.state == eDelete)); m_soentries.clear(); m_added_soentries.clear(); m_removed_soentries.clear(); @@ -320,23 +330,11 @@ DYLDRendezvous::ReadStringFromMemory(addr_t addr) { std::string str; Error error; - size_t size; - char c; if (addr == LLDB_INVALID_ADDRESS) return std::string(); - for (;;) { - size = m_process->DoReadMemory(addr, &c, 1, error); - if (size != 1 || error.Fail()) - return std::string(); - if (c == 0) - break; - else { - str.push_back(c); - addr++; - } - } + m_process->ReadCStringFromMemory(addr, str, error); return str; } diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 549e5f9b5345b..6b0b6f5cc8b82 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -111,27 +111,88 @@ DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD() void DynamicLoaderPOSIXDYLD::DidAttach() { - ModuleSP executable; - addr_t load_offset; + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); m_auxv.reset(new AuxVector(m_process)); + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reloaded auxv data", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); - executable = GetTargetExecutable(); - load_offset = ComputeLoadOffset(); + ModuleSP executable_sp = GetTargetExecutable(); + ModuleSpec process_module_spec; + if (GetProcessModuleSpec(process_module_spec)) + { + if (executable_sp == nullptr || !executable_sp->MatchesModuleSpec(process_module_spec)) + { + executable_sp.reset(new Module(process_module_spec)); + assert(m_process != nullptr); + m_process->GetTarget().SetExecutableModule(executable_sp, false); + } + } - if (executable.get() && load_offset != LLDB_INVALID_ADDRESS) + addr_t load_offset = ComputeLoadOffset(); + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " executable '%s', load_offset 0x%" PRIx64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, executable_sp ? executable_sp->GetFileSpec().GetPath().c_str () : "<null executable>", load_offset); + + + if (executable_sp && load_offset != LLDB_INVALID_ADDRESS) { ModuleList module_list; - module_list.Append(executable); - UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset); - LoadAllCurrentModules(); + + module_list.Append(executable_sp); + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " added executable '%s' to module load list", + __FUNCTION__, + m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, + executable_sp->GetFileSpec().GetPath().c_str ()); + + UpdateLoadedSections(executable_sp, LLDB_INVALID_ADDRESS, load_offset); + + // When attaching to a target, there are two possible states: + // (1) We already crossed the entry point and therefore the rendezvous + // structure is ready to be used and we can load the list of modules + // and place the rendezvous breakpoint. + // (2) We didn't cross the entry point yet, so these structures are not + // ready; we should behave as if we just launched the target and + // call ProbeEntry(). This will place a breakpoint on the entry + // point which itself will be hit after the rendezvous structure is + // set up and will perform actions described in (1). + if (m_rendezvous.Resolve()) + { + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64 " rendezvous could resolve: attach assuming dynamic loader info is available now", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); + LoadAllCurrentModules(); + SetRendezvousBreakpoint(); + } + else + { + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64 " rendezvous could not yet resolve: adding breakpoint to catch future rendezvous setup", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); + ProbeEntry(); + } + m_process->GetTarget().ModulesDidLoad(module_list); + if (log) + { + log->Printf ("DynamicLoaderPOSIXDYLD::%s told the target about the modules that loaded:", __FUNCTION__); + for (auto module_sp : module_list.Modules ()) + { + log->Printf ("-- [module] %s (pid %" PRIu64 ")", + module_sp ? module_sp->GetFileSpec().GetPath().c_str () : "<null>", + m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); + } + } } } void DynamicLoaderPOSIXDYLD::DidLaunch() { + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s()", __FUNCTION__); + ModuleSP executable; addr_t load_offset; @@ -145,7 +206,11 @@ DynamicLoaderPOSIXDYLD::DidLaunch() ModuleList module_list; module_list.Append(executable); UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset); + + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s about to call ProbeEntry()", __FUNCTION__); ProbeEntry(); + m_process->GetTarget().ModulesDidLoad(module_list); } } @@ -187,15 +252,28 @@ DynamicLoaderPOSIXDYLD::UnloadSections(const ModuleSP module) void DynamicLoaderPOSIXDYLD::ProbeEntry() { - Breakpoint *entry_break; - addr_t entry; + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if ((entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) + const addr_t entry = GetEntryPoint(); + if (entry == LLDB_INVALID_ADDRESS) + { + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " GetEntryPoint() returned no address, not setting entry breakpoint", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); return; - - entry_break = m_process->GetTarget().CreateBreakpoint(entry, true, false).get(); - entry_break->SetCallback(EntryBreakpointHit, this, true); - entry_break->SetBreakpointKind("shared-library-event"); + } + + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " GetEntryPoint() returned address 0x%" PRIx64 ", setting entry breakpoint", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, entry); + + if (m_process) + { + Breakpoint *const entry_break = m_process->GetTarget().CreateBreakpoint(entry, true, false).get(); + entry_break->SetCallback(EntryBreakpointHit, this, true); + entry_break->SetBreakpointKind("shared-library-event"); + + // Shoudn't hit this more than once. + entry_break->SetOneShot (true); + } } // The runtime linker has run and initialized the rendezvous structure once the @@ -210,9 +288,40 @@ DynamicLoaderPOSIXDYLD::EntryBreakpointHit(void *baton, user_id_t break_id, user_id_t break_loc_id) { - DynamicLoaderPOSIXDYLD* dyld_instance; + assert(baton && "null baton"); + if (!baton) + return false; + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + DynamicLoaderPOSIXDYLD *const dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton); + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64, __FUNCTION__, dyld_instance->m_process ? dyld_instance->m_process->GetID () : LLDB_INVALID_PROCESS_ID); + + // Disable the breakpoint --- if a stop happens right after this, which we've seen on occasion, we don't + // want the breakpoint stepping thread-plan logic to show a breakpoint instruction at the disassembled + // entry point to the program. Disabling it prevents it. (One-shot is not enough - one-shot removal logic + // only happens after the breakpoint goes public, which wasn't happening in our scenario). + if (dyld_instance->m_process) + { + BreakpointSP breakpoint_sp = dyld_instance->m_process->GetTarget().GetBreakpointByID (break_id); + if (breakpoint_sp) + { + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " disabling breakpoint id %" PRIu64, __FUNCTION__, dyld_instance->m_process->GetID (), break_id); + breakpoint_sp->SetEnabled (false); + } + else + { + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " failed to find breakpoint for breakpoint id %" PRIu64, __FUNCTION__, dyld_instance->m_process->GetID (), break_id); + } + } + else + { + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s breakpoint id %" PRIu64 " no Process instance! Cannot disable breakpoint", __FUNCTION__, break_id); + } - dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton); dyld_instance->LoadAllCurrentModules(); dyld_instance->SetRendezvousBreakpoint(); return false; // Continue running. @@ -221,16 +330,25 @@ DynamicLoaderPOSIXDYLD::EntryBreakpointHit(void *baton, void DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() { + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + addr_t break_addr = m_rendezvous.GetBreakAddress(); Target &target = m_process->GetTarget(); if (m_dyld_bid == LLDB_INVALID_BREAK_ID) { + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " setting rendezvous break address at 0x%" PRIx64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, break_addr); Breakpoint *dyld_break = target.CreateBreakpoint (break_addr, true, false).get(); dyld_break->SetCallback(RendezvousBreakpointHit, this, true); dyld_break->SetBreakpointKind ("shared-library-event"); m_dyld_bid = dyld_break->GetID(); } + else + { + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reusing break id %" PRIu32 ", address at 0x%" PRIx64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, m_dyld_bid, break_addr); + } // Make sure our breakpoint is at the right address. assert (target.GetBreakpointByID(m_dyld_bid)->FindLocationByAddress(break_addr)->GetBreakpoint().GetID() == m_dyld_bid); @@ -242,13 +360,22 @@ DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit(void *baton, user_id_t break_id, user_id_t break_loc_id) { - DynamicLoaderPOSIXDYLD* dyld_instance; + assert (baton && "null baton"); + if (!baton) + return false; + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + DynamicLoaderPOSIXDYLD *const dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton); + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64, __FUNCTION__, dyld_instance->m_process ? dyld_instance->m_process->GetID () : LLDB_INVALID_PROCESS_ID); - dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton); dyld_instance->RefreshModules(); // Return true to stop the target, false to just let the target run. - return dyld_instance->GetStopWhenImagesChange(); + const bool stop_when_images_change = dyld_instance->GetStopWhenImagesChange(); + if (log) + log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " stop_when_images_change=%s", __FUNCTION__, dyld_instance->m_process ? dyld_instance->m_process->GetID () : LLDB_INVALID_PROCESS_ID, stop_when_images_change ? "true" : "false"); + return stop_when_images_change; } void @@ -439,6 +566,13 @@ DynamicLoaderPOSIXDYLD::GetEntryPoint() return LLDB_INVALID_ADDRESS; m_entry_point = static_cast<addr_t>(I->value); + + const ArchSpec &arch = m_process->GetTarget().GetArchitecture(); + + // On ppc64, the entry point is actually a descriptor. Dereference it. + if (arch.GetMachine() == llvm::Triple::ppc64) + m_entry_point = ReadUnsignedIntWithSizeInBytes(m_entry_point, 8); + return m_entry_point; } @@ -487,3 +621,18 @@ DynamicLoaderPOSIXDYLD::GetThreadLocalData (const lldb::ModuleSP module, const l return tls_block; } + +bool +DynamicLoaderPOSIXDYLD::GetProcessModuleSpec (ModuleSpec& module_spec) +{ + if (m_process == nullptr) + return false; + + auto& target = m_process->GetTarget (); + ProcessInstanceInfo process_info; + if (!target.GetPlatform ()->GetProcessInfo (m_process->GetID (), process_info)) + return false; + + module_spec = ModuleSpec (process_info.GetExecutableFile (), process_info.GetArchitecture ()); + return true; +} diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h index 9ced5da8a0157..747ff3f2be360 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -168,6 +168,10 @@ protected: lldb::addr_t GetEntryPoint(); + /// Loads ModuleSpec data from inferior process. + bool + GetProcessModuleSpec(lldb_private::ModuleSpec& module_spec); + private: DISALLOW_COPY_AND_ASSIGN(DynamicLoaderPOSIXDYLD); }; diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index fa8681ed69fea..bc358a985248a 100644 --- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -9873,12 +9873,14 @@ EmulateInstructionARM::EmulateSTREX (const uint32_t opcode, const ARMEncoding en if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 0)) return false; } +#if 0 // unreachable because if true else { // R[d] = 1; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 1)) return false; } +#endif // unreachable because if true } return true; } diff --git a/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp b/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp new file mode 100644 index 0000000000000..96754ff787873 --- /dev/null +++ b/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp @@ -0,0 +1,314 @@ +//===-- AddressSanitizerRuntime.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AddressSanitizerRuntime.h" + +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/PluginInterface.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/InstrumentationRuntimeStopInfo.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +lldb::InstrumentationRuntimeSP +AddressSanitizerRuntime::CreateInstance (const lldb::ProcessSP &process_sp) +{ + return InstrumentationRuntimeSP(new AddressSanitizerRuntime(process_sp)); +} + +void +AddressSanitizerRuntime::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + "AddressSanitizer instrumentation runtime plugin.", + CreateInstance, + GetTypeStatic); +} + +void +AddressSanitizerRuntime::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +lldb_private::ConstString +AddressSanitizerRuntime::GetPluginNameStatic() +{ + return ConstString("AddressSanitizer"); +} + +lldb::InstrumentationRuntimeType +AddressSanitizerRuntime::GetTypeStatic() +{ + return eInstrumentationRuntimeTypeAddressSanitizer; +} + +AddressSanitizerRuntime::AddressSanitizerRuntime(const ProcessSP &process_sp) : + m_is_active(false), + m_runtime_module(), + m_process(process_sp), + m_breakpoint_id(0) +{ +} + +AddressSanitizerRuntime::~AddressSanitizerRuntime() +{ + Deactivate(); +} + +bool ModuleContainsASanRuntime(Module * module) +{ + SymbolContextList sc_list; + const bool include_symbols = true; + const bool append = true; + const bool include_inlines = true; + + size_t num_matches = module->FindFunctions(ConstString("__asan_get_alloc_stack"), NULL, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list); + + return num_matches > 0; +} + +void +AddressSanitizerRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list) +{ + if (IsActive()) + return; + + if (m_runtime_module) { + Activate(); + return; + } + + Mutex::Locker modules_locker(module_list.GetMutex()); + const size_t num_modules = module_list.GetSize(); + for (size_t i = 0; i < num_modules; ++i) + { + Module *module_pointer = module_list.GetModulePointerAtIndexUnlocked(i); + const FileSpec & file_spec = module_pointer->GetFileSpec(); + if (! file_spec) + continue; + + static RegularExpression g_asan_runtime_regex("libclang_rt.asan_(.*)_dynamic\\.dylib"); + if (g_asan_runtime_regex.Execute (file_spec.GetFilename().GetCString()) || module_pointer->IsExecutable()) + { + if (ModuleContainsASanRuntime(module_pointer)) + { + m_runtime_module = module_pointer->shared_from_this(); + Activate(); + return; + } + } + } +} + +bool +AddressSanitizerRuntime::IsActive() +{ + return m_is_active; +} + +#define RETRIEVE_REPORT_DATA_FUNCTION_TIMEOUT_USEC 2*1000*1000 + +const char * +address_sanitizer_retrieve_report_data_command = R"( + struct { + int present; + void *pc, *bp, *sp, *address; + int access_type; + size_t access_size; + const char *description; + } t; + + t.present = ((int (*) ())__asan_report_present)(); + t.pc = ((void * (*) ())__asan_get_report_pc)(); + /* commented out because rdar://problem/18533301 + t.bp = ((void * (*) ())__asan_get_report_bp)(); + t.sp = ((void * (*) ())__asan_get_report_sp)(); + */ + t.address = ((void * (*) ())__asan_get_report_address)(); + t.description = ((const char * (*) ())__asan_get_report_description)(); + t.access_type = ((int (*) ())__asan_get_report_access_type)(); + t.access_size = ((size_t (*) ())__asan_get_report_access_size)(); + + t; +)"; + +StructuredData::ObjectSP +AddressSanitizerRuntime::RetrieveReportData() +{ + ThreadSP thread_sp = m_process->GetThreadList().GetSelectedThread(); + StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); + + if (!frame_sp) + return StructuredData::ObjectSP(); + + EvaluateExpressionOptions options; + options.SetUnwindOnError(true); + options.SetTryAllThreads(true); + options.SetStopOthers(true); + options.SetIgnoreBreakpoints(true); + options.SetTimeoutUsec(RETRIEVE_REPORT_DATA_FUNCTION_TIMEOUT_USEC); + + ValueObjectSP return_value_sp; + if (m_process->GetTarget().EvaluateExpression(address_sanitizer_retrieve_report_data_command, frame_sp.get(), return_value_sp, options) != eExpressionCompleted) + return StructuredData::ObjectSP(); + + int present = return_value_sp->GetValueForExpressionPath(".present")->GetValueAsUnsigned(0); + if (present != 1) + return StructuredData::ObjectSP(); + + addr_t pc = return_value_sp->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0); + addr_t bp = return_value_sp->GetValueForExpressionPath(".bp")->GetValueAsUnsigned(0); + addr_t sp = return_value_sp->GetValueForExpressionPath(".sp")->GetValueAsUnsigned(0); + addr_t address = return_value_sp->GetValueForExpressionPath(".address")->GetValueAsUnsigned(0); + addr_t access_type = return_value_sp->GetValueForExpressionPath(".access_type")->GetValueAsUnsigned(0); + addr_t access_size = return_value_sp->GetValueForExpressionPath(".access_size")->GetValueAsUnsigned(0); + addr_t description_ptr = return_value_sp->GetValueForExpressionPath(".description")->GetValueAsUnsigned(0); + std::string description; + Error error; + m_process->ReadCStringFromMemory(description_ptr, description, error); + + StructuredData::Dictionary *dict = new StructuredData::Dictionary(); + dict->AddStringItem("instrumentation_class", "AddressSanitizer"); + dict->AddStringItem("stop_type", "fatal_error"); + dict->AddIntegerItem("pc", pc); + dict->AddIntegerItem("bp", bp); + dict->AddIntegerItem("sp", sp); + dict->AddIntegerItem("address", address); + dict->AddIntegerItem("access_type", access_type); + dict->AddIntegerItem("access_size", access_size); + dict->AddStringItem("description", description); + + return StructuredData::ObjectSP(dict); +} + +std::string +AddressSanitizerRuntime::FormatDescription(StructuredData::ObjectSP report) +{ + std::string description = report->GetAsDictionary()->GetValueForKey("description")->GetAsString()->GetValue(); + if (description == "heap-use-after-free") { + return "Use of deallocated memory detected"; + } else if (description == "heap-buffer-overflow") { + return "Heap buffer overflow detected"; + } else if (description == "stack-buffer-underflow") { + return "Stack buffer underflow detected"; + } else if (description == "initialization-order-fiasco") { + return "Initialization order problem detected"; + } else if (description == "stack-buffer-overflow") { + return "Stack buffer overflow detected"; + } else if (description == "stack-use-after-return") { + return "Use of returned stack memory detected"; + } else if (description == "use-after-poison") { + return "Use of poisoned memory detected"; + } else if (description == "container-overflow") { + return "Container overflow detected"; + } else if (description == "stack-use-after-scope") { + return "Use of out-of-scope stack memory detected"; + } else if (description == "global-buffer-overflow") { + return "Global buffer overflow detected"; + } else if (description == "unknown-crash") { + return "Invalid memory access detected"; + } + + // for unknown report codes just show the code + return description; +} + +bool +AddressSanitizerRuntime::NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, user_id_t break_id, user_id_t break_loc_id) +{ + assert (baton && "null baton"); + if (!baton) + return false; + + AddressSanitizerRuntime *const instance = static_cast<AddressSanitizerRuntime*>(baton); + + StructuredData::ObjectSP report = instance->RetrieveReportData(); + std::string description; + if (report) { + description = instance->FormatDescription(report); + } + ThreadSP thread = context->exe_ctx_ref.GetThreadSP(); + thread->SetStopInfo(InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(*thread, description.c_str(), report)); + + if (instance->m_process) + { + StreamFileSP stream_sp (instance->m_process->GetTarget().GetDebugger().GetOutputFile()); + if (stream_sp) + { + stream_sp->Printf ("AddressSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.\n"); + } + } + // Return true to stop the target, false to just let the target run. + return true; +} + +void +AddressSanitizerRuntime::Activate() +{ + if (m_is_active) + return; + + ConstString symbol_name ("__asan::AsanDie()"); + const Symbol *symbol = m_runtime_module->FindFirstSymbolWithNameAndType (symbol_name, eSymbolTypeCode); + + if (symbol == NULL) + return; + + if (!symbol->GetAddress().IsValid()) + return; + + Target &target = m_process->GetTarget(); + addr_t symbol_address = symbol->GetAddress().GetOpcodeLoadAddress(&target); + + if (symbol_address == LLDB_INVALID_ADDRESS) + return; + + bool internal = true; + bool hardware = false; + Breakpoint *breakpoint = m_process->GetTarget().CreateBreakpoint(symbol_address, internal, hardware).get(); + breakpoint->SetCallback (AddressSanitizerRuntime::NotifyBreakpointHit, this, true); + breakpoint->SetBreakpointKind ("address-sanitizer-report"); + m_breakpoint_id = breakpoint->GetID(); + + if (m_process) + { + StreamFileSP stream_sp (m_process->GetTarget().GetDebugger().GetOutputFile()); + if (stream_sp) + { + stream_sp->Printf ("AddressSanitizer debugger support is active. Memory error breakpoint has been installed and you can now use the 'memory history' command.\n"); + } + } + + m_is_active = true; +} + +void +AddressSanitizerRuntime::Deactivate() +{ + if (m_breakpoint_id != LLDB_INVALID_BREAK_ID) + { + m_process->GetTarget().RemoveBreakpointByID(m_breakpoint_id); + m_breakpoint_id = LLDB_INVALID_BREAK_ID; + } + m_is_active = false; +} diff --git a/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h b/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h new file mode 100644 index 0000000000000..69c134cbedaff --- /dev/null +++ b/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h @@ -0,0 +1,86 @@ +//===-- AddressSanitizerRuntime.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_AddressSanitizerRuntime_h_ +#define liblldb_AddressSanitizerRuntime_h_ + +#include "lldb/lldb-private.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/InstrumentationRuntime.h" +#include "lldb/Target/Process.h" +#include "lldb/Core/StructuredData.h" + +namespace lldb_private { + +class AddressSanitizerRuntime : public lldb_private::InstrumentationRuntime +{ +public: + + static lldb::InstrumentationRuntimeSP + CreateInstance (const lldb::ProcessSP &process_sp); + + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static lldb::InstrumentationRuntimeType + GetTypeStatic(); + + virtual + ~AddressSanitizerRuntime(); + + virtual lldb_private::ConstString + GetPluginName() { return GetPluginNameStatic(); } + + virtual lldb::InstrumentationRuntimeType + GetType() { return GetTypeStatic(); } + + virtual uint32_t + GetPluginVersion() { return 1; } + + virtual void + ModulesDidLoad(lldb_private::ModuleList &module_list); + + virtual bool + IsActive(); + +private: + + AddressSanitizerRuntime(const lldb::ProcessSP &process_sp); + + void + Activate(); + + void + Deactivate(); + + static bool + NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + + StructuredData::ObjectSP + RetrieveReportData(); + + std::string + FormatDescription(StructuredData::ObjectSP report); + + bool m_is_active; + lldb::ModuleSP m_runtime_module; + lldb::ProcessSP m_process; + lldb::user_id_t m_breakpoint_id; + +}; + +} // namespace lldb_private + +#endif // liblldb_InstrumentationRuntime_h_ diff --git a/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index 905984d334105..cd303cb0768f4 100644 --- a/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -36,21 +36,24 @@ typedef enum JIT_UNREGISTER_FN } jit_actions_t; +#pragma pack(push, 4) +template <typename ptr_t> struct jit_code_entry { - struct jit_code_entry *next_entry; - struct jit_code_entry *prev_entry; - const char *symfile_addr; + ptr_t next_entry; // pointer + ptr_t prev_entry; // pointer + ptr_t symfile_addr; // pointer uint64_t symfile_size; }; - +template <typename ptr_t> struct jit_descriptor { uint32_t version; uint32_t action_flag; // Values are jit_action_t - struct jit_code_entry *relevant_entry; - struct jit_code_entry *first_entry; + ptr_t relevant_entry; // pointer + ptr_t first_entry; // pointer }; +#pragma pack(pop) JITLoaderGDB::JITLoaderGDB (lldb_private::Process *process) : JITLoader(process), @@ -198,6 +201,17 @@ static void updateSectionLoadAddress(const SectionList §ion_list, bool JITLoaderGDB::ReadJITDescriptor(bool all_entries) { + Target &target = m_process->GetTarget(); + if (target.GetArchitecture().GetAddressByteSize() == 8) + return ReadJITDescriptorImpl<uint64_t>(all_entries); + else + return ReadJITDescriptorImpl<uint32_t>(all_entries); +} + +template <typename ptr_t> +bool +JITLoaderGDB::ReadJITDescriptorImpl(bool all_entries) +{ if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS) return false; @@ -205,7 +219,7 @@ JITLoaderGDB::ReadJITDescriptor(bool all_entries) Target &target = m_process->GetTarget(); ModuleList &module_list = target.GetImages(); - jit_descriptor jit_desc; + jit_descriptor<ptr_t> jit_desc; const size_t jit_desc_size = sizeof(jit_desc); Error error; size_t bytes_read = m_process->DoReadMemory( @@ -228,7 +242,7 @@ JITLoaderGDB::ReadJITDescriptor(bool all_entries) while (jit_relevant_entry != 0) { - jit_code_entry jit_entry; + jit_code_entry<ptr_t> jit_entry; const size_t jit_entry_size = sizeof(jit_entry); bytes_read = m_process->DoReadMemory(jit_relevant_entry, &jit_entry, jit_entry_size, error); if (bytes_read != jit_entry_size || !error.Success()) diff --git a/source/Plugins/JITLoader/GDB/JITLoaderGDB.h b/source/Plugins/JITLoader/GDB/JITLoaderGDB.h index 5fa66b8749723..bfa1721d3349c 100644 --- a/source/Plugins/JITLoader/GDB/JITLoaderGDB.h +++ b/source/Plugins/JITLoader/GDB/JITLoaderGDB.h @@ -81,6 +81,10 @@ private: bool ReadJITDescriptor(bool all_entries); + template <typename ptr_t> + bool + ReadJITDescriptorImpl(bool all_entries); + static bool JITDebugBreakpointHit(void *baton, lldb_private::StoppointCallbackContext *context, diff --git a/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp new file mode 100644 index 0000000000000..c7c64ed54d87e --- /dev/null +++ b/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -0,0 +1,183 @@ +//===-- MemoryHistoryASan.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MemoryHistoryASan.h" + +#include "lldb/Target/MemoryHistory.h" + +#include "lldb/lldb-private.h" +#include "lldb/Core/PluginInterface.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/ThreadList.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Core/Module.h" +#include "Plugins/Process/Utility/HistoryThread.h" +#include "lldb/Core/ValueObject.h" + +using namespace lldb; +using namespace lldb_private; + +MemoryHistorySP +MemoryHistoryASan::CreateInstance (const ProcessSP &process_sp) +{ + if (!process_sp.get()) + return NULL; + + Target & target = process_sp->GetTarget(); + + bool found_asan_runtime = false; + + const ModuleList &target_modules = target.GetImages(); + Mutex::Locker modules_locker(target_modules.GetMutex()); + const size_t num_modules = target_modules.GetSize(); + for (size_t i = 0; i < num_modules; ++i) + { + Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked(i); + + SymbolContextList sc_list; + const bool include_symbols = true; + const bool append = true; + const bool include_inlines = true; + + size_t num_matches = module_pointer->FindFunctions(ConstString("__asan_get_alloc_stack"), NULL, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list); + + if (num_matches) + { + found_asan_runtime = true; + break; + } + } + + if (! found_asan_runtime) + return MemoryHistorySP(); + + return MemoryHistorySP(new MemoryHistoryASan(process_sp)); +} + +void +MemoryHistoryASan::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + "ASan memory history provider.", + CreateInstance); +} + +void +MemoryHistoryASan::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + + +ConstString +MemoryHistoryASan::GetPluginNameStatic() +{ + static ConstString g_name("asan"); + return g_name; +} + +MemoryHistoryASan::MemoryHistoryASan(const ProcessSP &process_sp) +{ + this->m_process_sp = process_sp; +} + +const char * +memory_history_asan_command_format = R"( + struct t { + void *alloc_trace[256]; + size_t alloc_count; + int alloc_tid; + + void *free_trace[256]; + size_t free_count; + int free_tid; + } t; + + t.alloc_count = ((size_t (*) (void *, void **, size_t, int *))__asan_get_alloc_stack)((void *)0x%)" PRIx64 R"(, t.alloc_trace, 256, &t.alloc_tid); + t.free_count = ((size_t (*) (void *, void **, size_t, int *))__asan_get_free_stack)((void *)0x%)" PRIx64 R"(, t.free_trace, 256, &t.free_tid); + + t; +)"; + +static void CreateHistoryThreadFromValueObject(ProcessSP process_sp, ValueObjectSP return_value_sp, const char *type, const char *thread_name, HistoryThreads & result) +{ + std::string count_path = "." + std::string(type) + "_count"; + std::string tid_path = "." + std::string(type) + "_tid"; + std::string trace_path = "." + std::string(type) + "_trace"; + + int count = return_value_sp->GetValueForExpressionPath(count_path.c_str())->GetValueAsUnsigned(0); + tid_t tid = return_value_sp->GetValueForExpressionPath(tid_path.c_str())->GetValueAsUnsigned(0); + + if (count <= 0) + return; + + ValueObjectSP trace_sp = return_value_sp->GetValueForExpressionPath(trace_path.c_str()); + + std::vector<lldb::addr_t> pcs; + for (int i = 0; i < count; i++) + { + addr_t pc = trace_sp->GetChildAtIndex(i, true)->GetValueAsUnsigned(0); + if (pc == 0 || pc == 1 || pc == LLDB_INVALID_ADDRESS) + continue; + pcs.push_back(pc); + } + + HistoryThread *history_thread = new HistoryThread(*process_sp, tid, pcs, 0, false); + ThreadSP new_thread_sp(history_thread); + // let's use thread name for the type of history thread, since history threads don't have names anyway + history_thread->SetThreadName(thread_name); + // Save this in the Process' ExtendedThreadList so a strong pointer retains the object + process_sp->GetExtendedThreadList().AddThread (new_thread_sp); + result.push_back(new_thread_sp); +} + +#define GET_STACK_FUNCTION_TIMEOUT_USEC 2*1000*1000 + +HistoryThreads +MemoryHistoryASan::GetHistoryThreads(lldb::addr_t address) +{ + ProcessSP process_sp = m_process_sp; + ThreadSP thread_sp = m_process_sp->GetThreadList().GetSelectedThread(); + StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); + + if (!frame_sp) + { + return HistoryThreads(); + } + + ExecutionContext exe_ctx (frame_sp); + ValueObjectSP return_value_sp; + StreamString expr; + expr.Printf(memory_history_asan_command_format, address, address); + + EvaluateExpressionOptions options; + options.SetUnwindOnError(true); + options.SetTryAllThreads(true); + options.SetStopOthers(true); + options.SetIgnoreBreakpoints(true); + options.SetTimeoutUsec(GET_STACK_FUNCTION_TIMEOUT_USEC); + + if (m_process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), return_value_sp, options) != eExpressionCompleted) + { + return HistoryThreads(); + } + if (!return_value_sp) + { + return HistoryThreads(); + } + + HistoryThreads result; + + CreateHistoryThreadFromValueObject(process_sp, return_value_sp, "alloc", "Memory allocated at", result); + CreateHistoryThreadFromValueObject(process_sp, return_value_sp, "free", "Memory deallocated at", result); + + return result; +} diff --git a/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h b/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h new file mode 100644 index 0000000000000..5307e0b340818 --- /dev/null +++ b/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h @@ -0,0 +1,62 @@ +//===-- MemoryHistoryASan.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_MemoryHistoryASan_h_ +#define liblldb_MemoryHistoryASan_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/MemoryHistory.h" +#include "lldb/Target/Process.h" + +namespace lldb_private { + +class MemoryHistoryASan : public lldb_private::MemoryHistory +{ +public: + + static lldb::MemoryHistorySP + CreateInstance (const lldb::ProcessSP &process_sp); + + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + virtual + ~MemoryHistoryASan () {} + + virtual lldb_private::ConstString + GetPluginName() { return GetPluginNameStatic(); } + + virtual uint32_t + GetPluginVersion() { return 1; } + + virtual lldb_private::HistoryThreads + GetHistoryThreads(lldb::addr_t address); + +private: + + MemoryHistoryASan(const lldb::ProcessSP &process_sp); + + lldb::ProcessSP m_process_sp; + +}; + +} // namespace lldb_private + +#endif // liblldb_MemoryHistoryASan_h_ diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 0263c23ce307f..1e2a0c721ff6e 100644 --- a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -9,7 +9,7 @@ #include "ObjectContainerBSDArchive.h" -#ifdef _WIN32 +#if defined(_WIN32) || defined(__ANDROID_NDK__) // Defines from ar, missing on Windows #define ARMAG "!<arch>\n" #define SARMAG 8 diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index f027294b7c570..12392c24407bc 100644 --- a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -173,6 +173,12 @@ ELFHeader::GetRelocationJumpSlotType() const default: assert(false && "architecture not supported"); break; + case EM_PPC: + slot = R_PPC_JMP_SLOT; + break; + case EM_PPC64: + slot = R_PPC64_JMP_SLOT; + break; case EM_386: case EM_486: slot = R_386_JUMP_SLOT; @@ -189,6 +195,9 @@ ELFHeader::GetRelocationJumpSlotType() const case EM_AARCH64: slot = R_AARCH64_JUMP_SLOT; break; + case EM_MIPS: + slot = R_MIPS_JUMP_SLOT; + break; } return slot; diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index d86aee78947fe..e7bf20e18008c 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -267,10 +267,14 @@ kalimbaVariantFromElfFlags(const elf::elf_word e_flags) { // TODO(mg11) Support more variants case 10: - kal_arch_variant = 3; + kal_arch_variant = llvm::Triple::KalimbaSubArch_v3; break; case 14: - kal_arch_variant = 4; + kal_arch_variant = llvm::Triple::KalimbaSubArch_v4; + break; + case 17: + case 20: + kal_arch_variant = llvm::Triple::KalimbaSubArch_v5; break; default: break; @@ -287,6 +291,34 @@ subTypeFromElfHeader(const elf::ELFHeader& header) LLDB_INVALID_CPUTYPE; } +//! The kalimba toolchain identifies a code section as being +//! one with the SHT_PROGBITS set in the section sh_type and the top +//! bit in the 32-bit address field set. +static lldb::SectionType +kalimbaSectionType( + const elf::ELFHeader& header, + const elf::ELFSectionHeader& sect_hdr) +{ + if (llvm::ELF::EM_CSR_KALIMBA != header.e_machine) + { + return eSectionTypeOther; + } + + if (llvm::ELF::SHT_NOBITS == sect_hdr.sh_type) + { + return eSectionTypeZeroFill; + } + + if (llvm::ELF::SHT_PROGBITS == sect_hdr.sh_type) + { + const lldb::addr_t KAL_CODE_BIT = 1 << 31; + return KAL_CODE_BIT & sect_hdr.sh_addr ? + eSectionTypeCode : eSectionTypeData; + } + + return eSectionTypeOther; +} + // Arbitrary constant used as UUID prefix for core files. const uint32_t ObjectFileELF::g_core_uuid_magic(0xE210C); @@ -826,6 +858,38 @@ ObjectFileELF::GetAddressByteSize() const return m_data.GetAddressByteSize(); } +// Top 16 bits of the `Symbol` flags are available. +#define ARM_ELF_SYM_IS_THUMB (1 << 16) + +AddressClass +ObjectFileELF::GetAddressClass (addr_t file_addr) +{ + auto res = ObjectFile::GetAddressClass (file_addr); + + if (res != eAddressClassCode) + return res; + + ArchSpec arch_spec; + GetArchitecture(arch_spec); + if (arch_spec.GetMachine() != llvm::Triple::arm) + return res; + + auto symtab = GetSymtab(); + if (symtab == nullptr) + return res; + + auto symbol = symtab->FindSymbolContainingFileAddress(file_addr); + if (symbol == nullptr) + return res; + + // Thumb symbols have the lower bit set in the flags field so we just check + // for that. + if (symbol->GetFlags() & ARM_ELF_SYM_IS_THUMB) + res = eAddressClassCodeAlternateISA; + + return res; +} + size_t ObjectFileELF::SectionIndex(const SectionHeaderCollIter &I) { @@ -1560,6 +1624,20 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list) break; } + if (eSectionTypeOther == sect_type) + { + // the kalimba toolchain assumes that ELF section names are free-form. It does + // supports linkscripts which (can) give rise to various arbitarily named + // sections being "Code" or "Data". + sect_type = kalimbaSectionType(m_header, header); + } + + const uint32_t target_bytes_size = + (eSectionTypeData == sect_type || eSectionTypeZeroFill == sect_type) ? + m_arch_spec.GetDataByteSize() : + eSectionTypeCode == sect_type ? + m_arch_spec.GetCodeByteSize() : 1; + elf::elf_xword log2align = (header.sh_addralign==0) ? 0 : llvm::Log2_64(header.sh_addralign); @@ -1573,7 +1651,8 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list) header.sh_offset, // Offset of this section in the file. file_size, // Size of the section as found in the file. log2align, // Alignment of the section - header.sh_flags)); // Flags for this section. + header.sh_flags, // Flags for this section. + target_bytes_size));// Number of host bytes per target byte if (is_thread_specific) section_sp->SetIsThreadSpecific (is_thread_specific); @@ -1645,6 +1724,7 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, static ConstString rodata1_section_name(".rodata1"); static ConstString data2_section_name(".data1"); static ConstString bss_section_name(".bss"); + static ConstString opd_section_name(".opd"); // For ppc64 //StreamFile strm(stdout, false); unsigned i; @@ -1746,6 +1826,48 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, } } + ArchSpec arch; + int64_t symbol_value_offset = 0; + uint32_t additional_flags = 0; + + if (GetArchitecture(arch) && + arch.GetMachine() == llvm::Triple::arm) + { + // ELF symbol tables may contain some mapping symbols. They provide + // information about the underlying data. There are three of them + // currently defined: + // $a[.<any>]* - marks an ARM instruction sequence + // $t[.<any>]* - marks a THUMB instruction sequence + // $d[.<any>]* - marks a data item sequence (e.g. lit pool) + // These symbols interfere with normal debugger operations and we + // don't need them. We can drop them here. + + static const llvm::StringRef g_armelf_arm_marker("$a"); + static const llvm::StringRef g_armelf_thumb_marker("$t"); + static const llvm::StringRef g_armelf_data_marker("$d"); + llvm::StringRef symbol_name_ref(symbol_name); + + if (symbol_name && + (symbol_name_ref.startswith(g_armelf_arm_marker) || + symbol_name_ref.startswith(g_armelf_thumb_marker) || + symbol_name_ref.startswith(g_armelf_data_marker))) + continue; + + // THUMB functions have the lower bit of their address set. Fixup + // the actual address and mark the symbol as THUMB. + if (symbol_type == eSymbolTypeCode && symbol.st_value & 1) + { + // Substracting 1 from the address effectively unsets + // the low order bit, which results in the address + // actually pointing to the beginning of the symbol. + // This delta will be used below in conjuction with + // symbol.st_value to produce the final symbol_value + // that we store in the symtab. + symbol_value_offset = -1; + additional_flags = ARM_ELF_SYM_IS_THUMB; + } + } + // If the symbol section we've found has no data (SHT_NOBITS), then check the module section // list. This can happen if we're parsing the debug file and it has no .text section, for example. if (symbol_section_sp && (symbol_section_sp->GetFileSize() == 0)) @@ -1766,12 +1888,15 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, } } - uint64_t symbol_value = symbol.st_value; + // symbol_value_offset may contain 0 for ARM symbols or -1 for + // THUMB symbols. See above for more details. + uint64_t symbol_value = symbol.st_value | symbol_value_offset; if (symbol_section_sp && CalculateType() != ObjectFile::Type::eTypeObjectFile) symbol_value -= symbol_section_sp->GetFileAddress(); bool is_global = symbol.getBinding() == STB_GLOBAL; - uint32_t flags = symbol.st_other << 8 | symbol.st_info; + uint32_t flags = symbol.st_other << 8 | symbol.st_info | additional_flags; bool is_mangled = symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false; + Symbol dc_symbol( i + start_id, // ID is the original symbol table index. symbol_name, // Symbol name. diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 6b036af7aeff4..b10dfb532cd06 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -133,6 +133,9 @@ public: virtual uint32_t GetAddressByteSize() const; + virtual lldb::AddressClass + GetAddressClass (lldb::addr_t file_addr); + virtual lldb_private::Symtab * GetSymtab(); diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index 7aa940a530b4b..3b38a5819934c 100644 --- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -32,7 +32,7 @@ using namespace lldb; using namespace lldb_private; -Platform * +PlatformSP PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch) { // The only time we create an instance is when we are creating a remote @@ -84,8 +84,8 @@ PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch) } } if (create) - return new PlatformFreeBSD (is_host); - return NULL; + return PlatformSP(new PlatformFreeBSD (is_host)); + return PlatformSP(); } @@ -124,7 +124,7 @@ PlatformFreeBSD::Initialize () // Force a host flag to true for the default platform object. PlatformSP default_platform_sp (new PlatformFreeBSD(true)); default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); - Platform::SetDefaultPlatform (default_platform_sp); + Platform::SetHostPlatform (default_platform_sp); #endif PluginManager::RegisterPlugin(PlatformFreeBSD::GetPluginNameStatic(false), PlatformFreeBSD::GetDescriptionStatic(false), @@ -180,8 +180,7 @@ PlatformFreeBSD::RunShellCommand (const char *command, Error -PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file, - const ArchSpec &exe_arch, +PlatformFreeBSD::ResolveExecutable (const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp, const FileSpecList *module_search_paths_ptr) { @@ -189,35 +188,33 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file, // Nothing special to do here, just use the actual file and architecture char exe_path[PATH_MAX]; - FileSpec resolved_exe_file (exe_file); + ModuleSpec resolved_module_spec(module_spec); if (IsHost()) { - // If we have "ls" as the exe_file, resolve the executable location based on + // If we have "ls" as the module_spec's file, resolve the executable location based on // the current path variables - if (!resolved_exe_file.Exists()) + if (!resolved_module_spec.GetFileSpec().Exists()) { - exe_file.GetPath(exe_path, sizeof(exe_path)); - resolved_exe_file.SetFile(exe_path, true); + module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); + resolved_module_spec.GetFileSpec().SetFile(exe_path, true); } - if (!resolved_exe_file.Exists()) - resolved_exe_file.ResolveExecutableLocation (); + if (!resolved_module_spec.GetFileSpec().Exists()) + resolved_module_spec.GetFileSpec().ResolveExecutableLocation (); - if (resolved_exe_file.Exists()) + if (resolved_module_spec.GetFileSpec().Exists()) error.Clear(); else { - exe_file.GetPath(exe_path, sizeof(exe_path)); - error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path); + error.SetErrorStringWithFormat("unable to find executable for '%s'", resolved_module_spec.GetFileSpec().GetPath().c_str()); } } else { if (m_remote_platform_sp) { - error = m_remote_platform_sp->ResolveExecutable (exe_file, - exe_arch, + error = m_remote_platform_sp->ResolveExecutable (module_spec, exe_module_sp, module_search_paths_ptr); } @@ -226,25 +223,24 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file, // We may connect to a process and use the provided executable (Don't use local $PATH). // Resolve any executable within a bundle on MacOSX - Host::ResolveExecutableInBundle (resolved_exe_file); + Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec()); - if (resolved_exe_file.Exists()) { + if (resolved_module_spec.GetFileSpec().Exists()) + { error.Clear(); } else { - exe_file.GetPath(exe_path, sizeof(exe_path)); - error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path); + error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", resolved_module_spec.GetFileSpec().GetPath().c_str()); } } } if (error.Success()) { - ModuleSpec module_spec (resolved_exe_file, exe_arch); - if (module_spec.GetArchitecture().IsValid()) + if (resolved_module_spec.GetArchitecture().IsValid()) { - error = ModuleList::GetSharedModule (module_spec, + error = ModuleList::GetSharedModule (resolved_module_spec, exe_module_sp, module_search_paths_ptr, NULL, @@ -254,8 +250,8 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file, { exe_module_sp.reset(); error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s", - exe_file.GetPath().c_str(), - exe_arch.GetArchitectureName()); + resolved_module_spec.GetFileSpec().GetPath().c_str(), + resolved_module_spec.GetArchitecture().GetArchitectureName()); } } else @@ -264,10 +260,9 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file, // the architectures that we should be using (in the correct order) // and see if we can find a match that way StreamString arch_names; - ArchSpec platform_arch; - for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx) + for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx) { - error = ModuleList::GetSharedModule (module_spec, + error = ModuleList::GetSharedModule (resolved_module_spec, exe_module_sp, module_search_paths_ptr, NULL, @@ -283,21 +278,21 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file, if (idx > 0) arch_names.PutCString (", "); - arch_names.PutCString (platform_arch.GetArchitectureName()); + arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName()); } if (error.Fail() || !exe_module_sp) { - if (exe_file.Readable()) + if (resolved_module_spec.GetFileSpec().Readable()) { error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s", - exe_file.GetPath().c_str(), + resolved_module_spec.GetFileSpec().GetPath().c_str(), GetPluginName().GetCString(), arch_names.GetString().c_str()); } else { - error.SetErrorStringWithFormat("'%s' is not readable", exe_file.GetPath().c_str()); + error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str()); } } } @@ -326,6 +321,13 @@ PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite trap_opcode_size = sizeof(g_i386_opcode); } break; + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + { + static const uint8_t g_ppc_opcode[] = { 0x7f, 0xe0, 0x00, 0x08 }; + trap_opcode = g_ppc_opcode; + trap_opcode_size = sizeof(g_ppc_opcode); + } } if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) @@ -404,7 +406,7 @@ PlatformFreeBSD::ConnectRemote (Args& args) else { if (!m_remote_platform_sp) - m_remote_platform_sp = Platform::Create ("remote-gdb-server", error); + m_remote_platform_sp = Platform::Create (ConstString("remote-gdb-server"), error); if (m_remote_platform_sp) { @@ -507,7 +509,6 @@ lldb::ProcessSP PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info, Debugger &debugger, Target *target, - Listener &listener, Error &error) { lldb::ProcessSP process_sp; @@ -535,7 +536,7 @@ PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info, // The freebsd always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! // Just like the darwin plugin. - process_sp = target->CreateProcess (listener, "gdb-remote", NULL); + process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL); if (process_sp) error = process_sp->Attach (attach_info); @@ -544,7 +545,7 @@ PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info, else { if (m_remote_platform_sp) - process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error); + process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error); else error.SetErrorString ("the platform is not currently connected"); } diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h index 62958a08a9e0e..ce3f8cfad9762 100644 --- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h +++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h @@ -24,7 +24,7 @@ public: //------------------------------------------------------------ // Class functions //------------------------------------------------------------ - static lldb_private::Platform* + static lldb::PlatformSP CreateInstance (bool force, const lldb_private::ArchSpec *arch); static void @@ -80,8 +80,7 @@ public: uint32_t timeout_sec); virtual lldb_private::Error - ResolveExecutable (const lldb_private::FileSpec &exe_file, - const lldb_private::ArchSpec &arch, + ResolveExecutable (const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp, const lldb_private::FileSpecList *module_search_paths_ptr); @@ -135,7 +134,6 @@ public: Attach(lldb_private::ProcessAttachInfo &attach_info, lldb_private::Debugger &debugger, lldb_private::Target *target, - lldb_private::Listener &listener, lldb_private::Error &error); // FreeBSD processes can not be launched by spawning and attaching. diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index cc4c693e1b434..b1be0f5b1fe12 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -15,7 +15,9 @@ // Project includes #include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/File.h" #include "lldb/Host/FileCache.h" @@ -330,8 +332,14 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, error = source_file.Read(buffer_sp->GetBytes(), bytes_read); if (bytes_read) { - WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error); - offset += bytes_read; + const uint64_t bytes_written = WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error); + offset += bytes_written; + if (bytes_written != bytes_read) + { + // We didn't write the correct numbe of bytes, so adjust + // the file position in the source file we are reading from... + source_file.SeekFromStart(offset); + } } else break; @@ -343,6 +351,18 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, // std::string dst_path (destination.GetPath()); // if (chown_file(this,dst_path.c_str(),uid,gid) != 0) // return Error("unable to perform chown"); + + + uint64_t src_md5[2]; + uint64_t dst_md5[2]; + + if (FileSystem::CalculateMD5 (source, src_md5[0], src_md5[1]) && CalculateMD5 (destination, dst_md5[0], dst_md5[1])) + { + if (src_md5[0] != dst_md5[0] || src_md5[1] != dst_md5[1]) + { + error.SetErrorString("md5 checksum of installed file doesn't match, installation failed"); + } + } return error; } return Platform::PutFile(source,destination,uid,gid); @@ -616,6 +636,18 @@ PlatformPOSIX::GetRemoteOSBuildString (std::string &s) return false; } +size_t +PlatformPOSIX::GetEnvironment (StringList &env) +{ + if (IsRemote()) + { + if (m_remote_platform_sp) + return m_remote_platform_sp->GetEnvironment(env); + return 0; + } + return Host::GetEnvironment(env); +} + bool PlatformPOSIX::GetRemoteOSKernelDescription (std::string &s) { @@ -681,7 +713,7 @@ PlatformPOSIX::ConnectRemote (Args& args) else { if (!m_remote_platform_sp) - m_remote_platform_sp = Platform::Create ("remote-gdb-server", error); + m_remote_platform_sp = Platform::Create (ConstString("remote-gdb-server"), error); if (m_remote_platform_sp && error.Success()) error = m_remote_platform_sp->ConnectRemote (args); @@ -739,11 +771,97 @@ PlatformPOSIX::DisconnectRemote () return error; } +Error +PlatformPOSIX::LaunchProcess (ProcessLaunchInfo &launch_info) +{ + Error error; + + if (IsHost()) + { + error = Platform::LaunchProcess (launch_info); + } + else + { + if (m_remote_platform_sp) + error = m_remote_platform_sp->LaunchProcess (launch_info); + else + error.SetErrorString ("the platform is not currently connected"); + } + return error; +} + +lldb::ProcessSP +PlatformPOSIX::Attach (ProcessAttachInfo &attach_info, + Debugger &debugger, + Target *target, + Error &error) +{ + lldb::ProcessSP process_sp; + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + + if (IsHost()) + { + if (target == NULL) + { + TargetSP new_target_sp; + + error = debugger.GetTargetList().CreateTarget (debugger, + NULL, + NULL, + false, + NULL, + new_target_sp); + target = new_target_sp.get(); + if (log) + log->Printf ("PlatformPOSIX::%s created new target", __FUNCTION__); + } + else + { + error.Clear(); + if (log) + log->Printf ("PlatformPOSIX::%s target already existed, setting target", __FUNCTION__); + } + + if (target && error.Success()) + { + debugger.GetTargetList().SetSelectedTarget(target); + if (log) + { + ModuleSP exe_module_sp = target->GetExecutableModule (); + log->Printf ("PlatformPOSIX::%s set selected target to %p %s", __FUNCTION__, + target, + exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<null>" ); + } + + + process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), attach_info.GetProcessPluginName(), NULL); + + if (process_sp) + { + // Set UnixSignals appropriately. + process_sp->SetUnixSignals (Host::GetUnixSignals ()); + + ListenerSP listener_sp (new Listener("lldb.PlatformPOSIX.attach.hijack")); + attach_info.SetHijackListener(listener_sp); + process_sp->HijackProcessEvents(listener_sp.get()); + error = process_sp->Attach (attach_info); + } + } + } + else + { + if (m_remote_platform_sp) + process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error); + else + error.SetErrorString ("the platform is not currently connected"); + } + return process_sp; +} + lldb::ProcessSP PlatformPOSIX::DebugProcess (ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, // Can be NULL, if NULL create a new target, else use existing one - Listener &listener, Error &error) { ProcessSP process_sp; @@ -754,12 +872,12 @@ PlatformPOSIX::DebugProcess (ProcessLaunchInfo &launch_info, // We still need to reap it from lldb but if we let the monitor thread also set the exit status, we set up a // race between debugserver & us for who will find out about the debugged process's death. launch_info.GetFlags().Set(eLaunchFlagDontSetExitStatus); - process_sp = Platform::DebugProcess (launch_info, debugger, target, listener, error); + process_sp = Platform::DebugProcess (launch_info, debugger, target, error); } else { if (m_remote_platform_sp) - process_sp = m_remote_platform_sp->DebugProcess (launch_info, debugger, target, listener, error); + process_sp = m_remote_platform_sp->DebugProcess (launch_info, debugger, target, error); else error.SetErrorString ("the platform is not currently connected"); } diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 374e36495d886..aae415e6eefa9 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -31,8 +31,9 @@ public: //------------------------------------------------------------ // lldb_private::Platform functions //------------------------------------------------------------ - virtual lldb_private::OptionGroupOptions* - GetConnectionOptions (lldb_private::CommandInterpreter& interpreter); + virtual lldb_private::OptionGroupOptions + *GetConnectionOptions( + lldb_private::CommandInterpreter &interpreter) override; const char * GetHostname () override; @@ -47,47 +48,47 @@ public: PutFile (const lldb_private::FileSpec& source, const lldb_private::FileSpec& destination, uint32_t uid = UINT32_MAX, - uint32_t gid = UINT32_MAX); + uint32_t gid = UINT32_MAX) override; virtual lldb::user_id_t OpenFile (const lldb_private::FileSpec& file_spec, uint32_t flags, uint32_t mode, - lldb_private::Error &error); + lldb_private::Error &error) override; virtual bool CloseFile (lldb::user_id_t fd, - lldb_private::Error &error); + lldb_private::Error &error) override; virtual uint64_t ReadFile (lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, - lldb_private::Error &error); + lldb_private::Error &error) override; virtual uint64_t WriteFile (lldb::user_id_t fd, uint64_t offset, const void* src, uint64_t src_len, - lldb_private::Error &error); + lldb_private::Error &error) override; virtual lldb::user_id_t - GetFileSize (const lldb_private::FileSpec& file_spec); + GetFileSize (const lldb_private::FileSpec& file_spec) override; virtual lldb_private::Error - CreateSymlink(const char *src, const char *dst); + CreateSymlink(const char *src, const char *dst) override; virtual lldb_private::Error GetFile (const lldb_private::FileSpec& source, - const lldb_private::FileSpec& destination); + const lldb_private::FileSpec& destination) override; virtual lldb_private::ConstString - GetRemoteWorkingDirectory(); + GetRemoteWorkingDirectory() override; virtual bool - SetRemoteWorkingDirectory(const lldb_private::ConstString &path); + SetRemoteWorkingDirectory(const lldb_private::ConstString &path) override; bool GetRemoteOSVersion () override; @@ -101,6 +102,9 @@ public: lldb_private::ArchSpec GetRemoteSystemArchitecture () override; + size_t + GetEnvironment (lldb_private::StringList &environment) override; + bool IsConnected () const override; @@ -110,40 +114,48 @@ public: int *status_ptr, // Pass NULL if you don't want the process exit status int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit std::string *command_output, // Pass NULL if you don't want the command output - uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish + uint32_t timeout_sec) override;// Timeout in seconds to wait for shell program to finish virtual lldb_private::Error - MakeDirectory (const char *path, uint32_t mode); + MakeDirectory (const char *path, uint32_t mode) override; virtual lldb_private::Error - GetFilePermissions (const char *path, uint32_t &file_permissions); + GetFilePermissions (const char *path, uint32_t &file_permissions) override; virtual lldb_private::Error - SetFilePermissions (const char *path, uint32_t file_permissions); + SetFilePermissions (const char *path, uint32_t file_permissions) override; virtual bool - GetFileExists (const lldb_private::FileSpec& file_spec); + GetFileExists (const lldb_private::FileSpec& file_spec) override; virtual lldb_private::Error - Unlink (const char *path); + Unlink (const char *path) override; + + lldb_private::Error + LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info) override; + + lldb::ProcessSP + Attach (lldb_private::ProcessAttachInfo &attach_info, + lldb_private::Debugger &debugger, + lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one + lldb_private::Error &error) override; lldb::ProcessSP DebugProcess (lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Debugger &debugger, lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one - lldb_private::Listener &listener, lldb_private::Error &error) override; virtual std::string - GetPlatformSpecificConnectionInformation(); + GetPlatformSpecificConnectionInformation() override; virtual bool CalculateMD5 (const lldb_private::FileSpec& file_spec, uint64_t &low, - uint64_t &high); + uint64_t &high) override; virtual void - CalculateTrapHandlerSymbolNames (); + CalculateTrapHandlerSymbolNames () override; lldb_private::Error ConnectRemote (lldb_private::Args& args) override; diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 05fbc51012789..43eae4d906ece 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -16,14 +16,15 @@ // Other libraries and framework includes // Project includes #include "lldb/Breakpoint/BreakpointLocation.h" -#include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" +#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamString.h" +#include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" #include "lldb/Target/Process.h" @@ -56,7 +57,7 @@ PlatformRemoteGDBServer::Terminate () } } -Platform* +PlatformSP PlatformRemoteGDBServer::CreateInstance (bool force, const lldb_private::ArchSpec *arch) { bool create = force; @@ -65,8 +66,8 @@ PlatformRemoteGDBServer::CreateInstance (bool force, const lldb_private::ArchSpe create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified(); } if (create) - return new PlatformRemoteGDBServer (); - return NULL; + return PlatformSP(new PlatformRemoteGDBServer()); + return PlatformSP(); } @@ -100,14 +101,13 @@ PlatformRemoteGDBServer::GetDescription () } Error -PlatformRemoteGDBServer::ResolveExecutable (const FileSpec &exe_file, - const ArchSpec &exe_arch, +PlatformRemoteGDBServer::ResolveExecutable (const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp, const FileSpecList *module_search_paths_ptr) { Error error; //error.SetErrorString ("PlatformRemoteGDBServer::ResolveExecutable() is unimplemented"); - if (m_gdb_client.GetFileExists(exe_file)) + if (m_gdb_client.GetFileExists(module_spec.GetFileSpec())) return error; // TODO: get the remote end to somehow resolve this file error.SetErrorString("file not found on remote end"); @@ -421,7 +421,6 @@ lldb::ProcessSP PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Debugger &debugger, lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one - lldb_private::Listener &listener, lldb_private::Error &error) { lldb::ProcessSP process_sp; @@ -473,7 +472,7 @@ PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_i // The darwin always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! - process_sp = target->CreateProcess (listener, "gdb-remote", NULL); + process_sp = target->CreateProcess (launch_info.GetListenerForProcess(debugger), "gdb-remote", NULL); if (process_sp) { @@ -488,10 +487,16 @@ PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_i port + port_offset); assert (connect_url_len < (int)sizeof(connect_url)); error = process_sp->ConnectRemote (NULL, connect_url); + // Retry the connect remote one time... + if (error.Fail()) + error = process_sp->ConnectRemote (NULL, connect_url); if (error.Success()) error = process_sp->Launch(launch_info); else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + { + printf ("error: connect remote failed (%s)\n", error.AsCString()); m_gdb_client.KillSpawnedProcess(debugserver_pid); + } } } } @@ -509,7 +514,6 @@ lldb::ProcessSP PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info, Debugger &debugger, Target *target, // Can be NULL, if NULL create a new target, else use existing one - Listener &listener, Error &error) { lldb::ProcessSP process_sp; @@ -561,7 +565,7 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info, // The darwin always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! - process_sp = target->CreateProcess (listener, "gdb-remote", NULL); + process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL); if (process_sp) { diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index e236e97c8bb3b..90b16b8b8fa9f 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -29,7 +29,7 @@ public: static void Terminate (); - static lldb_private::Platform* + static lldb::PlatformSP CreateInstance (bool force, const lldb_private::ArchSpec *arch); static lldb_private::ConstString @@ -64,8 +64,7 @@ public: // lldb_private::Platform functions //------------------------------------------------------------ virtual lldb_private::Error - ResolveExecutable (const lldb_private::FileSpec &exe_file, - const lldb_private::ArchSpec &arch, + ResolveExecutable (const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp, const lldb_private::FileSpecList *module_search_paths_ptr); @@ -92,14 +91,12 @@ public: DebugProcess (lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Debugger &debugger, lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one - lldb_private::Listener &listener, lldb_private::Error &error); virtual lldb::ProcessSP Attach (lldb_private::ProcessAttachInfo &attach_info, lldb_private::Debugger &debugger, lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one - lldb_private::Listener &listener, lldb_private::Error &error); virtual bool diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index 4b488444de1e0..5a0b5ed141941 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -258,8 +258,7 @@ ProcessFreeBSD::SendMessage(const ProcessMessage &message) case ProcessMessage::eLimboMessage: case ProcessMessage::eExitMessage: - m_exit_status = message.GetExitStatus(); - SetExitStatus(m_exit_status, NULL); + SetExitStatus(message.GetExitStatus(), NULL); break; case ProcessMessage::eSignalMessage: diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 63439b155111c..84e35ba22644b 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -25,6 +25,7 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Host/Host.h" +#include "lldb/Host/ThreadLauncher.h" #include "lldb/Target/Thread.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/PseudoTerminal.h" @@ -112,6 +113,7 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, log->Printf("PT_GETREGS: ax=0x%lx", r->r_rax); } #endif +#ifndef __powerpc__ if (req == PT_GETDBREGS || req == PT_SETDBREGS) { struct dbreg *r = (struct dbreg *) addr; char setget = (req == PT_GETDBREGS) ? 'G' : 'S'; @@ -119,6 +121,7 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, for (int i = 0; i <= 7; i++) log->Printf("PT_%cETDBREGS: dr[%d]=0x%lx", setget, i, r->dr[i]); } +#endif } return result; @@ -309,9 +312,14 @@ ReadRegOperation::Execute(ProcessMonitor *monitor) if ((rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)®s, 0)) < 0) { m_result = false; } else { - if (m_size == sizeof(uintptr_t)) - m_value = *(uintptr_t *)(((caddr_t)®s) + m_offset); - else + // 'struct reg' contains only 32- or 64-bit register values. Punt on + // others. Also, not all entries may be uintptr_t sized, such as 32-bit + // processes on powerpc64 (probably the same for i386 on amd64) + if (m_size == sizeof(uint32_t)) + m_value = *(uint32_t *)(((caddr_t)®s) + m_offset); + else if (m_size == sizeof(uint64_t)) + m_value = *(uint64_t *)(((caddr_t)®s) + m_offset); + else memcpy(&m_value, (((caddr_t)®s) + m_offset), m_size); m_result = true; } @@ -810,8 +818,6 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process, const lldb_private::ProcessLaunchInfo & /* launch_info */, lldb_private::Error &error) : m_process(static_cast<ProcessFreeBSD *>(process)), - m_operation_thread(LLDB_INVALID_HOST_THREAD), - m_monitor_thread(LLDB_INVALID_HOST_THREAD), m_pid(LLDB_INVALID_PROCESS_ID), m_terminal_fd(-1), m_operation(0) @@ -852,7 +858,7 @@ WAIT_AGAIN: // Finally, start monitoring the child process for change in state. m_monitor_thread = Host::StartMonitoringChildProcess( ProcessMonitor::MonitorCallback, this, GetPID(), true); - if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread)) + if (!m_monitor_thread.IsJoinable()) { error.SetErrorToGenericError(); error.SetErrorString("Process launch failed."); @@ -864,8 +870,6 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process, lldb::pid_t pid, lldb_private::Error &error) : m_process(static_cast<ProcessFreeBSD *>(process)), - m_operation_thread(LLDB_INVALID_HOST_THREAD), - m_monitor_thread(LLDB_INVALID_HOST_THREAD), m_pid(pid), m_terminal_fd(-1), m_operation(0) @@ -904,7 +908,7 @@ WAIT_AGAIN: // Finally, start monitoring the child process for change in state. m_monitor_thread = Host::StartMonitoringChildProcess( ProcessMonitor::MonitorCallback, this, GetPID(), true); - if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread)) + if (!m_monitor_thread.IsJoinable()) { error.SetErrorToGenericError(); error.SetErrorString("Process attach failed."); @@ -924,11 +928,10 @@ ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Error &error) { static const char *g_thread_name = "lldb.process.freebsd.operation"; - if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread)) + if (m_operation_thread.IsJoinable()) return; - m_operation_thread = - Host::ThreadCreate(g_thread_name, LaunchOpThread, args, &error); + m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, LaunchOpThread, args, &error); } void * @@ -1101,11 +1104,10 @@ ProcessMonitor::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error { static const char *g_thread_name = "lldb.process.freebsd.operation"; - if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread)) + if (m_operation_thread.IsJoinable()) return; - m_operation_thread = - Host::ThreadCreate(g_thread_name, AttachOpThread, args, &error); + m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, AttachOpThread, args, &error); } void * @@ -1113,14 +1115,13 @@ ProcessMonitor::AttachOpThread(void *arg) { AttachArgs *args = static_cast<AttachArgs*>(arg); - if (!Attach(args)) - return NULL; + Attach(args); ServeOperation(args); return NULL; } -bool +void ProcessMonitor::Attach(AttachArgs *args) { lldb::pid_t pid = args->m_pid; @@ -1132,27 +1133,24 @@ ProcessMonitor::Attach(AttachArgs *args) { args->m_error.SetErrorToGenericError(); args->m_error.SetErrorString("Attaching to process 1 is not allowed."); - goto FINISH; + return; } // Attach to the requested process. if (PTRACE(PT_ATTACH, pid, NULL, 0) < 0) { args->m_error.SetErrorToErrno(); - goto FINISH; + return; } int status; if ((status = waitpid(pid, NULL, 0)) < 0) { args->m_error.SetErrorToErrno(); - goto FINISH; + return; } process.SendMessage(ProcessMessage::Attach(pid)); - -FINISH: - return args->m_error.Success(); } size_t @@ -1714,13 +1712,11 @@ ProcessMonitor::DupDescriptor(const char *path, int fd, int flags) void ProcessMonitor::StopMonitoringChildProcess() { - lldb::thread_result_t thread_result; - - if (IS_VALID_LLDB_HOST_THREAD(m_monitor_thread)) + if (m_monitor_thread.IsJoinable()) { - Host::ThreadCancel(m_monitor_thread, NULL); - Host::ThreadJoin(m_monitor_thread, &thread_result, NULL); - m_monitor_thread = LLDB_INVALID_HOST_THREAD; + m_monitor_thread.Cancel(); + m_monitor_thread.Join(nullptr); + m_monitor_thread.Reset(); } } @@ -1764,12 +1760,10 @@ ProcessMonitor::WaitForInitialTIDStop(lldb::tid_t tid) void ProcessMonitor::StopOpThread() { - lldb::thread_result_t result; - - if (!IS_VALID_LLDB_HOST_THREAD(m_operation_thread)) + if (!m_operation_thread.IsJoinable()) return; - Host::ThreadCancel(m_operation_thread, NULL); - Host::ThreadJoin(m_operation_thread, &result, NULL); - m_operation_thread = LLDB_INVALID_HOST_THREAD; + m_operation_thread.Cancel(); + m_operation_thread.Join(nullptr); + m_operation_thread.Reset(); } diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 314743b007541..935fd85ed37a6 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -17,6 +17,7 @@ // C++ Includes // Other libraries and framework includes #include "lldb/lldb-types.h" +#include "lldb/Host/HostThread.h" #include "lldb/Host/Mutex.h" namespace lldb_private @@ -212,8 +213,8 @@ public: private: ProcessFreeBSD *m_process; - lldb::thread_t m_operation_thread; - lldb::thread_t m_monitor_thread; + lldb_private::HostThread m_operation_thread; + lldb_private::HostThread m_monitor_thread; lldb::pid_t m_pid; int m_terminal_fd; @@ -289,7 +290,7 @@ private: static void * AttachOpThread(void *args); - static bool + static void Attach(AttachArgs *args); static void diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/POSIX/POSIXThread.cpp index d48f8f9dd307d..1057585e1b2a2 100644 --- a/source/Plugins/Process/POSIX/POSIXThread.cpp +++ b/source/Plugins/Process/POSIX/POSIXThread.cpp @@ -20,27 +20,30 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/State.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostNativeThread.h" #include "lldb/Host/HostInfo.h" #include "lldb/Target/Process.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadSpec.h" +#include "llvm/ADT/SmallString.h" #include "POSIXStopInfo.h" #include "POSIXThread.h" #include "ProcessPOSIX.h" #include "ProcessPOSIXLog.h" -#include "ProcessMonitor.h" +#include "Plugins/Process/Linux/ProcessMonitor.h" #include "RegisterContextPOSIXProcessMonitor_arm64.h" #include "RegisterContextPOSIXProcessMonitor_mips64.h" +#include "RegisterContextPOSIXProcessMonitor_powerpc.h" #include "RegisterContextPOSIXProcessMonitor_x86.h" -#include "RegisterContextLinux_arm64.h" -#include "RegisterContextLinux_i386.h" -#include "RegisterContextLinux_x86_64.h" -#include "RegisterContextFreeBSD_i386.h" -#include "RegisterContextFreeBSD_mips64.h" -#include "RegisterContextFreeBSD_x86_64.h" - -#include "UnwindLLDB.h" +#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" +#include "Plugins/Process/Utility/RegisterContextLinux_i386.h" +#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" +#include "Plugins/Process/Utility/UnwindLLDB.h" using namespace lldb; using namespace lldb_private; @@ -140,7 +143,9 @@ POSIXThread::GetName () { if (!m_thread_name_valid) { - SetName(Host::GetThreadName(GetProcess()->GetID(), GetID()).c_str()); + llvm::SmallString<32> thread_name; + HostNativeThread::GetName(GetID(), thread_name); + m_thread_name = thread_name.c_str(); m_thread_name_valid = true; } @@ -164,6 +169,14 @@ POSIXThread::GetRegisterContext() case llvm::Triple::FreeBSD: switch (target_arch.GetMachine()) { + case llvm::Triple::ppc: +#ifndef __powerpc64__ + reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch); + break; +#endif + case llvm::Triple::ppc64: + reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch); + break; case llvm::Triple::mips64: reg_interface = new RegisterContextFreeBSD_mips64(target_arch); break; @@ -226,6 +239,14 @@ POSIXThread::GetRegisterContext() m_reg_context_sp.reset(reg_ctx); break; } + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + { + RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx = new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } case llvm::Triple::x86: case llvm::Triple::x86_64: { @@ -621,6 +642,8 @@ POSIXThread::GetRegisterIndexFromOffset(unsigned offset) case llvm::Triple::aarch64: case llvm::Triple::mips64: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: case llvm::Triple::x86: case llvm::Triple::x86_64: { @@ -652,6 +675,8 @@ POSIXThread::GetRegisterName(unsigned reg) case llvm::Triple::aarch64: case llvm::Triple::mips64: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: case llvm::Triple::x86: case llvm::Triple::x86_64: name = GetRegisterContext()->GetRegisterName(reg); diff --git a/source/Plugins/Process/POSIX/POSIXThread.h b/source/Plugins/Process/POSIX/POSIXThread.h index 51d6645f209d8..56dcccbfb0f98 100644 --- a/source/Plugins/Process/POSIX/POSIXThread.h +++ b/source/Plugins/Process/POSIX/POSIXThread.h @@ -17,7 +17,7 @@ // Other libraries and framework includes #include "lldb/Target/Thread.h" -#include "RegisterContextPOSIX.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX.h" class ProcessMessage; class ProcessMonitor; diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp index f340631c7d076..0e5ab5a8d8b1e 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -16,6 +16,7 @@ // Other libraries and framework includes #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" #include "lldb/Host/FileSpec.h" @@ -28,7 +29,7 @@ #include "ProcessPOSIX.h" #include "ProcessPOSIXLog.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" -#include "ProcessMonitor.h" +#include "Plugins/Process/Linux/ProcessMonitor.h" #include "POSIXThread.h" using namespace lldb; @@ -140,8 +141,8 @@ ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid) // Resolve the executable module ModuleSP exe_module_sp; FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); - error = platform_sp->ResolveExecutable(process_info.GetExecutableFile(), - m_target.GetArchitecture(), + ModuleSpec exe_module_spec(process_info.GetExecutableFile(), m_target.GetArchitecture()); + error = platform_sp->ResolveExecutable(exe_module_spec, exe_module_sp, executable_search_paths.GetSize() ? &executable_search_paths : NULL); if (!error.Success()) @@ -176,9 +177,9 @@ ProcessPOSIX::WillLaunch(Module* module) } const char * -ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const char *default_path) +ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const char *default_path, + const char *dbg_pts_path) { - const char *pts_name = "/dev/pts/"; const char *path = NULL; if (file_action) @@ -190,11 +191,11 @@ ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const cha // (/dev/pts). If so, convert to using a different default path // instead to redirect I/O to the debugger console. This should // also handle user overrides to /dev/null or a different file. - if (!path || ::strncmp(path, pts_name, ::strlen(pts_name)) == 0) + if (!path || (dbg_pts_path && + ::strncmp(path, dbg_pts_path, ::strlen(dbg_pts_path)) == 0)) path = default_path; } } - return path; } @@ -224,14 +225,16 @@ ProcessPOSIX::DoLaunch (Module *module, const char *stdout_path = NULL; const char *stderr_path = NULL; + const char * dbg_pts_path = launch_info.GetPTY().GetSlaveName(NULL,0); + file_action = launch_info.GetFileActionForFD (STDIN_FILENO); - stdin_path = GetFilePath(file_action, stdin_path); + stdin_path = GetFilePath(file_action, stdin_path, dbg_pts_path); file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); - stdout_path = GetFilePath(file_action, stdout_path); + stdout_path = GetFilePath(file_action, stdout_path, dbg_pts_path); file_action = launch_info.GetFileActionForFD (STDERR_FILENO); - stderr_path = GetFilePath(file_action, stderr_path); + stderr_path = GetFilePath(file_action, stderr_path, dbg_pts_path); m_monitor = new ProcessMonitor (this, module, @@ -338,6 +341,11 @@ ProcessPOSIX::DoDestroy() { assert(m_monitor); m_exit_now = true; + if (GetID() == LLDB_INVALID_PROCESS_ID) + { + error.SetErrorString("invalid process id"); + return error; + } if (!m_monitor->Kill()) { error.SetErrorToErrno(); @@ -363,11 +371,11 @@ ProcessPOSIX::DoDidExec() ProcessInstanceInfo process_info; platform_sp->GetProcessInfo(GetID(), process_info); ModuleSP exe_module_sp; + ModuleSpec exe_module_spec(process_info.GetExecutableFile(), target->GetArchitecture()); FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); - Error error = platform_sp->ResolveExecutable(process_info.GetExecutableFile(), - target->GetArchitecture(), - exe_module_sp, - executable_search_paths.GetSize() ? &executable_search_paths : NULL); + Error error = platform_sp->ResolveExecutable(exe_module_spec, + exe_module_sp, + executable_search_paths.GetSize() ? &executable_search_paths : NULL); if (!error.Success()) return; target->SetExecutableModule(exe_module_sp, true); @@ -432,8 +440,7 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) // FIXME: I'm not sure we need to do this. if (message.GetTID() == GetID()) { - m_exit_status = message.GetExitStatus(); - SetExitStatus(m_exit_status, NULL); + SetExitStatus(message.GetExitStatus(), NULL); } else if (!IsAThreadRunning()) SetPrivateState(eStateStopped); diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h index 033accf17f296..f152356b3093a 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h @@ -42,104 +42,104 @@ public: // Process protocol. //------------------------------------------------------------------ virtual void - Finalize(); + Finalize() override; virtual bool - CanDebug(lldb_private::Target &target, bool plugin_specified_by_name); + CanDebug(lldb_private::Target &target, bool plugin_specified_by_name) override; virtual lldb_private::Error - WillLaunch(lldb_private::Module *module); + WillLaunch(lldb_private::Module *module) override; virtual lldb_private::Error - DoAttachToProcessWithID(lldb::pid_t pid); + DoAttachToProcessWithID(lldb::pid_t pid) override; virtual lldb_private::Error - DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info); + DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override; virtual lldb_private::Error DoLaunch (lldb_private::Module *exe_module, - lldb_private::ProcessLaunchInfo &launch_info); + lldb_private::ProcessLaunchInfo &launch_info) override; virtual void - DidLaunch(); + DidLaunch() override; virtual lldb_private::Error - DoResume(); + DoResume() override; virtual lldb_private::Error - DoHalt(bool &caused_stop); + DoHalt(bool &caused_stop) override; virtual lldb_private::Error - DoDetach(bool keep_stopped) = 0; + DoDetach(bool keep_stopped) override = 0; virtual lldb_private::Error - DoSignal(int signal); + DoSignal(int signal) override; virtual lldb_private::Error - DoDestroy(); + DoDestroy() override; virtual void - DoDidExec(); + DoDidExec() override; virtual void - RefreshStateAfterStop(); + RefreshStateAfterStop() override; virtual bool - IsAlive(); + IsAlive() override; virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - lldb_private::Error &error); + lldb_private::Error &error) override; virtual size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, - lldb_private::Error &error); + lldb_private::Error &error) override; virtual lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions, - lldb_private::Error &error); + lldb_private::Error &error) override; virtual lldb_private::Error - DoDeallocateMemory(lldb::addr_t ptr); + DoDeallocateMemory(lldb::addr_t ptr) override; virtual size_t GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site); virtual lldb_private::Error - EnableBreakpointSite(lldb_private::BreakpointSite *bp_site); + EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; virtual lldb_private::Error - DisableBreakpointSite(lldb_private::BreakpointSite *bp_site); + DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; virtual lldb_private::Error - EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true); + EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override; virtual lldb_private::Error - DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true); + DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override; virtual lldb_private::Error - GetWatchpointSupportInfo(uint32_t &num); + GetWatchpointSupportInfo(uint32_t &num) override; virtual lldb_private::Error - GetWatchpointSupportInfo(uint32_t &num, bool &after); + GetWatchpointSupportInfo(uint32_t &num, bool &after) override; virtual uint32_t UpdateThreadListIfNeeded(); virtual bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) = 0; + lldb_private::ThreadList &new_thread_list) override = 0; virtual lldb::ByteOrder GetByteOrder() const; virtual lldb::addr_t - GetImageInfoAddress(); + GetImageInfoAddress() override; virtual size_t - PutSTDIN(const char *buf, size_t len, lldb_private::Error &error); + PutSTDIN(const char *buf, size_t len, lldb_private::Error &error) override; const lldb::DataBufferSP GetAuxvData () override; @@ -154,7 +154,8 @@ public: ProcessMonitor & GetMonitor() { assert(m_monitor); return *m_monitor; } - const char *GetFilePath(const lldb_private::FileAction *file_action, const char *default_path); + const char *GetFilePath(const lldb_private::FileAction *file_action, const char *default_path, + const char *dbg_pts_path); /// Stops all threads in the process. /// The \p stop_tid parameter indicates the thread which initiated the stop. diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp index 9109cdb000aed..ec34d9e28161a 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp @@ -10,10 +10,10 @@ #include "lldb/Target/Thread.h" #include "lldb/Core/RegisterValue.h" -#include "RegisterContextPOSIX_arm64.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" #include "ProcessPOSIX.h" #include "RegisterContextPOSIXProcessMonitor_arm64.h" -#include "ProcessMonitor.h" +#include "Plugins/Process/Linux/ProcessMonitor.h" #define REG_CONTEXT_SIZE (GetGPRSize()) diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp index 9bfe236de1394..6717d20da056f 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp @@ -10,10 +10,10 @@ #include "lldb/Target/Thread.h" #include "lldb/Core/RegisterValue.h" -#include "RegisterContextPOSIX_mips64.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" #include "ProcessPOSIX.h" #include "RegisterContextPOSIXProcessMonitor_mips64.h" -#include "ProcessMonitor.h" +#include "Plugins/Process/Linux/ProcessMonitor.h" using namespace lldb_private; using namespace lldb; diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp new file mode 100644 index 0000000000000..b542db4779db4 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp @@ -0,0 +1,321 @@ +//===-- RegisterContextPOSIXProcessMonitor_powerpc.h ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "lldb/Target/Thread.h" +#include "lldb/Core/RegisterValue.h" + +#include "RegisterContextPOSIX_powerpc.h" +#include "ProcessPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_powerpc.h" +#include "ProcessMonitor.h" + +using namespace lldb_private; +using namespace lldb; + +#define REG_CONTEXT_SIZE (GetGPRSize()) + +RegisterContextPOSIXProcessMonitor_powerpc::RegisterContextPOSIXProcessMonitor_powerpc(Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_powerpc(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_powerpc::GetMonitor() +{ + ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadFPR() +{ + // XXX not yet implemented + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteFPR() +{ + // XXX not yet implemented + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const unsigned reg, + RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const unsigned reg, + const RegisterValue &value) +{ + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + } + + ProcessMonitor &monitor = GetMonitor(); + // Account for the fact that 32-bit targets on powerpc64 really use 64-bit + // registers in ptrace, but expose here 32-bit registers with a higher + // offset. + uint64_t offset = GetRegisterOffset(reg_to_write); + offset &= ~(sizeof(uintptr_t) - 1); + return monitor.WriteRegisterValue(m_thread.GetID(), + offset, + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg)) + { + if (!ReadFPR()) + return false; + } + else + { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); + + if (is_subreg) + { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; + } + + bool success = ReadRegister(full_reg, value); + + if (success) + { + // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. + if (is_subreg && (reg_info->byte_offset & 0x1)) + value.SetUInt64(value.GetAsUInt64() >> 8); + + // If our return byte size was greater than the return value reg size, then + // use the type specified by reg_info rather than the uint64_t default + if (value.GetByteSize() > reg_info->byte_size) + value.SetType(reg_info); + } + return success; + } + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsGPR(reg)) + return WriteRegister(reg, value); + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadAllRegisterValues(DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR () && ReadFPR ()) + { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) + { + ::memcpy (dst, &m_gpr_powerpc, GetGPRSize()); + dst += GetGPRSize(); + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteAllRegisterValues(const DataBufferSP &data_sp) +{ + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + uint8_t *src = data_sp->GetBytes(); + if (src) + { + ::memcpy (&m_gpr_powerpc, src, GetGPRSize()); + + if (WriteGPR()) + { + src += GetGPRSize(); + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpoint(addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, + read, write, + hw_index); + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::UpdateAfterBreakpoint() +{ + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_powerpc::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < k_num_registers_powerpc; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_powerpc && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointHit(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ClearWatchpointHits() +{ + return false; +} + +addr_t +RegisterContextPOSIXProcessMonitor_powerpc::GetWatchpointAddress(uint32_t hw_index) +{ + return LLDB_INVALID_ADDRESS; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointVacant(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_powerpc::NumSupportedHardwareWatchpoints() +{ + return 0; +} + diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h new file mode 100644 index 0000000000000..92a3312855152 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_powerpc.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_RegisterContextPOSIXProcessMonitor_powerpc_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" + +class RegisterContextPOSIXProcessMonitor_powerpc: + public RegisterContextPOSIX_powerpc, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_powerpc(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + + // lldb_private::RegisterContext + bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + + bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + + bool + HardwareSingleStep(bool enable); + + // POSIXBreakpointProtocol + bool + UpdateAfterBreakpoint(); + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + bool + IsWatchpointHit(uint32_t hw_index); + + bool + ClearWatchpointHits(); + + lldb::addr_t + GetWatchpointAddress(uint32_t hw_index); + + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + + uint32_t + NumSupportedHardwareWatchpoints(); + +private: + ProcessMonitor & + GetMonitor(); +}; + +#endif diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp index e534f3b4f9d0a..1956e4584fa96 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -10,9 +10,13 @@ #include "lldb/Target/Thread.h" #include "lldb/Core/RegisterValue.h" -#include "ProcessPOSIX.h" +#include "Plugins/Process/POSIX/ProcessPOSIX.h" #include "RegisterContextPOSIXProcessMonitor_x86.h" -#include "ProcessMonitor.h" +#if defined(__FreeBSD__) +#include "Plugins/Process/FreeBSD/ProcessMonitor.h" +#else +#include "Plugins/Process/Linux/ProcessMonitor.h" +#endif using namespace lldb_private; using namespace lldb; @@ -48,6 +52,7 @@ size_and_rw_bits(size_t size, bool read, bool write) return (0x2 << 2) | rw; default: assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); + return 0; // Unreachable. Just to silence compiler. } } diff --git a/source/Plugins/Process/Utility/ARMDefines.h b/source/Plugins/Process/Utility/ARMDefines.h index 2c8ad3586af11..cfb33beb447a7 100644 --- a/source/Plugins/Process/Utility/ARMDefines.h +++ b/source/Plugins/Process/Utility/ARMDefines.h @@ -45,7 +45,8 @@ typedef enum #define COND_AL 0xE // Always (unconditional) Always (unconditional) Any #define COND_UNCOND 0xF -static inline const char *ARMCondCodeToString(uint32_t CC) +static inline const char * +ARMCondCodeToString(uint32_t CC) { switch (CC) { default: assert(0 && "Unknown condition code"); @@ -67,6 +68,37 @@ static inline const char *ARMCondCodeToString(uint32_t CC) } } +static inline bool +ARMConditionPassed(const uint32_t condition, const uint32_t cpsr) +{ + const uint32_t cpsr_n = (cpsr >> 31) & 1u; // Negative condition code flag + const uint32_t cpsr_z = (cpsr >> 30) & 1u; // Zero condition code flag + const uint32_t cpsr_c = (cpsr >> 29) & 1u; // Carry condition code flag + const uint32_t cpsr_v = (cpsr >> 28) & 1u; // Overflow condition code flag + + switch (condition) { + case COND_EQ: return (cpsr_z == 1); + case COND_NE: return (cpsr_z == 0); + case COND_CS: return (cpsr_c == 1); + case COND_CC: return (cpsr_c == 0); + case COND_MI: return (cpsr_n == 1); + case COND_PL: return (cpsr_n == 0); + case COND_VS: return (cpsr_v == 1); + case COND_VC: return (cpsr_v == 0); + case COND_HI: return ((cpsr_c == 1) && (cpsr_z == 0)); + case COND_LS: return ((cpsr_c == 0) || (cpsr_z == 1)); + case COND_GE: return (cpsr_n == cpsr_v); + case COND_LT: return (cpsr_n != cpsr_v); + case COND_GT: return ((cpsr_z == 0) && (cpsr_n == cpsr_v)); + case COND_LE: return ((cpsr_z == 1) || (cpsr_n != cpsr_v)); + case COND_AL: + case COND_UNCOND: + default: + return true; + } + return false; +} + // Bit positions for CPSR #define CPSR_T_POS 5 #define CPSR_F_POS 6 diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp index 3507ccf92065d..1088924bfeac9 100644 --- a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -81,6 +81,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict else { Clear(); + printf("error: register sets must have valid names\n"); return 0; } } @@ -121,6 +122,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict if (reg_info.name == NULL) { Clear(); + printf("error: registers must have valid names\n"); + reg_info_dict.Dump(); return 0; } @@ -290,6 +293,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict if (!success) { Clear(); + reg_info_dict.Dump(); return 0; } } @@ -297,6 +301,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict if (bitsize == 0) { Clear(); + printf("error: invalid or missing 'bitsize' key/value pair in register dictionary\n"); + reg_info_dict.Dump(); return 0; } @@ -308,6 +314,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict if (Args::StringToFormat(format_cstr, reg_info.format, NULL).Fail()) { Clear(); + printf("error: invalid 'format' value in register dictionary\n"); + reg_info_dict.Dump(); return 0; } } @@ -326,6 +334,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict if (static_cast<size_t>(set) >= m_sets.size()) { Clear(); + printf("error: invalid 'set' value in register dictionary, valid values are 0 - %i\n", (int)set); + reg_info_dict.Dump(); return 0; } @@ -409,6 +419,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict else { Clear(); + printf("error: items in the 'registers' array must be dictionaries\n"); + regs.Dump(); return 0; } } diff --git a/source/Plugins/Process/Utility/HistoryThread.cpp b/source/Plugins/Process/Utility/HistoryThread.cpp index 590bb0162c8a9..206b8290c5fd1 100644 --- a/source/Plugins/Process/Utility/HistoryThread.cpp +++ b/source/Plugins/Process/Utility/HistoryThread.cpp @@ -39,7 +39,7 @@ HistoryThread::HistoryThread (lldb_private::Process &process, m_originating_unique_thread_id (tid), m_queue_id (LLDB_INVALID_QUEUE_ID) { - m_unwinder_ap.reset (new HistoryUnwind (*this, pcs, stop_id, stop_id_is_valid)); + m_unwinder_ap.reset (new HistoryUnwind (*this, pcs, stop_id_is_valid)); Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) log->Printf ("%p HistoryThread::HistoryThread", diff --git a/source/Plugins/Process/Utility/HistoryThread.h b/source/Plugins/Process/Utility/HistoryThread.h index f9a431d8340b9..51173c626d71d 100644 --- a/source/Plugins/Process/Utility/HistoryThread.h +++ b/source/Plugins/Process/Utility/HistoryThread.h @@ -101,6 +101,18 @@ public: { m_thread_name = name; } + + virtual const char * + GetName () + { + return m_thread_name.c_str(); + } + + virtual void + SetName(const char *name) + { + m_thread_name = name; + } protected: virtual lldb::StackFrameListSP diff --git a/source/Plugins/Process/Utility/HistoryUnwind.cpp b/source/Plugins/Process/Utility/HistoryUnwind.cpp index f809ebedcfc8c..14afcbee0b49c 100644 --- a/source/Plugins/Process/Utility/HistoryUnwind.cpp +++ b/source/Plugins/Process/Utility/HistoryUnwind.cpp @@ -24,11 +24,9 @@ using namespace lldb_private; HistoryUnwind::HistoryUnwind (Thread &thread, std::vector<lldb::addr_t> pcs, - uint32_t stop_id, bool stop_id_is_valid) : Unwind (thread), m_pcs (pcs), - m_stop_id (stop_id), m_stop_id_is_valid (stop_id_is_valid) { } diff --git a/source/Plugins/Process/Utility/HistoryUnwind.h b/source/Plugins/Process/Utility/HistoryUnwind.h index 0661b80286087..733f93e1ff87e 100644 --- a/source/Plugins/Process/Utility/HistoryUnwind.h +++ b/source/Plugins/Process/Utility/HistoryUnwind.h @@ -21,7 +21,7 @@ namespace lldb_private { class HistoryUnwind : public lldb_private::Unwind { public: - HistoryUnwind (Thread &thread, std::vector<lldb::addr_t> pcs, uint32_t stop_id, bool stop_id_is_valid); + HistoryUnwind (Thread &thread, std::vector<lldb::addr_t> pcs, bool stop_id_is_valid); virtual ~HistoryUnwind (); @@ -42,7 +42,6 @@ protected: private: std::vector<lldb::addr_t> m_pcs; - uint32_t m_stop_id; bool m_stop_id_is_valid; }; diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 4a94457466bef..7db83ae5467fd 100644 --- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -98,13 +98,11 @@ lldb_private::InferiorCallMmap (Process *process, ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); lldb::addr_t args[] = { addr, length, prot_arg, flags_arg, fd, offset }; - ThreadPlanCallFunction *call_function_thread_plan - = new ThreadPlanCallFunction (*thread, - mmap_range.GetBaseAddress(), - clang_void_ptr_type, - args, - options); - lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); + lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread, + mmap_range.GetBaseAddress(), + clang_void_ptr_type, + args, + options)); if (call_plan_sp) { StreamFile error_strm; @@ -241,13 +239,11 @@ lldb_private::InferiorCall (Process *process, ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - ThreadPlanCallFunction *call_function_thread_plan - = new ThreadPlanCallFunction (*thread, - *address, - clang_void_ptr_type, - llvm::ArrayRef<addr_t>(), - options); - lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); + lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread, + *address, + clang_void_ptr_type, + llvm::ArrayRef<addr_t>(), + options)); if (call_plan_sp) { StreamString error_strm; diff --git a/source/Plugins/Process/Utility/InstructionUtils.h b/source/Plugins/Process/Utility/InstructionUtils.h index 813990095c49d..6226fbc04b083 100644 --- a/source/Plugins/Process/Utility/InstructionUtils.h +++ b/source/Plugins/Process/Utility/InstructionUtils.h @@ -20,7 +20,7 @@ static inline uint64_t Bits64 (const uint64_t bits, const uint32_t msbit, const uint32_t lsbit) { assert(msbit < 64 && lsbit <= msbit); - return (bits >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1); + return (bits >> lsbit) & ((1ull << (msbit - lsbit + 1)) - 1); } // Return the bit field(s) from the most significant bit (msbit) to the diff --git a/source/Plugins/Process/Utility/LinuxSignals.cpp b/source/Plugins/Process/Utility/LinuxSignals.cpp index fb49df681caef..11a3eef235295 100644 --- a/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -53,7 +53,7 @@ LinuxSignals::Reset() AddSignal (24, "SIGXCPU", "XCPU", false, true , true , "CPU resource exceeded"); AddSignal (25, "SIGXFSZ", "XFSZ", false, true , true , "file size limit exceeded"); AddSignal (26, "SIGVTALRM", "VTALRM", false, true , true , "virtual time alarm"); - AddSignal (27, "SIGPROF", "PROF", false, true , true , "profiling time alarm"); + AddSignal (27, "SIGPROF", "PROF", false, false, false, "profiling time alarm"); AddSignal (28, "SIGWINCH", "WINCH", false, true , true , "window size changes"); AddSignal (29, "SIGPOLL", "POLL", false, true , true , "pollable event"); AddSignal (29, "SIGIO", "IO", false, true , true , "input/output ready"); diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp new file mode 100644 index 0000000000000..5170e6d2accb3 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp @@ -0,0 +1,230 @@ +//===-- RegisterContextFreeBSD_powerpc.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include <vector> +#include "RegisterContextPOSIX_powerpc.h" +#include "RegisterContextFreeBSD_powerpc.h" + +using namespace lldb_private; +using namespace lldb; + +// http://svnweb.freebsd.org/base/head/sys/powerpc/include/reg.h +typedef struct _GPR64 +{ + uint64_t r0; + uint64_t r1; + uint64_t r2; + uint64_t r3; + uint64_t r4; + uint64_t r5; + uint64_t r6; + uint64_t r7; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t r16; + uint64_t r17; + uint64_t r18; + uint64_t r19; + uint64_t r20; + uint64_t r21; + uint64_t r22; + uint64_t r23; + uint64_t r24; + uint64_t r25; + uint64_t r26; + uint64_t r27; + uint64_t r28; + uint64_t r29; + uint64_t r30; + uint64_t r31; + uint64_t lr; + uint64_t cr; + uint64_t xer; + uint64_t ctr; + uint64_t pc; +} GPR64; + +typedef struct _GPR32 +{ + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t r12; + uint32_t r13; + uint32_t r14; + uint32_t r15; + uint32_t r16; + uint32_t r17; + uint32_t r18; + uint32_t r19; + uint32_t r20; + uint32_t r21; + uint32_t r22; + uint32_t r23; + uint32_t r24; + uint32_t r25; + uint32_t r26; + uint32_t r27; + uint32_t r28; + uint32_t r29; + uint32_t r30; + uint32_t r31; + uint32_t lr; + uint32_t cr; + uint32_t xer; + uint32_t ctr; + uint32_t pc; +} GPR32; + +typedef struct _FPR +{ + uint64_t f0; + uint64_t f1; + uint64_t f2; + uint64_t f3; + uint64_t f4; + uint64_t f5; + uint64_t f6; + uint64_t f7; + uint64_t f8; + uint64_t f9; + uint64_t f10; + uint64_t f11; + uint64_t f12; + uint64_t f13; + uint64_t f14; + uint64_t f15; + uint64_t f16; + uint64_t f17; + uint64_t f18; + uint64_t f19; + uint64_t f20; + uint64_t f21; + uint64_t f22; + uint64_t f23; + uint64_t f24; + uint64_t f25; + uint64_t f26; + uint64_t f27; + uint64_t f28; + uint64_t f29; + uint64_t f30; + uint64_t f31; + uint64_t fpscr; +} FPR; + +//--------------------------------------------------------------------------- +// Include RegisterInfos_powerpc to declare our g_register_infos_powerpc structure. +//--------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_POWERPC_STRUCT +#include "RegisterInfos_powerpc.h" +#undef DECLARE_REGISTER_INFOS_POWERPC_STRUCT + +RegisterContextFreeBSD_powerpc::RegisterContextFreeBSD_powerpc(const ArchSpec &target_arch) : + RegisterInfoInterface(target_arch) +{ +} + +RegisterContextFreeBSD_powerpc::~RegisterContextFreeBSD_powerpc() +{ +} + +size_t +RegisterContextFreeBSD_powerpc::GetGPRSize() const +{ + // This is an 'abstract' base, so no GPR struct. + return 0; +} + +const RegisterInfo * +RegisterContextFreeBSD_powerpc::GetRegisterInfo() const +{ + //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc); + llvm_unreachable("Abstract class!"); + return NULL; +} + +uint32_t +RegisterContextFreeBSD_powerpc::GetRegisterCount () const +{ + return 0; +} + +RegisterContextFreeBSD_powerpc32::RegisterContextFreeBSD_powerpc32(const ArchSpec &target_arch) : + RegisterContextFreeBSD_powerpc(target_arch) +{ +} + +RegisterContextFreeBSD_powerpc32::~RegisterContextFreeBSD_powerpc32() +{ +} + +size_t +RegisterContextFreeBSD_powerpc32::GetGPRSize() const +{ + return sizeof(GPR32); +} + +const RegisterInfo * +RegisterContextFreeBSD_powerpc32::GetRegisterInfo() const +{ + //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc); + return g_register_infos_powerpc32; +} + +uint32_t +RegisterContextFreeBSD_powerpc32::GetRegisterCount () const +{ + return static_cast<uint32_t> (sizeof (g_register_infos_powerpc32) / sizeof (g_register_infos_powerpc32 [0])); +} + +RegisterContextFreeBSD_powerpc64::RegisterContextFreeBSD_powerpc64(const ArchSpec &target_arch) : + RegisterContextFreeBSD_powerpc(target_arch) +{ +} + +RegisterContextFreeBSD_powerpc64::~RegisterContextFreeBSD_powerpc64() +{ +} + +size_t +RegisterContextFreeBSD_powerpc64::GetGPRSize() const +{ + return sizeof(GPR64); +} + +const RegisterInfo * +RegisterContextFreeBSD_powerpc64::GetRegisterInfo() const +{ + //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc); + if (m_target_arch.GetMachine() == llvm::Triple::ppc) + return g_register_infos_powerpc64_32; + return g_register_infos_powerpc64; +} + +uint32_t +RegisterContextFreeBSD_powerpc64::GetRegisterCount () const +{ + return static_cast<uint32_t> (sizeof (g_register_infos_powerpc64) / sizeof (g_register_infos_powerpc64 [0])); +} diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h new file mode 100644 index 0000000000000..b907fe99b5e05 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h @@ -0,0 +1,66 @@ +//===-- RegisterContextFreeBSD_powerpc.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_RegisterContextFreeBSD_powerpc_H_ +#define liblldb_RegisterContextFreeBSD_powerpc_H_ + +#include "RegisterContextPOSIX.h" + +class RegisterContextFreeBSD_powerpc: + public lldb_private::RegisterInfoInterface +{ +public: + RegisterContextFreeBSD_powerpc(const lldb_private::ArchSpec &target_arch); + virtual ~RegisterContextFreeBSD_powerpc(); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount() const override; +}; + +class RegisterContextFreeBSD_powerpc32: + public RegisterContextFreeBSD_powerpc +{ +public: + RegisterContextFreeBSD_powerpc32(const lldb_private::ArchSpec &target_arch); + virtual ~RegisterContextFreeBSD_powerpc32(); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount() const override; +}; + +class RegisterContextFreeBSD_powerpc64: + public RegisterContextFreeBSD_powerpc +{ +public: + RegisterContextFreeBSD_powerpc64(const lldb_private::ArchSpec &target_arch); + virtual ~RegisterContextFreeBSD_powerpc64(); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount() const override; +}; + +#endif diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index b58e6bb607ed9..f47d687702ecf 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -172,6 +172,21 @@ RegisterContextLLDB::InitializeZerothFrame() m_sym_ctx_valid = true; } + if (m_sym_ctx.symbol) + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'", + current_pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); + } + else if (m_sym_ctx.function) + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'", + current_pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.function->GetName().AsCString()); + } + else + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", no symbol/function name is known.", current_pc); + } + AddressRange addr_range; m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range); @@ -217,7 +232,6 @@ RegisterContextLLDB::InitializeZerothFrame() m_full_unwind_plan_sp = GetFullUnwindPlanForFrame (); UnwindPlan::RowSP active_row; - int cfa_offset = 0; lldb::RegisterKind row_register_kind = eRegisterKindGeneric; if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc)) { @@ -239,18 +253,13 @@ RegisterContextLLDB::InitializeZerothFrame() } - addr_t cfa_regval = LLDB_INVALID_ADDRESS; - if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) + if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa)) { UnwindLogMsg ("could not read CFA register for this frame."); m_frame_type = eNotAValidFrame; return; } - cfa_offset = active_row->GetCFAOffset (); - m_cfa = cfa_regval + cfa_offset; - - UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset); UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan", (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa, @@ -294,20 +303,27 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (log) { - UnwindLogMsg ("pc = 0x%16.16" PRIx64, pc); + UnwindLogMsg ("pc = 0x%" PRIx64, pc); addr_t reg_val; if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val)) - UnwindLogMsg ("fp = 0x%16.16" PRIx64, reg_val); + UnwindLogMsg ("fp = 0x%" PRIx64, reg_val); if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val)) - UnwindLogMsg ("sp = 0x%16.16" PRIx64, reg_val); + UnwindLogMsg ("sp = 0x%" PRIx64, reg_val); } - // A pc of 0x0 means it's the end of the stack crawl - if (pc == 0) + // A pc of 0x0 means it's the end of the stack crawl unless we're above a trap handler function + bool above_trap_handler = false; + if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsTrapHandlerFrame()) + above_trap_handler = true; + + if (pc == 0 || pc == 0x1) { - m_frame_type = eNotAValidFrame; - UnwindLogMsg ("this frame has a pc of 0x0"); - return; + if (above_trap_handler == false) + { + m_frame_type = eNotAValidFrame; + UnwindLogMsg ("this frame has a pc of 0x0"); + return; + } } ExecutionContext exe_ctx(m_thread.shared_from_this()); @@ -363,35 +379,31 @@ RegisterContextLLDB::InitializeNonZerothFrame() m_all_registers_available = false; m_current_offset = -1; m_current_offset_backed_up_one = -1; - addr_t cfa_regval = LLDB_INVALID_ADDRESS; RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0); if (row.get()) { - uint32_t cfa_regnum = row->GetCFARegister(); - int cfa_offset = row->GetCFAOffset(); - if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval)) + if (!ReadCFAValueForRow (row_register_kind, row, m_cfa)) { UnwindLogMsg ("failed to get cfa value"); if (m_frame_type != eSkipFrame) // don't override eSkipFrame { - m_frame_type = eNormalFrame; + m_frame_type = eNotAValidFrame; } return; } - m_cfa = cfa_regval + cfa_offset; // A couple of sanity checks.. - if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1) + if (m_cfa == LLDB_INVALID_ADDRESS || m_cfa == 0 || m_cfa == 1) { UnwindLogMsg ("could not find a valid cfa address"); m_frame_type = eNotAValidFrame; return; } - // cfa_regval should point into the stack memory; if we can query memory region permissions, + // m_cfa should point into the stack memory; if we can query memory region permissions, // see if the memory is allocated & readable. - if (process->GetLoadAddressPermissions(cfa_regval, permissions) + if (process->GetLoadAddressPermissions(m_cfa, permissions) && (permissions & ePermissionsReadable) == 0) { m_frame_type = eNotAValidFrame; @@ -406,6 +418,17 @@ RegisterContextLLDB::InitializeNonZerothFrame() return; } + if (CheckIfLoopingStack ()) + { + TryFallbackUnwindPlan(); + if (CheckIfLoopingStack ()) + { + UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping"); + m_frame_type = eNotAValidFrame; + return; + } + } + UnwindLogMsg ("initialized frame cfa is 0x%" PRIx64, (uint64_t) m_cfa); return; } @@ -431,6 +454,21 @@ RegisterContextLLDB::InitializeNonZerothFrame() m_sym_ctx_valid = true; } + if (m_sym_ctx.symbol) + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'", + pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); + } + else if (m_sym_ctx.function) + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'", + pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.function->GetName().AsCString()); + } + else + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", no symbol/function name is known.", pc); + } + AddressRange addr_range; if (!m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range)) { @@ -461,17 +499,22 @@ RegisterContextLLDB::InitializeNonZerothFrame() // to the ABI plugin and consult that. if (decr_pc_and_recompute_addr_range) { - Address temporary_pc(m_current_pc); - temporary_pc.SetOffset(m_current_pc.GetOffset() - 1); - m_sym_ctx.Clear(false); + UnwindLogMsg ("Backing up the pc value of 0x%" PRIx64 " by 1 and re-doing symbol lookup; old symbol was %s", + pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); + Address temporary_pc; + temporary_pc.SetLoadAddress (pc - 1, &process->GetTarget()); + m_sym_ctx.Clear (false); m_sym_ctx_valid = false; uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; - if (pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope) + ModuleSP temporary_module_sp = temporary_pc.GetModule(); + if (temporary_module_sp && + temporary_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope) { if (m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range)) m_sym_ctx_valid = true; } + UnwindLogMsg ("Symbol is now %s", m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); } // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function. @@ -479,13 +522,15 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (addr_range.GetBaseAddress().IsValid()) { m_start_pc = addr_range.GetBaseAddress(); - m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset(); + m_current_offset = pc - m_start_pc.GetLoadAddress (&process->GetTarget()); m_current_offset_backed_up_one = m_current_offset; if (decr_pc_and_recompute_addr_range && m_current_offset_backed_up_one > 0) { m_current_offset_backed_up_one--; if (m_sym_ctx_valid) - m_current_pc.SetOffset(m_current_pc.GetOffset() - 1); + { + m_current_pc.SetLoadAddress (pc - 1, &process->GetTarget()); + } } } else @@ -512,7 +557,6 @@ RegisterContextLLDB::InitializeNonZerothFrame() m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame (); UnwindPlan::RowSP active_row; - int cfa_offset = 0; RegisterKind row_register_kind = eRegisterKindGeneric; // Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get @@ -553,27 +597,33 @@ RegisterContextLLDB::InitializeNonZerothFrame() return; } - addr_t cfa_regval = LLDB_INVALID_ADDRESS; - if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) + if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa)) { UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister()); m_frame_type = eNotAValidFrame; return; } - cfa_offset = active_row->GetCFAOffset (); - m_cfa = cfa_regval + cfa_offset; + UnwindLogMsg ("m_cfa = 0x%" PRIx64, m_cfa); - UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset); - - // A couple of sanity checks.. - if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1) + if (CheckIfLoopingStack ()) { - UnwindLogMsg ("could not find a valid cfa address"); - m_frame_type = eNotAValidFrame; - return; + TryFallbackUnwindPlan(); + if (CheckIfLoopingStack ()) + { + UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping"); + m_frame_type = eNotAValidFrame; + return; + } } + UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64, + (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa); +} + +bool +RegisterContextLLDB::CheckIfLoopingStack () +{ // If we have a bad stack setup, we can get the same CFA value multiple times -- or even // more devious, we can actually oscillate between two CFA values. Detect that here and // break out to avoid a possible infinite loop in lldb trying to unwind the stack. @@ -581,29 +631,19 @@ RegisterContextLLDB::InitializeNonZerothFrame() addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS; if (GetNextFrame().get() && GetNextFrame()->GetCFA(next_frame_cfa)) { - bool repeating_frames = false; if (next_frame_cfa == m_cfa) { - repeating_frames = true; - } - else - { - if (GetNextFrame()->GetNextFrame() && GetNextFrame()->GetNextFrame()->GetCFA(next_next_frame_cfa) - && next_next_frame_cfa == m_cfa) - { - repeating_frames = true; - } + // We have a loop in the stack unwind + return true; } - if (repeating_frames && abi && abi->FunctionCallsChangeCFA()) + if (GetNextFrame()->GetNextFrame().get() && GetNextFrame()->GetNextFrame()->GetCFA(next_next_frame_cfa) + && next_next_frame_cfa == m_cfa) { - UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping"); - m_frame_type = eNotAValidFrame; - return; + // We have a loop in the stack unwind + return true; } } - - UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64, - (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa); + return false; } @@ -715,13 +755,17 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () uint32_t permissions; addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()); if (current_pc_addr == 0 - || (process->GetLoadAddressPermissions (current_pc_addr, permissions) + || (process && + process->GetLoadAddressPermissions (current_pc_addr, permissions) && (permissions & ePermissionsExecutable) == 0)) { - unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); - abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp); - m_frame_type = eNormalFrame; - return unwind_plan_sp; + if (abi) + { + unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); + abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp); + m_frame_type = eNormalFrame; + return unwind_plan_sp; + } } } @@ -764,10 +808,10 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // is properly encoded in the eh_frame section, so prefer that if available. // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of // how to unwind out of sigtramp. - if (m_frame_type == eTrapHandlerFrame) + if (m_frame_type == eTrapHandlerFrame && process) { m_fast_unwind_plan_sp.reset(); - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (process->GetTarget(), m_current_offset_backed_up_one); if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc) && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes) { return unwind_plan_sp; @@ -782,7 +826,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // But there is not. if (process && process->GetDynamicLoader() && process->GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo (m_sym_ctx)) { - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (process->GetTarget(), m_current_offset_backed_up_one); if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) { UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan because the DynamicLoader suggested we prefer it", @@ -792,7 +836,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () } // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions - if (behaves_like_zeroth_frame) + if (behaves_like_zeroth_frame && process) { unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one); if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) @@ -812,7 +856,10 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () } // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); + if (process) + { + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (process->GetTarget(), m_current_offset_backed_up_one); + } int valid_offset = -1; if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { @@ -822,7 +869,10 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible. - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one); + if (process) + { + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one); + } if (unwind_plan_sp && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) { // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably @@ -908,6 +958,16 @@ RegisterContextLLDB::ReadRegisterValueFromRegisterLocation (lldb_private::Unwind switch (regloc.type) { + case UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext: + { + const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number); + + if (!other_reg_info) + return false; + + success = m_thread.GetRegisterContext()->ReadRegister (other_reg_info, value); + } + break; case UnwindLLDB::RegisterLocation::eRegisterInRegister: { const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number); @@ -962,6 +1022,12 @@ RegisterContextLLDB::WriteRegisterValueToRegisterLocation (lldb_private::UnwindL switch (regloc.type) { + case UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext: + { + const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number); + success = m_thread.GetRegisterContext()->WriteRegister (other_reg_info, value); + } + break; case UnwindLLDB::RegisterLocation::eRegisterInRegister: { const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number); @@ -1004,6 +1070,11 @@ RegisterContextLLDB::IsValid () const return m_frame_type != eNotAValidFrame; } +// After the final stack frame in a stack walk we'll get one invalid (eNotAValidFrame) stack frame -- +// one past the end of the stack walk. But higher-level code will need to tell the differnece between +// "the unwind plan below this frame failed" versus "we successfully completed the stack walk" so +// this method helps to disambiguate that. + bool RegisterContextLLDB::IsTrapHandlerFrame () const { @@ -1056,57 +1127,42 @@ RegisterContextLLDB::IsTrapHandlerSymbol (lldb_private::Process *process, const enum UnwindLLDB::RegisterSearchResult RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) { + RegisterNumber regnum (m_thread, eRegisterKindLLDB, lldb_regnum); + // Have we already found this register location? if (!m_registers.empty()) { std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation>::const_iterator iterator; - iterator = m_registers.find (lldb_regnum); + iterator = m_registers.find (regnum.GetAsKind (eRegisterKindLLDB)); if (iterator != m_registers.end()) { regloc = iterator->second; - UnwindLogMsg ("supplying caller's saved reg %d's location, cached", lldb_regnum); + UnwindLogMsg ("supplying caller's saved %s (%d)'s location, cached", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } } - uint32_t sp_regnum = LLDB_INVALID_REGNUM; - uint32_t pc_regnum = LLDB_INVALID_REGNUM; - m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, eRegisterKindLLDB, sp_regnum); - m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, eRegisterKindLLDB, pc_regnum); - - // Are we looking for the CALLER's stack pointer? The stack pointer is defined to be the same as THIS frame's - // CFA so just return the CFA value. This is true on x86-32/x86-64 at least. - if (sp_regnum != LLDB_INVALID_REGNUM && sp_regnum == lldb_regnum) - { - // make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.inferred_value) - assert (sizeof (addr_t) <= sizeof (uint64_t)); - regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; - regloc.location.inferred_value = m_cfa; - m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's stack pointer (%d) value, computed from CFA", lldb_regnum); - return UnwindLLDB::RegisterSearchResult::eRegisterFound; - } - // Look through the available UnwindPlans for the register location. UnwindPlan::Row::RegisterLocation unwindplan_regloc; bool have_unwindplan_regloc = false; - RegisterKind unwindplan_registerkind = (RegisterKind)-1; + RegisterKind unwindplan_registerkind = kNumRegisterKinds; if (m_fast_unwind_plan_sp) { UnwindPlan::RowSP active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind (); - uint32_t row_regnum; - if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum)) + if (regnum.GetAsKind (unwindplan_registerkind) == LLDB_INVALID_REGNUM) { - UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme", - lldb_regnum, (int) unwindplan_registerkind); + UnwindLogMsg ("could not convert lldb regnum %s (%d) into %d RegisterKind reg numbering scheme", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), (int) unwindplan_registerkind); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } - if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc)) + if (active_row->GetRegisterInfo (regnum.GetAsKind (unwindplan_registerkind), unwindplan_regloc)) { - UnwindLogMsg ("supplying caller's saved reg %d's location using FastUnwindPlan", lldb_regnum); + UnwindLogMsg ("supplying caller's saved %s (%d)'s location using FastUnwindPlan", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); have_unwindplan_regloc = true; } } @@ -1119,37 +1175,49 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat if (m_full_unwind_plan_sp) { + RegisterNumber pc_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind (); - uint32_t row_regnum; - bool row_register_rewritten_to_return_address_reg = false; + + RegisterNumber return_address_reg; // If we're fetching the saved pc and this UnwindPlan defines a ReturnAddress register (e.g. lr on arm), // look for the return address register number in the UnwindPlan's row. - if (lldb_regnum == pc_regnum && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM) + if (pc_regnum.IsValid() + && pc_regnum == regnum + && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM) { - row_regnum = m_full_unwind_plan_sp->GetReturnAddressRegister(); - row_register_rewritten_to_return_address_reg = true; - UnwindLogMsg ("requested caller's saved PC but this UnwindPlan uses a RA reg; getting reg %d instead", - row_regnum); + + return_address_reg.init (m_thread, m_full_unwind_plan_sp->GetRegisterKind(), m_full_unwind_plan_sp->GetReturnAddressRegister()); + regnum = return_address_reg; + UnwindLogMsg ("requested caller's saved PC but this UnwindPlan uses a RA reg; getting %s (%d) instead", + return_address_reg.GetName(), return_address_reg.GetAsKind (eRegisterKindLLDB)); } else { - if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum)) + if (regnum.GetAsKind (unwindplan_registerkind) == LLDB_INVALID_REGNUM) { if (unwindplan_registerkind == eRegisterKindGeneric) - UnwindLogMsg ("could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme", lldb_regnum); + { + UnwindLogMsg ("could not convert lldb regnum %s (%d) into eRegisterKindGeneric reg numbering scheme", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); + } else - UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme", - lldb_regnum, (int) unwindplan_registerkind); + { + UnwindLogMsg ("could not convert lldb regnum %s (%d) into %d RegisterKind reg numbering scheme", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), (int) unwindplan_registerkind); + } return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } } - if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc)) + if (regnum.IsValid() + && active_row->GetRegisterInfo (regnum.GetAsKind (unwindplan_registerkind), unwindplan_regloc)) { have_unwindplan_regloc = true; - UnwindLogMsg ("supplying caller's saved reg %d's location using %s UnwindPlan", lldb_regnum, + UnwindLogMsg ("supplying caller's saved %s (%d)'s location using %s UnwindPlan", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), m_full_unwind_plan_sp->GetSourceName().GetCString()); } @@ -1158,19 +1226,19 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat // Handle this specially. if (have_unwindplan_regloc == false - && row_register_rewritten_to_return_address_reg == true - && IsFrameZero() - && row_regnum != LLDB_INVALID_REGNUM) + && return_address_reg.IsValid() + && IsFrameZero()) { - uint32_t ra_regnum_in_lldb_reg_numbering; - if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, row_regnum, eRegisterKindLLDB, ra_regnum_in_lldb_reg_numbering)) + if (return_address_reg.GetAsKind (eRegisterKindLLDB) != LLDB_INVALID_REGNUM) { lldb_private::UnwindLLDB::RegisterLocation new_regloc; - new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister; - new_regloc.location.register_number = ra_regnum_in_lldb_reg_numbering; - m_registers[lldb_regnum] = new_regloc; + new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext; + new_regloc.location.register_number = return_address_reg.GetAsKind (eRegisterKindLLDB); + m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = new_regloc; regloc = new_regloc; - UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0, saved in %d", lldb_regnum, ra_regnum_in_lldb_reg_numbering); + UnwindLogMsg ("supplying caller's register %s (%d) from the live RegisterContext at frame 0, saved in %d", + return_address_reg.GetName(), return_address_reg.GetAsKind (eRegisterKindLLDB), + return_address_reg.GetAsKind (eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } } @@ -1187,13 +1255,12 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat // when we're at a call site location. // arch_default_ra_regnum is the return address register # in the Full UnwindPlan register numbering - uint32_t arch_default_ra_regnum = LLDB_INVALID_REGNUM; - if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, unwindplan_registerkind, arch_default_ra_regnum) - && arch_default_ra_regnum != LLDB_INVALID_REGNUM - && pc_regnum != LLDB_INVALID_REGNUM - && pc_regnum == lldb_regnum + RegisterNumber arch_default_ra_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + + if (arch_default_ra_regnum.GetAsKind (unwindplan_registerkind) != LLDB_INVALID_REGNUM + && pc_regnum == regnum && unwindplan_regloc.IsInOtherRegister() - && unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum + && unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum.GetAsKind (unwindplan_registerkind) && m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes && !m_all_registers_available) { @@ -1201,15 +1268,32 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat m_full_unwind_plan_sp->GetSourceName().GetCString()); // Throw away the full unwindplan; install the arch default unwindplan - if (TryFallbackUnwindPlan()) + if (ForceSwitchToFallbackUnwindPlan()) { - // Now re-fetch the pc value we're searching for - uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM; + // Update for the possibly new unwind plan + unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind (); UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); - if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg) - && arch_default_pc_reg != LLDB_INVALID_REGNUM - && active_row - && active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc)) + + // Sanity check: Verify that we can fetch a pc value and CFA value with this unwind plan + + RegisterNumber arch_default_pc_reg (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + bool can_fetch_pc_value = false; + bool can_fetch_cfa = false; + addr_t cfa_value; + if (active_row) + { + if (arch_default_pc_reg.GetAsKind (unwindplan_registerkind) != LLDB_INVALID_REGNUM + && active_row->GetRegisterInfo (arch_default_pc_reg.GetAsKind (unwindplan_registerkind), unwindplan_regloc)) + { + can_fetch_pc_value = true; + } + if (ReadCFAValueForRow (unwindplan_registerkind, active_row, cfa_value)) + { + can_fetch_cfa = true; + } + } + + if (can_fetch_pc_value && can_fetch_cfa) { have_unwindplan_regloc = true; } @@ -1218,10 +1302,35 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat have_unwindplan_regloc = false; } } + else + { + // We were unable to fall back to another unwind plan + have_unwindplan_regloc = false; + } } } } + if (have_unwindplan_regloc == false) + { + // Did the UnwindPlan fail to give us the caller's stack pointer? + // The stack pointer is defined to be the same as THIS frame's CFA, so return the CFA value as + // the caller's stack pointer. This is true on x86-32/x86-64 at least. + + RegisterNumber sp_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + if (sp_regnum.GetAsKind (eRegisterKindLLDB) != LLDB_INVALID_REGNUM + && sp_regnum.GetAsKind (eRegisterKindLLDB) == regnum.GetAsKind (eRegisterKindLLDB)) + { + // make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.inferred_value) + assert (sizeof (addr_t) <= sizeof (uint64_t)); + regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; + regloc.location.inferred_value = m_cfa; + m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc; + UnwindLogMsg ("supplying caller's stack pointer %s (%d) value, computed from CFA", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + } ExecutionContext exe_ctx(m_thread.shared_from_this()); Process *process = exe_ctx.GetProcessPtr(); @@ -1232,11 +1341,11 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat ABI *abi = process ? process->GetABI().get() : NULL; if (abi) { - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum); + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(regnum.GetAsKind (eRegisterKindLLDB)); if (reg_info && abi->RegisterIsVolatile (reg_info)) { - UnwindLogMsg ("did not supply reg location for %d (%s) because it is volatile", - lldb_regnum, reg_info->name ? reg_info->name : "??"); + UnwindLogMsg ("did not supply reg location for %s (%d) because it is volatile", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; } } @@ -1245,15 +1354,27 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat { // This is frame 0 - we should return the actual live register context value lldb_private::UnwindLLDB::RegisterLocation new_regloc; - new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister; - new_regloc.location.register_number = lldb_regnum; - m_registers[lldb_regnum] = new_regloc; + new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext; + new_regloc.location.register_number = regnum.GetAsKind (eRegisterKindLLDB); + m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = new_regloc; regloc = new_regloc; - UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0", lldb_regnum); + UnwindLogMsg ("supplying caller's register %s (%d) from the live RegisterContext at frame 0", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } else - UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum); + { + std::string unwindplan_name (""); + if (m_full_unwind_plan_sp) + { + unwindplan_name += "via '"; + unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString(); + unwindplan_name += "'"; + } + UnwindLogMsg ("no save location for %s (%d) %s", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), + unwindplan_name.c_str()); + } return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } @@ -1262,8 +1383,9 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat { lldb_private::UnwindLLDB::RegisterLocation new_regloc; new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved; - m_registers[lldb_regnum] = new_regloc; - UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum); + m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = new_regloc; + UnwindLogMsg ("save location for %s (%d) is unspecified, continue searching", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } @@ -1271,7 +1393,8 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat { if (IsFrameZero ()) { - UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum); + UnwindLogMsg ("could not supply caller's %s (%d) location, IsSame", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } else @@ -1285,8 +1408,10 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat int offset = unwindplan_regloc.GetOffset(); regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_cfa + offset; - m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset %d", lldb_regnum, offset); + m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc; + UnwindLogMsg ("supplying caller's register %s (%d), value is CFA plus offset %d [value is 0x%" PRIx64 "]", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), + offset, regloc.location.inferred_value); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } @@ -1295,24 +1420,29 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat int offset = unwindplan_regloc.GetOffset(); regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_cfa + offset; - m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset %d", lldb_regnum, offset); + m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc; + UnwindLogMsg ("supplying caller's register %s (%d) from the stack, saved at CFA plus offset %d [saved at 0x%" PRIx64 "]", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), + offset, regloc.location.target_memory_location); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } if (unwindplan_regloc.IsInOtherRegister()) { uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber(); - uint32_t row_regnum_in_lldb; - if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, unwindplan_regnum, eRegisterKindLLDB, row_regnum_in_lldb)) + RegisterNumber row_regnum (m_thread, unwindplan_registerkind, unwindplan_regnum); + if (row_regnum.GetAsKind (eRegisterKindLLDB) == LLDB_INVALID_REGNUM) { - UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum); + UnwindLogMsg ("could not supply caller's %s (%d) location - was saved in another reg but couldn't convert that regnum", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister; - regloc.location.register_number = row_regnum_in_lldb; - m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's register %d, saved in register %d", lldb_regnum, row_regnum_in_lldb); + regloc.location.register_number = row_regnum.GetAsKind (eRegisterKindLLDB); + m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc; + UnwindLogMsg ("supplying caller's register %s (%d), saved in register %s (%d)", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), + row_regnum.GetName(), row_regnum.GetAsKind (eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } @@ -1334,75 +1464,277 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat { regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = val; - m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsDWARFExpression)", lldb_regnum); + m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc; + UnwindLogMsg ("supplying caller's register %s (%d) via DWARF expression (IsDWARFExpression)", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } else { regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = val; - m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsAtDWARFExpression)", lldb_regnum); + m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc; + UnwindLogMsg ("supplying caller's register %s (%d) via DWARF expression (IsAtDWARFExpression)", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } } - UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for reg %d but failed", lldb_regnum); + UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for %s (%d) but failed", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } - UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum); + UnwindLogMsg ("no save location for %s (%d) in this stack frame", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); // FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are unsupported. return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } -// If the Full unwindplan has been determined to be incorrect, this method will -// replace it with the architecture's default unwindplan, if one is defined. -// It will also find the FuncUnwinders object for this function and replace the -// Full unwind method for the function there so we don't use the errant Full unwindplan -// again in the future of this debug session. -// We're most likely doing this because the Full unwindplan was generated by assembly -// instruction profiling and the profiler got something wrong. +// TryFallbackUnwindPlan() -- this method is a little tricky. +// +// When this is called, the frame above -- the caller frame, the "previous" frame -- +// is invalid or bad. +// +// Instead of stopping the stack walk here, we'll try a different UnwindPlan and see +// if we can get a valid frame above us. +// +// This most often happens when an unwind plan based on assembly instruction inspection +// is not correct -- mostly with hand-written assembly functions or functions where the +// stack frame is set up "out of band", e.g. the kernel saved the register context and +// then called an asynchronous trap handler like _sigtramp. +// +// Often in these cases, if we just do a dumb stack walk we'll get past this tricky +// frame and our usual techniques can continue to be used. bool RegisterContextLLDB::TryFallbackUnwindPlan () { - UnwindPlan::Row::RegisterLocation unwindplan_regloc; - if (m_fallback_unwind_plan_sp.get() == NULL) + if (m_fallback_unwind_plan_sp.get() == nullptr) + return false; + + if (m_full_unwind_plan_sp.get() == nullptr) return false; + if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() + || m_full_unwind_plan_sp->GetSourceName() == m_fallback_unwind_plan_sp->GetSourceName()) + { + return false; + } + + // If a compiler generated unwind plan failed, trying the arch default unwindplan + // isn't going to do any better. + if (m_full_unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes) + return false; + + + // Get the caller's pc value and our own CFA value. + // Swap in the fallback unwind plan, re-fetch the caller's pc value and CFA value. + // If they're the same, then the fallback unwind plan provides no benefit. + + RegisterNumber pc_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + + addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS; + addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS; + addr_t old_this_frame_cfa_value = m_cfa; + UnwindLLDB::RegisterLocation regloc; + if (SavedLocationForRegister (pc_regnum.GetAsKind (eRegisterKindLLDB), regloc) == UnwindLLDB::RegisterSearchResult::eRegisterFound) + { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(pc_regnum.GetAsKind (eRegisterKindLLDB)); + if (reg_info) + { + RegisterValue reg_value; + if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value)) + { + old_caller_pc_value = reg_value.GetAsUInt64(); + } + } + } + + // This is a tricky wrinkle! If SavedLocationForRegister() detects a really impossible + // register location for the full unwind plan, it may call ForceSwitchToFallbackUnwindPlan() + // which in turn replaces the full unwindplan with the fallback... in short, we're done, + // we're using the fallback UnwindPlan. + // We checked if m_fallback_unwind_plan_sp was nullptr at the top -- the only way it + // became nullptr since then is via SavedLocationForRegister(). + if (m_fallback_unwind_plan_sp.get() == nullptr) + return true; + + + // Switch the full UnwindPlan to be the fallback UnwindPlan. If we decide this isn't + // working, we need to restore. + // We'll also need to save & restore the value of the m_cfa ivar. Save is down below a bit in 'old_cfa'. UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp; + addr_t old_cfa = m_cfa; + + m_registers.clear(); + + m_full_unwind_plan_sp = m_fallback_unwind_plan_sp; + UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM) { - FuncUnwindersSP func_unwinders_sp; - if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule()) + addr_t new_cfa; + if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa) + || new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS) + { + UnwindLogMsg ("failed to get cfa with fallback unwindplan"); + m_fallback_unwind_plan_sp.reset(); + m_full_unwind_plan_sp = original_full_unwind_plan_sp; + m_cfa = old_cfa; + return false; + } + m_cfa = new_cfa; + + if (SavedLocationForRegister (pc_regnum.GetAsKind (eRegisterKindLLDB), regloc) == UnwindLLDB::RegisterSearchResult::eRegisterFound) { - func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx); - if (func_unwinders_sp) + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(pc_regnum.GetAsKind (eRegisterKindLLDB)); + if (reg_info) { - func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread); + RegisterValue reg_value; + if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value)) + { + new_caller_pc_value = reg_value.GetAsUInt64(); + } } } - m_registers.clear(); - m_full_unwind_plan_sp = m_fallback_unwind_plan_sp; - addr_t cfa_regval = LLDB_INVALID_ADDRESS; - if (ReadGPRValue (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval)) + + + if (new_caller_pc_value == LLDB_INVALID_ADDRESS) { - m_cfa = cfa_regval + active_row->GetCFAOffset (); + UnwindLogMsg ("failed to get a pc value for the caller frame with the fallback unwind plan"); + m_fallback_unwind_plan_sp.reset(); + m_full_unwind_plan_sp = original_full_unwind_plan_sp; + m_cfa = old_cfa; + return false; + } + + if (old_caller_pc_value != LLDB_INVALID_ADDRESS) + { + if (old_caller_pc_value == new_caller_pc_value && new_cfa == old_this_frame_cfa_value) + { + UnwindLogMsg ("fallback unwind plan got the same values for this frame CFA and caller frame pc, not using"); + m_fallback_unwind_plan_sp.reset(); + m_full_unwind_plan_sp = original_full_unwind_plan_sp; + m_cfa = old_cfa; + return false; + } } - UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.", - original_full_unwind_plan_sp->GetSourceName().GetCString(), m_fallback_unwind_plan_sp->GetSourceName().GetCString()); + UnwindLogMsg ("trying to unwind from this function with the UnwindPlan '%s' because UnwindPlan '%s' failed.", + m_fallback_unwind_plan_sp->GetSourceName().GetCString(), + original_full_unwind_plan_sp->GetSourceName().GetCString()); + + // We've copied the fallback unwind plan into the full - now clear the fallback. m_fallback_unwind_plan_sp.reset(); } return true; } +bool +RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan () +{ + if (m_fallback_unwind_plan_sp.get() == NULL) + return false; + + if (m_full_unwind_plan_sp.get() == NULL) + return false; + + if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() + || m_full_unwind_plan_sp->GetSourceName() == m_fallback_unwind_plan_sp->GetSourceName()) + { + return false; + } + + UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + + if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM) + { + addr_t new_cfa; + if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa) + || new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS) + { + UnwindLogMsg ("failed to get cfa with fallback unwindplan"); + m_fallback_unwind_plan_sp.reset(); + return false; + } + + m_full_unwind_plan_sp = m_fallback_unwind_plan_sp; + m_fallback_unwind_plan_sp.reset(); + + m_registers.clear(); + + m_cfa = new_cfa; + + UnwindLogMsg ("switched unconditionally to the fallback unwindplan %s", m_full_unwind_plan_sp->GetSourceName().GetCString()); + return true; + } + return false; +} + +bool +RegisterContextLLDB::ReadCFAValueForRow (lldb::RegisterKind row_register_kind, + const UnwindPlan::RowSP &row, + addr_t &cfa_value) +{ + RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFARegister()); + RegisterValue reg_value; + + cfa_value = LLDB_INVALID_ADDRESS; + addr_t cfa_reg_contents; + + if (ReadGPRValue (cfa_reg, cfa_reg_contents)) + { + if (row->GetCFAType() == UnwindPlan::Row::CFAIsRegisterDereferenced) + { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex (cfa_reg.GetAsKind (eRegisterKindLLDB)); + RegisterValue reg_value; + if (reg_info) + { + Error error = ReadRegisterValueFromMemory(reg_info, + cfa_reg_contents, + reg_info->byte_size, + reg_value); + if (error.Success ()) + { + cfa_value = reg_value.GetAsUInt64(); + UnwindLogMsg ("CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 ", CFA value is 0x%" PRIx64, + cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), + cfa_reg_contents, cfa_value); + return true; + } + else + { + UnwindLogMsg ("Tried to deref reg %s (%d) [0x%" PRIx64 "] but memory read failed.", + cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), + cfa_reg_contents); + } + } + } + else + { + if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || cfa_reg_contents == 1) + { + UnwindLogMsg ("Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64, + cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), + cfa_reg_contents); + cfa_reg_contents = LLDB_INVALID_ADDRESS; + return false; + } + cfa_value = cfa_reg_contents + row->GetCFAOffset (); + UnwindLogMsg ("CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64 ", offset is %d", + cfa_value, + cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), + cfa_reg_contents, row->GetCFAOffset ()); + return true; + } + } + return false; +} + // Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that // this frame called. e.g. // @@ -1471,6 +1803,12 @@ RegisterContextLLDB::ReadGPRValue (lldb::RegisterKind register_kind, uint32_t re return false; } +bool +RegisterContextLLDB::ReadGPRValue (const RegisterNumber ®num, addr_t &value) +{ + return ReadGPRValue (regnum.GetRegisterKind(), regnum.GetRegisterNumber(), value); +} + // Find the value of a register in THIS frame bool @@ -1593,6 +1931,10 @@ RegisterContextLLDB::ReadPC (addr_t& pc) if (!IsValid()) return false; + bool above_trap_handler = false; + if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsTrapHandlerFrame()) + above_trap_handler = true; + if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) { // A pc value of 0 or 1 is impossible in the middle of the stack -- it indicates the end of a stack walk. @@ -1601,6 +1943,7 @@ RegisterContextLLDB::ReadPC (addr_t& pc) // find the bug. if (m_all_registers_available == false + && above_trap_handler == false && (pc == 0 || pc == 1)) { return false; diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h index d6ecfeb68caa4..5f94a977448d5 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -16,6 +16,7 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Utility/RegisterNumber.h" #include "UnwindLLDB.h" namespace lldb_private { @@ -98,6 +99,12 @@ private: // UnwindLLDB needs to pass around references to RegisterLocations friend class UnwindLLDB; + + // Returns true if we have an unwind loop -- the same stack frame unwinding + // multiple times. + bool + CheckIfLoopingStack (); + // Indicates whether this frame is frame zero -- the currently // executing frame -- or not. bool @@ -175,11 +182,30 @@ private: bool TryFallbackUnwindPlan (); + //------------------------------------------------------------------ + /// Switch to the fallback unwind plan unconditionally without any safety + /// checks that it is providing better results than the normal unwind plan. + /// + /// The only time it is valid to call this method is if the full unwindplan is + /// found to be fundamentally incorrect/impossible. + /// + /// Returns true if it was able to install the fallback unwind plan. + //------------------------------------------------------------------ + bool + ForceSwitchToFallbackUnwindPlan (); + // Get the contents of a general purpose (address-size) register for this frame // (usually retrieved from the next frame) bool ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, lldb::addr_t &value); + bool + ReadGPRValue (const RegisterNumber ®_num, lldb::addr_t &value); + + // Get the CFA register for a given frame. + bool + ReadCFAValueForRow (lldb::RegisterKind register_kind, const UnwindPlan::RowSP &row, lldb::addr_t &value); + lldb::UnwindPlanSP GetFastUnwindPlanForFrame (); diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp index e246e715de86a..a2ab67438b75e 100644 --- a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp +++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp @@ -149,7 +149,8 @@ RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info, // TOOD: need a better way to detect when "long double" types are // the same bytes size as "double" -#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) && !defined(_MSC_VER) && !defined(__mips__) +#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) && !defined(_MSC_VER) && \ + !defined(__mips__) && !defined(__powerpc__) && !defined(__ANDROID_NDK__) case sizeof (long double): if (sizeof (long double) == sizeof(uint32_t)) { diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp new file mode 100644 index 0000000000000..a9477d583517f --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp @@ -0,0 +1,273 @@ +//===-- RegisterContextPOSIX_powerpc.cpp -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <cstring> +#include <errno.h> +#include <stdint.h> + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Host/Endian.h" +#include "llvm/Support/Compiler.h" + +#include "RegisterContextPOSIX_powerpc.h" +#include "Plugins/Process/elf-core/ProcessElfCore.h" + +using namespace lldb_private; +using namespace lldb; + +static const +uint32_t g_gpr_regnums[] = +{ + gpr_r0_powerpc, + gpr_r1_powerpc, + gpr_r2_powerpc, + gpr_r3_powerpc, + gpr_r4_powerpc, + gpr_r5_powerpc, + gpr_r6_powerpc, + gpr_r7_powerpc, + gpr_r8_powerpc, + gpr_r9_powerpc, + gpr_r10_powerpc, + gpr_r11_powerpc, + gpr_r12_powerpc, + gpr_r13_powerpc, + gpr_r14_powerpc, + gpr_r15_powerpc, + gpr_r16_powerpc, + gpr_r17_powerpc, + gpr_r18_powerpc, + gpr_r19_powerpc, + gpr_r20_powerpc, + gpr_r21_powerpc, + gpr_r22_powerpc, + gpr_r23_powerpc, + gpr_r24_powerpc, + gpr_r25_powerpc, + gpr_r26_powerpc, + gpr_r27_powerpc, + gpr_r28_powerpc, + gpr_r29_powerpc, + gpr_r30_powerpc, + gpr_r31_powerpc, + gpr_lr_powerpc, + gpr_cr_powerpc, + gpr_xer_powerpc, + gpr_ctr_powerpc, + gpr_pc_powerpc, +}; + +static const +uint32_t g_fpr_regnums[] = +{ + fpr_f0_powerpc, + fpr_f1_powerpc, + fpr_f2_powerpc, + fpr_f3_powerpc, + fpr_f4_powerpc, + fpr_f5_powerpc, + fpr_f6_powerpc, + fpr_f7_powerpc, + fpr_f8_powerpc, + fpr_f9_powerpc, + fpr_f10_powerpc, + fpr_f11_powerpc, + fpr_f12_powerpc, + fpr_f13_powerpc, + fpr_f14_powerpc, + fpr_f15_powerpc, + fpr_f16_powerpc, + fpr_f17_powerpc, + fpr_f18_powerpc, + fpr_f19_powerpc, + fpr_f20_powerpc, + fpr_f21_powerpc, + fpr_f22_powerpc, + fpr_f23_powerpc, + fpr_f24_powerpc, + fpr_f25_powerpc, + fpr_f26_powerpc, + fpr_f27_powerpc, + fpr_f28_powerpc, + fpr_f29_powerpc, + fpr_f30_powerpc, + fpr_f31_powerpc, + fpr_fpscr_powerpc, +}; + +// Number of register sets provided by this context. +enum +{ + k_num_register_sets = 2 +}; + +static const RegisterSet +g_reg_sets_powerpc[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers_powerpc, g_gpr_regnums }, + { "Floating Point Registers", "fpr", k_num_fpr_registers_powerpc, g_fpr_regnums }, +}; + +bool RegisterContextPOSIX_powerpc::IsGPR(unsigned reg) +{ + return reg <= k_num_gpr_registers_powerpc; // GPR's come first. +} + +bool +RegisterContextPOSIX_powerpc::IsFPR(unsigned reg) +{ + // XXX + return (reg >= k_first_fpr) && (reg <= k_last_fpr); +} + +RegisterContextPOSIX_powerpc::RegisterContextPOSIX_powerpc(Thread &thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info) + : RegisterContext(thread, concrete_frame_idx) +{ + m_register_info_ap.reset(register_info); + + // elf-core yet to support ReadFPR() + ProcessSP base = CalculateProcess(); + if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) + return; +} + +RegisterContextPOSIX_powerpc::~RegisterContextPOSIX_powerpc() +{ +} + +void +RegisterContextPOSIX_powerpc::Invalidate() +{ +} + +void +RegisterContextPOSIX_powerpc::InvalidateAllRegisters() +{ +} + +unsigned +RegisterContextPOSIX_powerpc::GetRegisterOffset(unsigned reg) +{ + assert(reg < k_num_registers_powerpc && "Invalid register number."); + return GetRegisterInfo()[reg].byte_offset; +} + +unsigned +RegisterContextPOSIX_powerpc::GetRegisterSize(unsigned reg) +{ + assert(reg < k_num_registers_powerpc && "Invalid register number."); + return GetRegisterInfo()[reg].byte_size; +} + +size_t +RegisterContextPOSIX_powerpc::GetRegisterCount() +{ + size_t num_registers = k_num_registers_powerpc; + return num_registers; +} + +size_t +RegisterContextPOSIX_powerpc::GetGPRSize() +{ + return m_register_info_ap->GetGPRSize(); +} + +const RegisterInfo * +RegisterContextPOSIX_powerpc::GetRegisterInfo() +{ + // Commonly, this method is overridden and g_register_infos is copied and specialized. + // So, use GetRegisterInfo() rather than g_register_infos in this scope. + return m_register_info_ap->GetRegisterInfo (); +} + +const RegisterInfo * +RegisterContextPOSIX_powerpc::GetRegisterInfoAtIndex(size_t reg) +{ + if (reg < k_num_registers_powerpc) + return &GetRegisterInfo()[reg]; + else + return NULL; +} + +size_t +RegisterContextPOSIX_powerpc::GetRegisterSetCount() +{ + size_t sets = 0; + for (size_t set = 0; set < k_num_register_sets; ++set) + { + if (IsRegisterSetAvailable(set)) + ++sets; + } + + return sets; +} + +const RegisterSet * +RegisterContextPOSIX_powerpc::GetRegisterSet(size_t set) +{ + if (IsRegisterSetAvailable(set)) + return &g_reg_sets_powerpc[set]; + else + return NULL; +} + +const char * +RegisterContextPOSIX_powerpc::GetRegisterName(unsigned reg) +{ + assert(reg < k_num_registers_powerpc && "Invalid register offset."); + return GetRegisterInfo()[reg].name; +} + +lldb::ByteOrder +RegisterContextPOSIX_powerpc::GetByteOrder() +{ + // Get the target process whose privileged thread was used for the register read. + lldb::ByteOrder byte_order = eByteOrderInvalid; + Process *process = CalculateProcess().get(); + + if (process) + byte_order = process->GetByteOrder(); + return byte_order; +} + +bool +RegisterContextPOSIX_powerpc::IsRegisterSetAvailable(size_t set_index) +{ + size_t num_sets = k_num_register_sets; + + return (set_index < num_sets); +} + +// Used when parsing DWARF and EH frame information and any other +// object file sections that contain register numbers in them. +uint32_t +RegisterContextPOSIX_powerpc::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) +{ + const uint32_t num_regs = GetRegisterCount(); + + assert (kind < kNumRegisterKinds); + for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) + { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx); + + if (reg_info->kinds[kind] == num) + return reg_idx; + } + + return LLDB_INVALID_REGNUM; +} + diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h new file mode 100644 index 0000000000000..3194c3968c989 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h @@ -0,0 +1,173 @@ +//===-- RegisterContextPOSIX_powerpc.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_RegisterContextPOSIX_powerpc_H_ +#define liblldb_RegisterContextPOSIX_powerpc_H_ + +#include "lldb/Core/Log.h" +#include "RegisterContextPOSIX.h" +#include "RegisterContext_powerpc.h" + +class ProcessMonitor; + +// --------------------------------------------------------------------------- +// Internal codes for all powerpc registers. +// --------------------------------------------------------------------------- +enum +{ + k_first_gpr_powerpc, + gpr_r0_powerpc = k_first_gpr_powerpc, + gpr_r1_powerpc, + gpr_r2_powerpc, + gpr_r3_powerpc, + gpr_r4_powerpc, + gpr_r5_powerpc, + gpr_r6_powerpc, + gpr_r7_powerpc, + gpr_r8_powerpc, + gpr_r9_powerpc, + gpr_r10_powerpc, + gpr_r11_powerpc, + gpr_r12_powerpc, + gpr_r13_powerpc, + gpr_r14_powerpc, + gpr_r15_powerpc, + gpr_r16_powerpc, + gpr_r17_powerpc, + gpr_r18_powerpc, + gpr_r19_powerpc, + gpr_r20_powerpc, + gpr_r21_powerpc, + gpr_r22_powerpc, + gpr_r23_powerpc, + gpr_r24_powerpc, + gpr_r25_powerpc, + gpr_r26_powerpc, + gpr_r27_powerpc, + gpr_r28_powerpc, + gpr_r29_powerpc, + gpr_r30_powerpc, + gpr_r31_powerpc, + gpr_lr_powerpc, + gpr_cr_powerpc, + gpr_xer_powerpc, + gpr_ctr_powerpc, + gpr_pc_powerpc, + k_last_gpr_powerpc = gpr_pc_powerpc, + + k_first_fpr, + fpr_f0_powerpc = k_first_fpr, + fpr_f1_powerpc, + fpr_f2_powerpc, + fpr_f3_powerpc, + fpr_f4_powerpc, + fpr_f5_powerpc, + fpr_f6_powerpc, + fpr_f7_powerpc, + fpr_f8_powerpc, + fpr_f9_powerpc, + fpr_f10_powerpc, + fpr_f11_powerpc, + fpr_f12_powerpc, + fpr_f13_powerpc, + fpr_f14_powerpc, + fpr_f15_powerpc, + fpr_f16_powerpc, + fpr_f17_powerpc, + fpr_f18_powerpc, + fpr_f19_powerpc, + fpr_f20_powerpc, + fpr_f21_powerpc, + fpr_f22_powerpc, + fpr_f23_powerpc, + fpr_f24_powerpc, + fpr_f25_powerpc, + fpr_f26_powerpc, + fpr_f27_powerpc, + fpr_f28_powerpc, + fpr_f29_powerpc, + fpr_f30_powerpc, + fpr_f31_powerpc, + fpr_fpscr_powerpc, + k_last_fpr = fpr_fpscr_powerpc, + + k_num_registers_powerpc, + k_num_gpr_registers_powerpc = k_last_gpr_powerpc - k_first_gpr_powerpc + 1, + k_num_fpr_registers_powerpc = k_last_fpr - k_first_fpr + 1, +}; + +class RegisterContextPOSIX_powerpc + : public lldb_private::RegisterContext +{ +public: + RegisterContextPOSIX_powerpc (lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + + ~RegisterContextPOSIX_powerpc(); + + void + Invalidate(); + + void + InvalidateAllRegisters(); + + size_t + GetRegisterCount(); + + virtual size_t + GetGPRSize(); + + virtual unsigned + GetRegisterSize(unsigned reg); + + virtual unsigned + GetRegisterOffset(unsigned reg); + + const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex(size_t reg); + + size_t + GetRegisterSetCount(); + + const lldb_private::RegisterSet * + GetRegisterSet(size_t set); + + const char * + GetRegisterName(unsigned reg); + + uint32_t + ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num); + +protected: + uint64_t m_gpr_powerpc[k_num_gpr_registers_powerpc]; // general purpose registers. + std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) + + // Determines if an extended register set is supported on the processor running the inferior process. + virtual bool + IsRegisterSetAvailable(size_t set_index); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfo(); + + bool + IsGPR(unsigned reg); + + bool + IsFPR(unsigned reg); + + lldb::ByteOrder GetByteOrder(); + + virtual bool ReadGPR() = 0; + virtual bool ReadFPR() = 0; + virtual bool WriteGPR() = 0; + virtual bool WriteFPR() = 0; +}; + +#endif // #ifndef liblldb_RegisterContextPOSIX_powerpc_H_ diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp index 2925a33a16905..77b6385da8bd3 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp @@ -30,96 +30,96 @@ using namespace lldb; const uint32_t g_gpr_regnums_i386[] = { - gpr_eax_i386, - gpr_ebx_i386, - gpr_ecx_i386, - gpr_edx_i386, - gpr_edi_i386, - gpr_esi_i386, - gpr_ebp_i386, - gpr_esp_i386, - gpr_eip_i386, - gpr_eflags_i386, - gpr_cs_i386, - gpr_fs_i386, - gpr_gs_i386, - gpr_ss_i386, - gpr_ds_i386, - gpr_es_i386, - gpr_ax_i386, - gpr_bx_i386, - gpr_cx_i386, - gpr_dx_i386, - gpr_di_i386, - gpr_si_i386, - gpr_bp_i386, - gpr_sp_i386, - gpr_ah_i386, - gpr_bh_i386, - gpr_ch_i386, - gpr_dh_i386, - gpr_al_i386, - gpr_bl_i386, - gpr_cl_i386, - gpr_dl_i386, + lldb_eax_i386, + lldb_ebx_i386, + lldb_ecx_i386, + lldb_edx_i386, + lldb_edi_i386, + lldb_esi_i386, + lldb_ebp_i386, + lldb_esp_i386, + lldb_eip_i386, + lldb_eflags_i386, + lldb_cs_i386, + lldb_fs_i386, + lldb_gs_i386, + lldb_ss_i386, + lldb_ds_i386, + lldb_es_i386, + lldb_ax_i386, + lldb_bx_i386, + lldb_cx_i386, + lldb_dx_i386, + lldb_di_i386, + lldb_si_i386, + lldb_bp_i386, + lldb_sp_i386, + lldb_ah_i386, + lldb_bh_i386, + lldb_ch_i386, + lldb_dh_i386, + lldb_al_i386, + lldb_bl_i386, + lldb_cl_i386, + lldb_dl_i386, LLDB_INVALID_REGNUM, // Register sets must be terminated with LLDB_INVALID_REGNUM. }; static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - 1 == k_num_gpr_registers_i386, "g_gpr_regnums_i386 has wrong number of register infos"); const uint32_t -g_fpu_regnums_i386[] = -{ - fpu_fctrl_i386, - fpu_fstat_i386, - fpu_ftag_i386, - fpu_fop_i386, - fpu_fiseg_i386, - fpu_fioff_i386, - fpu_foseg_i386, - fpu_fooff_i386, - fpu_mxcsr_i386, - fpu_mxcsrmask_i386, - fpu_st0_i386, - fpu_st1_i386, - fpu_st2_i386, - fpu_st3_i386, - fpu_st4_i386, - fpu_st5_i386, - fpu_st6_i386, - fpu_st7_i386, - fpu_mm0_i386, - fpu_mm1_i386, - fpu_mm2_i386, - fpu_mm3_i386, - fpu_mm4_i386, - fpu_mm5_i386, - fpu_mm6_i386, - fpu_mm7_i386, - fpu_xmm0_i386, - fpu_xmm1_i386, - fpu_xmm2_i386, - fpu_xmm3_i386, - fpu_xmm4_i386, - fpu_xmm5_i386, - fpu_xmm6_i386, - fpu_xmm7_i386, +g_lldb_regnums_i386[] = +{ + lldb_fctrl_i386, + lldb_fstat_i386, + lldb_ftag_i386, + lldb_fop_i386, + lldb_fiseg_i386, + lldb_fioff_i386, + lldb_foseg_i386, + lldb_fooff_i386, + lldb_mxcsr_i386, + lldb_mxcsrmask_i386, + lldb_st0_i386, + lldb_st1_i386, + lldb_st2_i386, + lldb_st3_i386, + lldb_st4_i386, + lldb_st5_i386, + lldb_st6_i386, + lldb_st7_i386, + lldb_mm0_i386, + lldb_mm1_i386, + lldb_mm2_i386, + lldb_mm3_i386, + lldb_mm4_i386, + lldb_mm5_i386, + lldb_mm6_i386, + lldb_mm7_i386, + lldb_xmm0_i386, + lldb_xmm1_i386, + lldb_xmm2_i386, + lldb_xmm3_i386, + lldb_xmm4_i386, + lldb_xmm5_i386, + lldb_xmm6_i386, + lldb_xmm7_i386, LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM. }; -static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - 1 == k_num_fpr_registers_i386, - "g_fpu_regnums_i386 has wrong number of register infos"); +static_assert((sizeof(g_lldb_regnums_i386) / sizeof(g_lldb_regnums_i386[0])) - 1 == k_num_fpr_registers_i386, + "g_lldb_regnums_i386 has wrong number of register infos"); const uint32_t g_avx_regnums_i386[] = { - fpu_ymm0_i386, - fpu_ymm1_i386, - fpu_ymm2_i386, - fpu_ymm3_i386, - fpu_ymm4_i386, - fpu_ymm5_i386, - fpu_ymm6_i386, - fpu_ymm7_i386, + lldb_ymm0_i386, + lldb_ymm1_i386, + lldb_ymm2_i386, + lldb_ymm3_i386, + lldb_ymm4_i386, + lldb_ymm5_i386, + lldb_ymm6_i386, + lldb_ymm7_i386, LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM. }; static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 == k_num_avx_registers_i386, @@ -128,212 +128,212 @@ static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 = static const uint32_t g_gpr_regnums_x86_64[] = { - gpr_rax_x86_64, - gpr_rbx_x86_64, - gpr_rcx_x86_64, - gpr_rdx_x86_64, - gpr_rdi_x86_64, - gpr_rsi_x86_64, - gpr_rbp_x86_64, - gpr_rsp_x86_64, - gpr_r8_x86_64, - gpr_r9_x86_64, - gpr_r10_x86_64, - gpr_r11_x86_64, - gpr_r12_x86_64, - gpr_r13_x86_64, - gpr_r14_x86_64, - gpr_r15_x86_64, - gpr_rip_x86_64, - gpr_rflags_x86_64, - gpr_cs_x86_64, - gpr_fs_x86_64, - gpr_gs_x86_64, - gpr_ss_x86_64, - gpr_ds_x86_64, - gpr_es_x86_64, - gpr_eax_x86_64, - gpr_ebx_x86_64, - gpr_ecx_x86_64, - gpr_edx_x86_64, - gpr_edi_x86_64, - gpr_esi_x86_64, - gpr_ebp_x86_64, - gpr_esp_x86_64, - gpr_r8d_x86_64, // Low 32 bits or r8 - gpr_r9d_x86_64, // Low 32 bits or r9 - gpr_r10d_x86_64, // Low 32 bits or r10 - gpr_r11d_x86_64, // Low 32 bits or r11 - gpr_r12d_x86_64, // Low 32 bits or r12 - gpr_r13d_x86_64, // Low 32 bits or r13 - gpr_r14d_x86_64, // Low 32 bits or r14 - gpr_r15d_x86_64, // Low 32 bits or r15 - gpr_ax_x86_64, - gpr_bx_x86_64, - gpr_cx_x86_64, - gpr_dx_x86_64, - gpr_di_x86_64, - gpr_si_x86_64, - gpr_bp_x86_64, - gpr_sp_x86_64, - gpr_r8w_x86_64, // Low 16 bits or r8 - gpr_r9w_x86_64, // Low 16 bits or r9 - gpr_r10w_x86_64, // Low 16 bits or r10 - gpr_r11w_x86_64, // Low 16 bits or r11 - gpr_r12w_x86_64, // Low 16 bits or r12 - gpr_r13w_x86_64, // Low 16 bits or r13 - gpr_r14w_x86_64, // Low 16 bits or r14 - gpr_r15w_x86_64, // Low 16 bits or r15 - gpr_ah_x86_64, - gpr_bh_x86_64, - gpr_ch_x86_64, - gpr_dh_x86_64, - gpr_al_x86_64, - gpr_bl_x86_64, - gpr_cl_x86_64, - gpr_dl_x86_64, - gpr_dil_x86_64, - gpr_sil_x86_64, - gpr_bpl_x86_64, - gpr_spl_x86_64, - gpr_r8l_x86_64, // Low 8 bits or r8 - gpr_r9l_x86_64, // Low 8 bits or r9 - gpr_r10l_x86_64, // Low 8 bits or r10 - gpr_r11l_x86_64, // Low 8 bits or r11 - gpr_r12l_x86_64, // Low 8 bits or r12 - gpr_r13l_x86_64, // Low 8 bits or r13 - gpr_r14l_x86_64, // Low 8 bits or r14 - gpr_r15l_x86_64, // Low 8 bits or r15 + lldb_rax_x86_64, + lldb_rbx_x86_64, + lldb_rcx_x86_64, + lldb_rdx_x86_64, + lldb_rdi_x86_64, + lldb_rsi_x86_64, + lldb_rbp_x86_64, + lldb_rsp_x86_64, + lldb_r8_x86_64, + lldb_r9_x86_64, + lldb_r10_x86_64, + lldb_r11_x86_64, + lldb_r12_x86_64, + lldb_r13_x86_64, + lldb_r14_x86_64, + lldb_r15_x86_64, + lldb_rip_x86_64, + lldb_rflags_x86_64, + lldb_cs_x86_64, + lldb_fs_x86_64, + lldb_gs_x86_64, + lldb_ss_x86_64, + lldb_ds_x86_64, + lldb_es_x86_64, + lldb_eax_x86_64, + lldb_ebx_x86_64, + lldb_ecx_x86_64, + lldb_edx_x86_64, + lldb_edi_x86_64, + lldb_esi_x86_64, + lldb_ebp_x86_64, + lldb_esp_x86_64, + lldb_r8d_x86_64, // Low 32 bits or r8 + lldb_r9d_x86_64, // Low 32 bits or r9 + lldb_r10d_x86_64, // Low 32 bits or r10 + lldb_r11d_x86_64, // Low 32 bits or r11 + lldb_r12d_x86_64, // Low 32 bits or r12 + lldb_r13d_x86_64, // Low 32 bits or r13 + lldb_r14d_x86_64, // Low 32 bits or r14 + lldb_r15d_x86_64, // Low 32 bits or r15 + lldb_ax_x86_64, + lldb_bx_x86_64, + lldb_cx_x86_64, + lldb_dx_x86_64, + lldb_di_x86_64, + lldb_si_x86_64, + lldb_bp_x86_64, + lldb_sp_x86_64, + lldb_r8w_x86_64, // Low 16 bits or r8 + lldb_r9w_x86_64, // Low 16 bits or r9 + lldb_r10w_x86_64, // Low 16 bits or r10 + lldb_r11w_x86_64, // Low 16 bits or r11 + lldb_r12w_x86_64, // Low 16 bits or r12 + lldb_r13w_x86_64, // Low 16 bits or r13 + lldb_r14w_x86_64, // Low 16 bits or r14 + lldb_r15w_x86_64, // Low 16 bits or r15 + lldb_ah_x86_64, + lldb_bh_x86_64, + lldb_ch_x86_64, + lldb_dh_x86_64, + lldb_al_x86_64, + lldb_bl_x86_64, + lldb_cl_x86_64, + lldb_dl_x86_64, + lldb_dil_x86_64, + lldb_sil_x86_64, + lldb_bpl_x86_64, + lldb_spl_x86_64, + lldb_r8l_x86_64, // Low 8 bits or r8 + lldb_r9l_x86_64, // Low 8 bits or r9 + lldb_r10l_x86_64, // Low 8 bits or r10 + lldb_r11l_x86_64, // Low 8 bits or r11 + lldb_r12l_x86_64, // Low 8 bits or r12 + lldb_r13l_x86_64, // Low 8 bits or r13 + lldb_r14l_x86_64, // Low 8 bits or r14 + lldb_r15l_x86_64, // Low 8 bits or r15 LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM. }; static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - 1 == k_num_gpr_registers_x86_64, "g_gpr_regnums_x86_64 has wrong number of register infos"); static const uint32_t -g_fpu_regnums_x86_64[] = -{ - fpu_fctrl_x86_64, - fpu_fstat_x86_64, - fpu_ftag_x86_64, - fpu_fop_x86_64, - fpu_fiseg_x86_64, - fpu_fioff_x86_64, - fpu_foseg_x86_64, - fpu_fooff_x86_64, - fpu_mxcsr_x86_64, - fpu_mxcsrmask_x86_64, - fpu_st0_x86_64, - fpu_st1_x86_64, - fpu_st2_x86_64, - fpu_st3_x86_64, - fpu_st4_x86_64, - fpu_st5_x86_64, - fpu_st6_x86_64, - fpu_st7_x86_64, - fpu_mm0_x86_64, - fpu_mm1_x86_64, - fpu_mm2_x86_64, - fpu_mm3_x86_64, - fpu_mm4_x86_64, - fpu_mm5_x86_64, - fpu_mm6_x86_64, - fpu_mm7_x86_64, - fpu_xmm0_x86_64, - fpu_xmm1_x86_64, - fpu_xmm2_x86_64, - fpu_xmm3_x86_64, - fpu_xmm4_x86_64, - fpu_xmm5_x86_64, - fpu_xmm6_x86_64, - fpu_xmm7_x86_64, - fpu_xmm8_x86_64, - fpu_xmm9_x86_64, - fpu_xmm10_x86_64, - fpu_xmm11_x86_64, - fpu_xmm12_x86_64, - fpu_xmm13_x86_64, - fpu_xmm14_x86_64, - fpu_xmm15_x86_64, +g_lldb_regnums_x86_64[] = +{ + lldb_fctrl_x86_64, + lldb_fstat_x86_64, + lldb_ftag_x86_64, + lldb_fop_x86_64, + lldb_fiseg_x86_64, + lldb_fioff_x86_64, + lldb_foseg_x86_64, + lldb_fooff_x86_64, + lldb_mxcsr_x86_64, + lldb_mxcsrmask_x86_64, + lldb_st0_x86_64, + lldb_st1_x86_64, + lldb_st2_x86_64, + lldb_st3_x86_64, + lldb_st4_x86_64, + lldb_st5_x86_64, + lldb_st6_x86_64, + lldb_st7_x86_64, + lldb_mm0_x86_64, + lldb_mm1_x86_64, + lldb_mm2_x86_64, + lldb_mm3_x86_64, + lldb_mm4_x86_64, + lldb_mm5_x86_64, + lldb_mm6_x86_64, + lldb_mm7_x86_64, + lldb_xmm0_x86_64, + lldb_xmm1_x86_64, + lldb_xmm2_x86_64, + lldb_xmm3_x86_64, + lldb_xmm4_x86_64, + lldb_xmm5_x86_64, + lldb_xmm6_x86_64, + lldb_xmm7_x86_64, + lldb_xmm8_x86_64, + lldb_xmm9_x86_64, + lldb_xmm10_x86_64, + lldb_xmm11_x86_64, + lldb_xmm12_x86_64, + lldb_xmm13_x86_64, + lldb_xmm14_x86_64, + lldb_xmm15_x86_64, LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM. }; -static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - 1 == k_num_fpr_registers_x86_64, - "g_fpu_regnums_x86_64 has wrong number of register infos"); +static_assert((sizeof(g_lldb_regnums_x86_64) / sizeof(g_lldb_regnums_x86_64[0])) - 1 == k_num_fpr_registers_x86_64, + "g_lldb_regnums_x86_64 has wrong number of register infos"); static const uint32_t g_avx_regnums_x86_64[] = { - fpu_ymm0_x86_64, - fpu_ymm1_x86_64, - fpu_ymm2_x86_64, - fpu_ymm3_x86_64, - fpu_ymm4_x86_64, - fpu_ymm5_x86_64, - fpu_ymm6_x86_64, - fpu_ymm7_x86_64, - fpu_ymm8_x86_64, - fpu_ymm9_x86_64, - fpu_ymm10_x86_64, - fpu_ymm11_x86_64, - fpu_ymm12_x86_64, - fpu_ymm13_x86_64, - fpu_ymm14_x86_64, - fpu_ymm15_x86_64, + lldb_ymm0_x86_64, + lldb_ymm1_x86_64, + lldb_ymm2_x86_64, + lldb_ymm3_x86_64, + lldb_ymm4_x86_64, + lldb_ymm5_x86_64, + lldb_ymm6_x86_64, + lldb_ymm7_x86_64, + lldb_ymm8_x86_64, + lldb_ymm9_x86_64, + lldb_ymm10_x86_64, + lldb_ymm11_x86_64, + lldb_ymm12_x86_64, + lldb_ymm13_x86_64, + lldb_ymm14_x86_64, + lldb_ymm15_x86_64, LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM. }; static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - 1 == k_num_avx_registers_x86_64, "g_avx_regnums_x86_64 has wrong number of register infos"); -uint32_t RegisterContextPOSIX_x86::g_contained_eax[] = { gpr_eax_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_ebx[] = { gpr_ebx_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_ecx[] = { gpr_ecx_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_edx[] = { gpr_edx_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_edi[] = { gpr_edi_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_esi[] = { gpr_esi_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_ebp[] = { gpr_ebp_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_esp[] = { gpr_esp_i386, LLDB_INVALID_REGNUM }; - -uint32_t RegisterContextPOSIX_x86::g_invalidate_eax[] = { gpr_eax_i386, gpr_ax_i386, gpr_ah_i386, gpr_al_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_ebx[] = { gpr_ebx_i386, gpr_bx_i386, gpr_bh_i386, gpr_bl_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_ecx[] = { gpr_ecx_i386, gpr_cx_i386, gpr_ch_i386, gpr_cl_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_edx[] = { gpr_edx_i386, gpr_dx_i386, gpr_dh_i386, gpr_dl_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_edi[] = { gpr_edi_i386, gpr_di_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_esi[] = { gpr_esi_i386, gpr_si_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_ebp[] = { gpr_ebp_i386, gpr_bp_i386, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_esp[] = { gpr_esp_i386, gpr_sp_i386, LLDB_INVALID_REGNUM }; - -uint32_t RegisterContextPOSIX_x86::g_contained_rax[] = { gpr_rax_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_rbx[] = { gpr_rbx_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_rcx[] = { gpr_rcx_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_rdx[] = { gpr_rdx_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_rdi[] = { gpr_rdi_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_rsi[] = { gpr_rsi_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_rbp[] = { gpr_rbp_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_rsp[] = { gpr_rsp_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_r8[] = { gpr_r8_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_r9[] = { gpr_r9_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_r10[] = { gpr_r10_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_r11[] = { gpr_r11_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_r12[] = { gpr_r12_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_r13[] = { gpr_r13_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_r14[] = { gpr_r14_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_contained_r15[] = { gpr_r15_x86_64, LLDB_INVALID_REGNUM }; - -uint32_t RegisterContextPOSIX_x86::g_invalidate_rax[] = { gpr_rax_x86_64, gpr_eax_x86_64, gpr_ax_x86_64, gpr_ah_x86_64, gpr_al_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_rbx[] = { gpr_rbx_x86_64, gpr_ebx_x86_64, gpr_bx_x86_64, gpr_bh_x86_64, gpr_bl_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_rcx[] = { gpr_rcx_x86_64, gpr_ecx_x86_64, gpr_cx_x86_64, gpr_ch_x86_64, gpr_cl_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_rdx[] = { gpr_rdx_x86_64, gpr_edx_x86_64, gpr_dx_x86_64, gpr_dh_x86_64, gpr_dl_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_rdi[] = { gpr_rdi_x86_64, gpr_edi_x86_64, gpr_di_x86_64, gpr_dil_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_rsi[] = { gpr_rsi_x86_64, gpr_esi_x86_64, gpr_si_x86_64, gpr_sil_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_rbp[] = { gpr_rbp_x86_64, gpr_ebp_x86_64, gpr_bp_x86_64, gpr_bpl_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_rsp[] = { gpr_rsp_x86_64, gpr_esp_x86_64, gpr_sp_x86_64, gpr_spl_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_r8[] = { gpr_r8_x86_64, gpr_r8d_x86_64, gpr_r8w_x86_64, gpr_r8l_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_r9[] = { gpr_r9_x86_64, gpr_r9d_x86_64, gpr_r9w_x86_64, gpr_r9l_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_r10[] = { gpr_r10_x86_64, gpr_r10d_x86_64, gpr_r10w_x86_64, gpr_r10l_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_r11[] = { gpr_r11_x86_64, gpr_r11d_x86_64, gpr_r11w_x86_64, gpr_r11l_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_r12[] = { gpr_r12_x86_64, gpr_r12d_x86_64, gpr_r12w_x86_64, gpr_r12l_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_r13[] = { gpr_r13_x86_64, gpr_r13d_x86_64, gpr_r13w_x86_64, gpr_r13l_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_r14[] = { gpr_r14_x86_64, gpr_r14d_x86_64, gpr_r14w_x86_64, gpr_r14l_x86_64, LLDB_INVALID_REGNUM }; -uint32_t RegisterContextPOSIX_x86::g_invalidate_r15[] = { gpr_r15_x86_64, gpr_r15d_x86_64, gpr_r15w_x86_64, gpr_r15l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_eax[] = { lldb_eax_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_ebx[] = { lldb_ebx_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_ecx[] = { lldb_ecx_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_edx[] = { lldb_edx_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_edi[] = { lldb_edi_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_esi[] = { lldb_esi_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_ebp[] = { lldb_ebp_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_esp[] = { lldb_esp_i386, LLDB_INVALID_REGNUM }; + +uint32_t RegisterContextPOSIX_x86::g_invalidate_eax[] = { lldb_eax_i386, lldb_ax_i386, lldb_ah_i386, lldb_al_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_ebx[] = { lldb_ebx_i386, lldb_bx_i386, lldb_bh_i386, lldb_bl_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_ecx[] = { lldb_ecx_i386, lldb_cx_i386, lldb_ch_i386, lldb_cl_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_edx[] = { lldb_edx_i386, lldb_dx_i386, lldb_dh_i386, lldb_dl_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_edi[] = { lldb_edi_i386, lldb_di_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_esi[] = { lldb_esi_i386, lldb_si_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_ebp[] = { lldb_ebp_i386, lldb_bp_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_esp[] = { lldb_esp_i386, lldb_sp_i386, LLDB_INVALID_REGNUM }; + +uint32_t RegisterContextPOSIX_x86::g_contained_rax[] = { lldb_rax_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rbx[] = { lldb_rbx_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rcx[] = { lldb_rcx_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rdx[] = { lldb_rdx_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rdi[] = { lldb_rdi_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rsi[] = { lldb_rsi_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rbp[] = { lldb_rbp_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rsp[] = { lldb_rsp_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r8[] = { lldb_r8_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r9[] = { lldb_r9_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r10[] = { lldb_r10_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r11[] = { lldb_r11_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r12[] = { lldb_r12_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r13[] = { lldb_r13_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r14[] = { lldb_r14_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r15[] = { lldb_r15_x86_64, LLDB_INVALID_REGNUM }; + +uint32_t RegisterContextPOSIX_x86::g_invalidate_rax[] = { lldb_rax_x86_64, lldb_eax_x86_64, lldb_ax_x86_64, lldb_ah_x86_64, lldb_al_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rbx[] = { lldb_rbx_x86_64, lldb_ebx_x86_64, lldb_bx_x86_64, lldb_bh_x86_64, lldb_bl_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rcx[] = { lldb_rcx_x86_64, lldb_ecx_x86_64, lldb_cx_x86_64, lldb_ch_x86_64, lldb_cl_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rdx[] = { lldb_rdx_x86_64, lldb_edx_x86_64, lldb_dx_x86_64, lldb_dh_x86_64, lldb_dl_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rdi[] = { lldb_rdi_x86_64, lldb_edi_x86_64, lldb_di_x86_64, lldb_dil_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rsi[] = { lldb_rsi_x86_64, lldb_esi_x86_64, lldb_si_x86_64, lldb_sil_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rbp[] = { lldb_rbp_x86_64, lldb_ebp_x86_64, lldb_bp_x86_64, lldb_bpl_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rsp[] = { lldb_rsp_x86_64, lldb_esp_x86_64, lldb_sp_x86_64, lldb_spl_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r8[] = { lldb_r8_x86_64, lldb_r8d_x86_64, lldb_r8w_x86_64, lldb_r8l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r9[] = { lldb_r9_x86_64, lldb_r9d_x86_64, lldb_r9w_x86_64, lldb_r9l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r10[] = { lldb_r10_x86_64, lldb_r10d_x86_64, lldb_r10w_x86_64, lldb_r10l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r11[] = { lldb_r11_x86_64, lldb_r11d_x86_64, lldb_r11w_x86_64, lldb_r11l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r12[] = { lldb_r12_x86_64, lldb_r12d_x86_64, lldb_r12w_x86_64, lldb_r12l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r13[] = { lldb_r13_x86_64, lldb_r13d_x86_64, lldb_r13w_x86_64, lldb_r13l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r14[] = { lldb_r14_x86_64, lldb_r14d_x86_64, lldb_r14w_x86_64, lldb_r14l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r15[] = { lldb_r15_x86_64, lldb_r15d_x86_64, lldb_r15w_x86_64, lldb_r15l_x86_64, LLDB_INVALID_REGNUM }; // Number of register sets provided by this context. enum @@ -346,7 +346,7 @@ static const RegisterSet g_reg_sets_i386[k_num_register_sets] = { { "General Purpose Registers", "gpr", k_num_gpr_registers_i386, g_gpr_regnums_i386 }, - { "Floating Point Registers", "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386 }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_i386, g_lldb_regnums_i386 }, { "Advanced Vector Extensions", "avx", k_num_avx_registers_i386, g_avx_regnums_i386 } }; @@ -354,7 +354,7 @@ static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { { "General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64 }, - { "Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64 }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, g_lldb_regnums_x86_64 }, { "Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, g_avx_regnums_x86_64 } }; @@ -399,16 +399,16 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread, m_reg_info.last_gpr = k_last_gpr_i386; m_reg_info.first_fpr = k_first_fpr_i386; m_reg_info.last_fpr = k_last_fpr_i386; - m_reg_info.first_st = fpu_st0_i386; - m_reg_info.last_st = fpu_st7_i386; - m_reg_info.first_mm = fpu_mm0_i386; - m_reg_info.last_mm = fpu_mm7_i386; - m_reg_info.first_xmm = fpu_xmm0_i386; - m_reg_info.last_xmm = fpu_xmm7_i386; - m_reg_info.first_ymm = fpu_ymm0_i386; - m_reg_info.last_ymm = fpu_ymm7_i386; - m_reg_info.first_dr = dr0_i386; - m_reg_info.gpr_flags = gpr_eflags_i386; + m_reg_info.first_st = lldb_st0_i386; + m_reg_info.last_st = lldb_st7_i386; + m_reg_info.first_mm = lldb_mm0_i386; + m_reg_info.last_mm = lldb_mm7_i386; + m_reg_info.first_xmm = lldb_xmm0_i386; + m_reg_info.last_xmm = lldb_xmm7_i386; + m_reg_info.first_ymm = lldb_ymm0_i386; + m_reg_info.last_ymm = lldb_ymm7_i386; + m_reg_info.first_dr = lldb_dr0_i386; + m_reg_info.gpr_flags = lldb_eflags_i386; break; case llvm::Triple::x86_64: m_reg_info.num_registers = k_num_registers_x86_64; @@ -418,16 +418,16 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread, m_reg_info.last_gpr = k_last_gpr_x86_64; m_reg_info.first_fpr = k_first_fpr_x86_64; m_reg_info.last_fpr = k_last_fpr_x86_64; - m_reg_info.first_st = fpu_st0_x86_64; - m_reg_info.last_st = fpu_st7_x86_64; - m_reg_info.first_mm = fpu_mm0_x86_64; - m_reg_info.last_mm = fpu_mm7_x86_64; - m_reg_info.first_xmm = fpu_xmm0_x86_64; - m_reg_info.last_xmm = fpu_xmm15_x86_64; - m_reg_info.first_ymm = fpu_ymm0_x86_64; - m_reg_info.last_ymm = fpu_ymm15_x86_64; - m_reg_info.first_dr = dr0_x86_64; - m_reg_info.gpr_flags = gpr_rflags_x86_64; + m_reg_info.first_st = lldb_st0_x86_64; + m_reg_info.last_st = lldb_st7_x86_64; + m_reg_info.first_mm = lldb_mm0_x86_64; + m_reg_info.last_mm = lldb_mm7_x86_64; + m_reg_info.first_xmm = lldb_xmm0_x86_64; + m_reg_info.last_xmm = lldb_xmm15_x86_64; + m_reg_info.first_ymm = lldb_ymm0_x86_64; + m_reg_info.last_ymm = lldb_ymm15_x86_64; + m_reg_info.first_dr = lldb_dr0_x86_64; + m_reg_info.gpr_flags = lldb_rflags_x86_64; break; default: assert(false && "Unhandled target architecture."); diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h index 4db7802e1b442..0eec1d909c1ac 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h @@ -11,285 +11,12 @@ #define liblldb_RegisterContextPOSIX_x86_H_ #include "lldb/Core/Log.h" +#include "lldb-x86-register-enums.h" #include "RegisterContextPOSIX.h" #include "RegisterContext_x86.h" class ProcessMonitor; -//--------------------------------------------------------------------------- -// Internal codes for all i386 registers. -//--------------------------------------------------------------------------- -enum -{ - k_first_gpr_i386, - gpr_eax_i386 = k_first_gpr_i386, - gpr_ebx_i386, - gpr_ecx_i386, - gpr_edx_i386, - gpr_edi_i386, - gpr_esi_i386, - gpr_ebp_i386, - gpr_esp_i386, - gpr_eip_i386, - gpr_eflags_i386, - gpr_cs_i386, - gpr_fs_i386, - gpr_gs_i386, - gpr_ss_i386, - gpr_ds_i386, - gpr_es_i386, - - k_first_alias_i386, - gpr_ax_i386 = k_first_alias_i386, - gpr_bx_i386, - gpr_cx_i386, - gpr_dx_i386, - gpr_di_i386, - gpr_si_i386, - gpr_bp_i386, - gpr_sp_i386, - gpr_ah_i386, - gpr_bh_i386, - gpr_ch_i386, - gpr_dh_i386, - gpr_al_i386, - gpr_bl_i386, - gpr_cl_i386, - gpr_dl_i386, - k_last_alias_i386 = gpr_dl_i386, - - k_last_gpr_i386 = k_last_alias_i386, - - k_first_fpr_i386, - fpu_fctrl_i386 = k_first_fpr_i386, - fpu_fstat_i386, - fpu_ftag_i386, - fpu_fop_i386, - fpu_fiseg_i386, - fpu_fioff_i386, - fpu_foseg_i386, - fpu_fooff_i386, - fpu_mxcsr_i386, - fpu_mxcsrmask_i386, - fpu_st0_i386, - fpu_st1_i386, - fpu_st2_i386, - fpu_st3_i386, - fpu_st4_i386, - fpu_st5_i386, - fpu_st6_i386, - fpu_st7_i386, - fpu_mm0_i386, - fpu_mm1_i386, - fpu_mm2_i386, - fpu_mm3_i386, - fpu_mm4_i386, - fpu_mm5_i386, - fpu_mm6_i386, - fpu_mm7_i386, - fpu_xmm0_i386, - fpu_xmm1_i386, - fpu_xmm2_i386, - fpu_xmm3_i386, - fpu_xmm4_i386, - fpu_xmm5_i386, - fpu_xmm6_i386, - fpu_xmm7_i386, - k_last_fpr_i386 = fpu_xmm7_i386, - - k_first_avx_i386, - fpu_ymm0_i386 = k_first_avx_i386, - fpu_ymm1_i386, - fpu_ymm2_i386, - fpu_ymm3_i386, - fpu_ymm4_i386, - fpu_ymm5_i386, - fpu_ymm6_i386, - fpu_ymm7_i386, - k_last_avx_i386 = fpu_ymm7_i386, - - dr0_i386, - dr1_i386, - dr2_i386, - dr3_i386, - dr4_i386, - dr5_i386, - dr6_i386, - dr7_i386, - - k_num_registers_i386, - k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1, - k_num_fpr_registers_i386 = k_last_fpr_i386 - k_first_fpr_i386 + 1, - k_num_avx_registers_i386 = k_last_avx_i386 - k_first_avx_i386 + 1 -}; - -//--------------------------------------------------------------------------- -// Internal codes for all x86_64 registers. -//--------------------------------------------------------------------------- -enum -{ - k_first_gpr_x86_64, - gpr_rax_x86_64 = k_first_gpr_x86_64, - gpr_rbx_x86_64, - gpr_rcx_x86_64, - gpr_rdx_x86_64, - gpr_rdi_x86_64, - gpr_rsi_x86_64, - gpr_rbp_x86_64, - gpr_rsp_x86_64, - gpr_r8_x86_64, - gpr_r9_x86_64, - gpr_r10_x86_64, - gpr_r11_x86_64, - gpr_r12_x86_64, - gpr_r13_x86_64, - gpr_r14_x86_64, - gpr_r15_x86_64, - gpr_rip_x86_64, - gpr_rflags_x86_64, - gpr_cs_x86_64, - gpr_fs_x86_64, - gpr_gs_x86_64, - gpr_ss_x86_64, - gpr_ds_x86_64, - gpr_es_x86_64, - - k_first_alias_x86_64, - gpr_eax_x86_64 = k_first_alias_x86_64, - gpr_ebx_x86_64, - gpr_ecx_x86_64, - gpr_edx_x86_64, - gpr_edi_x86_64, - gpr_esi_x86_64, - gpr_ebp_x86_64, - gpr_esp_x86_64, - gpr_r8d_x86_64, // Low 32 bits of r8 - gpr_r9d_x86_64, // Low 32 bits of r9 - gpr_r10d_x86_64, // Low 32 bits of r10 - gpr_r11d_x86_64, // Low 32 bits of r11 - gpr_r12d_x86_64, // Low 32 bits of r12 - gpr_r13d_x86_64, // Low 32 bits of r13 - gpr_r14d_x86_64, // Low 32 bits of r14 - gpr_r15d_x86_64, // Low 32 bits of r15 - gpr_ax_x86_64, - gpr_bx_x86_64, - gpr_cx_x86_64, - gpr_dx_x86_64, - gpr_di_x86_64, - gpr_si_x86_64, - gpr_bp_x86_64, - gpr_sp_x86_64, - gpr_r8w_x86_64, // Low 16 bits of r8 - gpr_r9w_x86_64, // Low 16 bits of r9 - gpr_r10w_x86_64, // Low 16 bits of r10 - gpr_r11w_x86_64, // Low 16 bits of r11 - gpr_r12w_x86_64, // Low 16 bits of r12 - gpr_r13w_x86_64, // Low 16 bits of r13 - gpr_r14w_x86_64, // Low 16 bits of r14 - gpr_r15w_x86_64, // Low 16 bits of r15 - gpr_ah_x86_64, - gpr_bh_x86_64, - gpr_ch_x86_64, - gpr_dh_x86_64, - gpr_al_x86_64, - gpr_bl_x86_64, - gpr_cl_x86_64, - gpr_dl_x86_64, - gpr_dil_x86_64, - gpr_sil_x86_64, - gpr_bpl_x86_64, - gpr_spl_x86_64, - gpr_r8l_x86_64, // Low 8 bits of r8 - gpr_r9l_x86_64, // Low 8 bits of r9 - gpr_r10l_x86_64, // Low 8 bits of r10 - gpr_r11l_x86_64, // Low 8 bits of r11 - gpr_r12l_x86_64, // Low 8 bits of r12 - gpr_r13l_x86_64, // Low 8 bits of r13 - gpr_r14l_x86_64, // Low 8 bits of r14 - gpr_r15l_x86_64, // Low 8 bits of r15 - k_last_alias_x86_64 = gpr_r15l_x86_64, - - k_last_gpr_x86_64 = k_last_alias_x86_64, - - k_first_fpr_x86_64, - fpu_fctrl_x86_64 = k_first_fpr_x86_64, - fpu_fstat_x86_64, - fpu_ftag_x86_64, - fpu_fop_x86_64, - fpu_fiseg_x86_64, - fpu_fioff_x86_64, - fpu_foseg_x86_64, - fpu_fooff_x86_64, - fpu_mxcsr_x86_64, - fpu_mxcsrmask_x86_64, - fpu_st0_x86_64, - fpu_st1_x86_64, - fpu_st2_x86_64, - fpu_st3_x86_64, - fpu_st4_x86_64, - fpu_st5_x86_64, - fpu_st6_x86_64, - fpu_st7_x86_64, - fpu_mm0_x86_64, - fpu_mm1_x86_64, - fpu_mm2_x86_64, - fpu_mm3_x86_64, - fpu_mm4_x86_64, - fpu_mm5_x86_64, - fpu_mm6_x86_64, - fpu_mm7_x86_64, - fpu_xmm0_x86_64, - fpu_xmm1_x86_64, - fpu_xmm2_x86_64, - fpu_xmm3_x86_64, - fpu_xmm4_x86_64, - fpu_xmm5_x86_64, - fpu_xmm6_x86_64, - fpu_xmm7_x86_64, - fpu_xmm8_x86_64, - fpu_xmm9_x86_64, - fpu_xmm10_x86_64, - fpu_xmm11_x86_64, - fpu_xmm12_x86_64, - fpu_xmm13_x86_64, - fpu_xmm14_x86_64, - fpu_xmm15_x86_64, - k_last_fpr_x86_64 = fpu_xmm15_x86_64, - - k_first_avx_x86_64, - fpu_ymm0_x86_64 = k_first_avx_x86_64, - fpu_ymm1_x86_64, - fpu_ymm2_x86_64, - fpu_ymm3_x86_64, - fpu_ymm4_x86_64, - fpu_ymm5_x86_64, - fpu_ymm6_x86_64, - fpu_ymm7_x86_64, - fpu_ymm8_x86_64, - fpu_ymm9_x86_64, - fpu_ymm10_x86_64, - fpu_ymm11_x86_64, - fpu_ymm12_x86_64, - fpu_ymm13_x86_64, - fpu_ymm14_x86_64, - fpu_ymm15_x86_64, - k_last_avx_x86_64 = fpu_ymm15_x86_64, - - dr0_x86_64, - dr1_x86_64, - dr2_x86_64, - dr3_x86_64, - dr4_x86_64, - dr5_x86_64, - dr6_x86_64, - dr7_x86_64, - - k_num_registers_x86_64, - k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1, - k_num_fpr_registers_x86_64 = k_last_fpr_x86_64 - k_first_fpr_x86_64 + 1, - k_num_avx_registers_x86_64 = k_last_avx_x86_64 - k_first_avx_x86_64 + 1 -}; - class RegisterContextPOSIX_x86 : public lldb_private::RegisterContext { @@ -422,7 +149,7 @@ protected: uint32_t gpr_flags; }; - uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64]; // 64-bit general purpose registers. + uint64_t m_gpr_x86_64[lldb_private::k_num_gpr_registers_x86_64]; // 64-bit general purpose registers. RegInfo m_reg_info; FPRType m_fpr_type; // determines the type of data stored by union FPR, if any. FPR m_fpr; // floating-point registers including extended register sets. diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp index 46dafa11d8f71..200ef4d3d651c 100644 --- a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp +++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp @@ -59,7 +59,7 @@ RegisterContextThreadMemory::UpdateRegisterContext () { OperatingSystem *os = process_sp->GetOperatingSystem (); if (os->IsOperatingSystemPluginThread (thread_sp)) - m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), LLDB_INVALID_ADDRESS); + m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), m_register_data_addr); } } } diff --git a/source/Plugins/Process/Utility/RegisterContext_powerpc.h b/source/Plugins/Process/Utility/RegisterContext_powerpc.h new file mode 100644 index 0000000000000..cf54cc0c2145b --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContext_powerpc.h @@ -0,0 +1,163 @@ +//===-- RegisterContext_powerpc.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_RegisterContext_powerpc_H_ +#define liblldb_RegisterContext_powerpc_H_ + +// GCC and DWARF Register numbers (eRegisterKindGCC & eRegisterKindDWARF) +enum +{ + gcc_dwarf_r0_powerpc = 0, + gcc_dwarf_r1_powerpc, + gcc_dwarf_r2_powerpc, + gcc_dwarf_r3_powerpc, + gcc_dwarf_r4_powerpc, + gcc_dwarf_r5_powerpc, + gcc_dwarf_r6_powerpc, + gcc_dwarf_r7_powerpc, + gcc_dwarf_r8_powerpc, + gcc_dwarf_r9_powerpc, + gcc_dwarf_r10_powerpc, + gcc_dwarf_r11_powerpc, + gcc_dwarf_r12_powerpc, + gcc_dwarf_r13_powerpc, + gcc_dwarf_r14_powerpc, + gcc_dwarf_r15_powerpc, + gcc_dwarf_r16_powerpc, + gcc_dwarf_r17_powerpc, + gcc_dwarf_r18_powerpc, + gcc_dwarf_r19_powerpc, + gcc_dwarf_r20_powerpc, + gcc_dwarf_r21_powerpc, + gcc_dwarf_r22_powerpc, + gcc_dwarf_r23_powerpc, + gcc_dwarf_r24_powerpc, + gcc_dwarf_r25_powerpc, + gcc_dwarf_r26_powerpc, + gcc_dwarf_r27_powerpc, + gcc_dwarf_r28_powerpc, + gcc_dwarf_r29_powerpc, + gcc_dwarf_r30_powerpc, + gcc_dwarf_r31_powerpc, + gcc_dwarf_f0_powerpc, + gcc_dwarf_f1_powerpc, + gcc_dwarf_f2_powerpc, + gcc_dwarf_f3_powerpc, + gcc_dwarf_f4_powerpc, + gcc_dwarf_f5_powerpc, + gcc_dwarf_f6_powerpc, + gcc_dwarf_f7_powerpc, + gcc_dwarf_f8_powerpc, + gcc_dwarf_f9_powerpc, + gcc_dwarf_f10_powerpc, + gcc_dwarf_f11_powerpc, + gcc_dwarf_f12_powerpc, + gcc_dwarf_f13_powerpc, + gcc_dwarf_f14_powerpc, + gcc_dwarf_f15_powerpc, + gcc_dwarf_f16_powerpc, + gcc_dwarf_f17_powerpc, + gcc_dwarf_f18_powerpc, + gcc_dwarf_f19_powerpc, + gcc_dwarf_f20_powerpc, + gcc_dwarf_f21_powerpc, + gcc_dwarf_f22_powerpc, + gcc_dwarf_f23_powerpc, + gcc_dwarf_f24_powerpc, + gcc_dwarf_f25_powerpc, + gcc_dwarf_f26_powerpc, + gcc_dwarf_f27_powerpc, + gcc_dwarf_f28_powerpc, + gcc_dwarf_f29_powerpc, + gcc_dwarf_f30_powerpc, + gcc_dwarf_f31_powerpc, + gcc_dwarf_cr_powerpc, + gcc_dwarf_fpscr_powerpc, + gcc_dwarf_xer_powerpc = 101, + gcc_dwarf_lr_powerpc = 108, + gcc_dwarf_ctr_powerpc, + gcc_dwarf_pc_powerpc, +}; + +// GDB Register numbers (eRegisterKindGDB) +enum +{ + gdb_r0_powerpc = 0, + gdb_r1_powerpc, + gdb_r2_powerpc, + gdb_r3_powerpc, + gdb_r4_powerpc, + gdb_r5_powerpc, + gdb_r6_powerpc, + gdb_r7_powerpc, + gdb_r8_powerpc, + gdb_r9_powerpc, + gdb_r10_powerpc, + gdb_r11_powerpc, + gdb_r12_powerpc, + gdb_r13_powerpc, + gdb_r14_powerpc, + gdb_r15_powerpc, + gdb_r16_powerpc, + gdb_r17_powerpc, + gdb_r18_powerpc, + gdb_r19_powerpc, + gdb_r20_powerpc, + gdb_r21_powerpc, + gdb_r22_powerpc, + gdb_r23_powerpc, + gdb_r24_powerpc, + gdb_r25_powerpc, + gdb_r26_powerpc, + gdb_r27_powerpc, + gdb_r28_powerpc, + gdb_r29_powerpc, + gdb_r30_powerpc, + gdb_r31_powerpc, + gdb_f0_powerpc, + gdb_f1_powerpc, + gdb_f2_powerpc, + gdb_f3_powerpc, + gdb_f4_powerpc, + gdb_f5_powerpc, + gdb_f6_powerpc, + gdb_f7_powerpc, + gdb_f8_powerpc, + gdb_f9_powerpc, + gdb_f10_powerpc, + gdb_f11_powerpc, + gdb_f12_powerpc, + gdb_f13_powerpc, + gdb_f14_powerpc, + gdb_f15_powerpc, + gdb_f16_powerpc, + gdb_f17_powerpc, + gdb_f18_powerpc, + gdb_f19_powerpc, + gdb_f20_powerpc, + gdb_f21_powerpc, + gdb_f22_powerpc, + gdb_f23_powerpc, + gdb_f24_powerpc, + gdb_f25_powerpc, + gdb_f26_powerpc, + gdb_f27_powerpc, + gdb_f28_powerpc, + gdb_f29_powerpc, + gdb_f30_powerpc, + gdb_f31_powerpc, + gdb_cr_powerpc, + gdb_fpscr_powerpc, + gdb_xer_powerpc = 101, + gdb_lr_powerpc = 108, + gdb_ctr_powerpc, + gdb_pc_powerpc, +}; + +#endif // liblldb_RegisterContext_powerpc_H_ diff --git a/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/source/Plugins/Process/Utility/RegisterInfos_arm64.h index 1bb4e89c8f78a..b687423622a47 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_arm64.h +++ b/source/Plugins/Process/Utility/RegisterInfos_arm64.h @@ -15,8 +15,8 @@ #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" -#include "ARM64_GCC_Registers.h" -#include "ARM64_DWARF_Registers.h" +#include "Utility/ARM64_GCC_Registers.h" +#include "Utility/ARM64_DWARF_Registers.h" #ifndef GPR_OFFSET #error GPR_OFFSET must be defined before including this header file diff --git a/source/Plugins/Process/Utility/RegisterInfos_i386.h b/source/Plugins/Process/Utility/RegisterInfos_i386.h index fa152b4147ced..fc94b8b2a738e 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_i386.h +++ b/source/Plugins/Process/Utility/RegisterInfos_i386.h @@ -42,37 +42,37 @@ // Note that the size and offset will be updated by platform-specific classes. #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_i386 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, lldb_##reg##_i386 }, NULL, NULL } #define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ { #name, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, fpu_##name##_i386 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, lldb_##name##_i386 }, NULL, NULL } // RegisterKind: GCC, DWARF, Generic, GDB, LLDB #define DEFINE_FP_ST(reg, i) \ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ eEncodingVector, eFormatVectorOfUInt8, \ - { gcc_st##i##_i386, dwarf_st##i##_i386, LLDB_INVALID_REGNUM, gdb_st##i##_i386, fpu_st##i##_i386 }, \ + { gcc_st##i##_i386, dwarf_st##i##_i386, LLDB_INVALID_REGNUM, gdb_st##i##_i386, lldb_st##i##_i386 }, \ NULL, NULL } #define DEFINE_FP_MM(reg, i) \ { #reg#i, NULL, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ eEncodingUint, eFormatHex, \ - { gcc_mm##i##_i386, dwarf_mm##i##_i386, LLDB_INVALID_REGNUM, gdb_mm##i##_i386, fpu_mm##i##_i386 }, \ + { gcc_mm##i##_i386, dwarf_mm##i##_i386, LLDB_INVALID_REGNUM, gdb_mm##i##_i386, lldb_mm##i##_i386 }, \ NULL, NULL } #define DEFINE_XMM(reg, i) \ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \ eEncodingVector, eFormatVectorOfUInt8, \ - { gcc_##reg##i##_i386, dwarf_##reg##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##_i386, fpu_##reg##i##_i386}, \ + { gcc_##reg##i##_i386, dwarf_##reg##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##_i386, lldb_##reg##i##_i386}, \ NULL, NULL } // I believe the YMM registers use dwarf_xmm_%_i386 register numbers and then differentiate based on register size. #define DEFINE_YMM(reg, i) \ { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \ eEncodingVector, eFormatVectorOfUInt8, \ - { LLDB_INVALID_REGNUM, dwarf_xmm##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##h_i386, fpu_##reg##i##_i386 }, \ + { LLDB_INVALID_REGNUM, dwarf_xmm##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##h_i386, lldb_##reg##i##_i386 }, \ NULL, NULL } #define DEFINE_DR(reg, i) \ @@ -82,13 +82,13 @@ #define DEFINE_GPR_PSEUDO_16(reg16, reg32) \ { #reg16, NULL, 2, GPR_OFFSET(reg32), eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg16##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg16##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } #define DEFINE_GPR_PSEUDO_8H(reg8, reg32) \ { #reg8, NULL, 1, GPR_OFFSET(reg32)+1, eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } #define DEFINE_GPR_PSEUDO_8L(reg8, reg32) \ { #reg8, NULL, 1, GPR_OFFSET(reg32), eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } static RegisterInfo g_register_infos_i386[] = diff --git a/source/Plugins/Process/Utility/RegisterInfos_powerpc.h b/source/Plugins/Process/Utility/RegisterInfos_powerpc.h new file mode 100644 index 0000000000000..045426648105b --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterInfos_powerpc.h @@ -0,0 +1,144 @@ +//===-- RegisterInfos_powerpc.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include <stddef.h> + +// Computes the offset of the given GPR in the user data area. +#define GPR_OFFSET(regname) \ + (offsetof(GPR, regname)) +#define FPR_OFFSET(regname) \ + (offsetof(FPR, regname)) +#define GPR_SIZE(regname) \ + (sizeof(((GPR*)NULL)->regname)) + +#ifdef DECLARE_REGISTER_INFOS_POWERPC_STRUCT + +// Note that the size and offset will be updated by platform-specific classes. +#define DEFINE_GPR(reg, alt, lldb_kind) \ + { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \ + eFormatHex, { gcc_dwarf_##reg##_powerpc, gcc_dwarf_##reg##_powerpc, lldb_kind, gdb_##reg##_powerpc, gpr_##reg##_powerpc }, NULL, NULL } +#define DEFINE_FPR(reg, lldb_kind) \ + { #reg, NULL, 8, FPR_OFFSET(reg), eEncodingIEEE754, \ + eFormatFloat, { gcc_dwarf_##reg##_powerpc, gcc_dwarf_##reg##_powerpc, lldb_kind, gdb_##reg##_powerpc, fpr_##reg##_powerpc }, NULL, NULL } + + // General purpose registers. GCC, DWARF, Generic, GDB +#define POWERPC_REGS \ + DEFINE_GPR(r0, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r1, "sp", LLDB_REGNUM_GENERIC_SP), \ + DEFINE_GPR(r2, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r3, "arg1",LLDB_REGNUM_GENERIC_ARG1), \ + DEFINE_GPR(r4, "arg2",LLDB_REGNUM_GENERIC_ARG2), \ + DEFINE_GPR(r5, "arg3",LLDB_REGNUM_GENERIC_ARG3), \ + DEFINE_GPR(r6, "arg4",LLDB_REGNUM_GENERIC_ARG4), \ + DEFINE_GPR(r7, "arg5",LLDB_REGNUM_GENERIC_ARG5), \ + DEFINE_GPR(r8, "arg6",LLDB_REGNUM_GENERIC_ARG6), \ + DEFINE_GPR(r9, "arg7",LLDB_REGNUM_GENERIC_ARG7), \ + DEFINE_GPR(r10, "arg8",LLDB_REGNUM_GENERIC_ARG8), \ + DEFINE_GPR(r11, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r12, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r13, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r14, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r15, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r16, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r17, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r18, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r19, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r20, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r21, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r22, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r23, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r24, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r25, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r26, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r27, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r28, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r29, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r30, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r31, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(lr, "lr", LLDB_REGNUM_GENERIC_RA), \ + DEFINE_GPR(cr, "cr", LLDB_REGNUM_GENERIC_FLAGS), \ + DEFINE_GPR(xer, "xer", LLDB_INVALID_REGNUM), \ + DEFINE_GPR(ctr, "ctr", LLDB_INVALID_REGNUM), \ + DEFINE_GPR(pc, "pc", LLDB_REGNUM_GENERIC_PC), \ + DEFINE_FPR(f0, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f1, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f2, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f3, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f4, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f5, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f6, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f7, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f8, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f9, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f10, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f11, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f12, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f13, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f14, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f15, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f16, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f17, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f18, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f19, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f20, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f21, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f22, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f23, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f24, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f25, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f26, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f27, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f28, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f29, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f30, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f31, LLDB_INVALID_REGNUM), \ + { "fpscr", NULL, 8, FPR_OFFSET(fpscr), eEncodingUint, eFormatHex, { gcc_dwarf_fpscr_powerpc, gcc_dwarf_fpscr_powerpc, LLDB_INVALID_REGNUM, gdb_fpscr_powerpc, fpr_fpscr_powerpc }, NULL, NULL }, +static RegisterInfo +g_register_infos_powerpc64[] = +{ +#define GPR GPR64 + POWERPC_REGS +#undef GPR +}; + +static RegisterInfo +g_register_infos_powerpc32[] = +{ +#define GPR GPR32 + POWERPC_REGS +#undef GPR +}; + +static RegisterInfo +g_register_infos_powerpc64_32[] = +{ +#define GPR GPR64 +#undef GPR_SIZE +#define GPR_SIZE(reg) (sizeof(uint32_t)) +#undef GPR_OFFSET +#define GPR_OFFSET(regname) \ + (offsetof(GPR, regname) + (sizeof(((GPR *)NULL)->regname) - GPR_SIZE(reg))) + POWERPC_REGS +#undef GPR +}; + +static_assert((sizeof(g_register_infos_powerpc32) / sizeof(g_register_infos_powerpc32[0])) == k_num_registers_powerpc, + "g_register_infos_powerpc32 has wrong number of register infos"); +static_assert((sizeof(g_register_infos_powerpc64) / sizeof(g_register_infos_powerpc64[0])) == k_num_registers_powerpc, + "g_register_infos_powerpc64 has wrong number of register infos"); +static_assert(sizeof(g_register_infos_powerpc64_32) == sizeof(g_register_infos_powerpc64), + "g_register_infos_powerpc64_32 doesn't match size of g_register_infos_powerpc64"); + +#undef DEFINE_FPR +#undef DEFINE_GPR + +#endif // DECLARE_REGISTER_INFOS_POWERPC_STRUCT + +#undef GPR_OFFSET + diff --git a/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h index c4dc6041ce439..c1bcd27053c6d 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_x86_64.h +++ b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h @@ -42,34 +42,34 @@ // Note that the size and offset will be updated by platform-specific classes. #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_x86_64 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, lldb_##reg##_x86_64 }, NULL, NULL } #define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ { #name, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, fpu_##name##_x86_64 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, lldb_##name##_x86_64 }, NULL, NULL } #define DEFINE_FP_ST(reg, i) \ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ eEncodingVector, eFormatVectorOfUInt8, \ - { gcc_dwarf_st##i##_x86_64, gcc_dwarf_st##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, fpu_st##i##_x86_64 }, \ + { gcc_dwarf_st##i##_x86_64, gcc_dwarf_st##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, lldb_st##i##_x86_64 }, \ NULL, NULL } #define DEFINE_FP_MM(reg, i) \ { #reg#i, NULL, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ eEncodingUint, eFormatHex, \ - { gcc_dwarf_mm##i##_x86_64, gcc_dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, fpu_mm##i##_x86_64 }, \ + { gcc_dwarf_mm##i##_x86_64, gcc_dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, lldb_mm##i##_x86_64 }, \ NULL, NULL } #define DEFINE_XMM(reg, i) \ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \ eEncodingVector, eFormatVectorOfUInt8, \ - { gcc_dwarf_##reg##i##_x86_64, gcc_dwarf_##reg##i##_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##_x86_64, fpu_##reg##i##_x86_64}, \ + { gcc_dwarf_##reg##i##_x86_64, gcc_dwarf_##reg##i##_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##_x86_64, lldb_##reg##i##_x86_64}, \ NULL, NULL } #define DEFINE_YMM(reg, i) \ { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \ eEncodingVector, eFormatVectorOfUInt8, \ - { gcc_dwarf_##reg##i##h_x86_64, gcc_dwarf_##reg##i##h_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##h_x86_64, fpu_##reg##i##_x86_64 }, \ + { gcc_dwarf_##reg##i##h_x86_64, gcc_dwarf_##reg##i##h_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##h_x86_64, lldb_##reg##i##_x86_64 }, \ NULL, NULL } #define DEFINE_DR(reg, i) \ @@ -79,16 +79,16 @@ #define DEFINE_GPR_PSEUDO_32(reg32, reg64) \ { #reg32, NULL, 4, GPR_OFFSET(reg64), eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg32##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg32##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } #define DEFINE_GPR_PSEUDO_16(reg16, reg64) \ { #reg16, NULL, 2, GPR_OFFSET(reg64), eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg16##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg16##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } #define DEFINE_GPR_PSEUDO_8H(reg8, reg64) \ { #reg8, NULL, 1, GPR_OFFSET(reg64)+1, eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } #define DEFINE_GPR_PSEUDO_8L(reg8, reg64) \ { #reg8, NULL, 1, GPR_OFFSET(reg64), eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } static RegisterInfo g_register_infos_x86_64[] = @@ -273,37 +273,37 @@ static_assert((sizeof(g_register_infos_x86_64) / sizeof(g_register_infos_x86_64[ #define UPDATE_GPR_INFO(reg, reg64) \ do { \ - g_register_infos[gpr_##reg##_i386].byte_offset = GPR_OFFSET(reg64); \ + g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64); \ } while(false); #define UPDATE_GPR_INFO_8H(reg, reg64) \ do { \ - g_register_infos[gpr_##reg##_i386].byte_offset = GPR_OFFSET(reg64) + 1; \ + g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64) + 1; \ } while(false); #define UPDATE_FPR_INFO(reg, reg64) \ do { \ - g_register_infos[fpu_##reg##_i386].byte_offset = FPR_OFFSET(reg64); \ + g_register_infos[lldb_##reg##_i386].byte_offset = FPR_OFFSET(reg64); \ } while(false); #define UPDATE_FP_INFO(reg, i) \ do { \ - g_register_infos[fpu_##reg##i##_i386].byte_offset = FPR_OFFSET(stmm[i]); \ + g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(stmm[i]); \ } while(false); #define UPDATE_XMM_INFO(reg, i) \ do { \ - g_register_infos[fpu_##reg##i##_i386].byte_offset = FPR_OFFSET(reg[i]); \ + g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(reg[i]); \ } while(false); #define UPDATE_YMM_INFO(reg, i) \ do { \ - g_register_infos[fpu_##reg##i##_i386].byte_offset = YMM_OFFSET(reg[i]); \ + g_register_infos[lldb_##reg##i##_i386].byte_offset = YMM_OFFSET(reg[i]); \ } while(false); #define UPDATE_DR_INFO(reg_index) \ do { \ - g_register_infos[dr##reg_index##_i386].byte_offset = DR_OFFSET(reg_index); \ + g_register_infos[lldb_dr##reg_index##_i386].byte_offset = DR_OFFSET(reg_index); \ } while(false); // Update the register offsets diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp index 0e3e559aef5c0..a69b38b6c93e3 100644 --- a/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -423,9 +423,11 @@ StopInfoMachException::CreateStopReasonWithMachException wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); } - // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS - if (thread.GetTemporaryResumeState() == eStateStepping) - return StopInfo::CreateStopReasonToTrace(thread); + else + { + is_actual_breakpoint = true; + is_trace_if_actual_breakpoint_missing = true; + } } else if (exc_code == 1) // EXC_ARM_BREAKPOINT { diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp index 37fd4f489552e..fc592e60d86d4 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -172,8 +172,9 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) if (!reg_ctx_sp->IsValid()) { - // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return - // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + // We failed to get a valid RegisterContext. + // See if the regctx below this on the stack has a fallback unwind plan it can use. + // Subsequent calls to TryFallbackUnwindPlan() will return false. if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) { return AddOneMoreFrame (abi); @@ -207,18 +208,35 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) // these. if (reg_ctx_sp->IsTrapHandlerFrame() == false) { - // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return - // true. Subsequent calls to TryFallbackUnwindPlan() will return false. - if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + // See if we can find a fallback unwind plan for THIS frame. It may be + // that the UnwindPlan we're using for THIS frame was bad and gave us a + // bad CFA. + // If that's not it, then see if we can change the UnwindPlan for the frame + // below us ("NEXT") -- see if using that other UnwindPlan gets us a better + // unwind state. + if (reg_ctx_sp->TryFallbackUnwindPlan() == false + || reg_ctx_sp->GetCFA (cursor_sp->cfa) == false + || abi->CallFrameAddressIsValid(cursor_sp->cfa) == false) { - return AddOneMoreFrame (abi); + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } + if (log) + { + log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk", + cur_idx < 100 ? cur_idx : 100, "", cur_idx); + } + goto unwind_done; } - if (log) + else { - log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk", - cur_idx < 100 ? cur_idx : 100, "", cur_idx); + if (log) + { + log->Printf("%*sFrame %d had a bad CFA value but we switched the UnwindPlan being used and got one that looks more realistic.", + cur_idx < 100 ? cur_idx : 100, "", cur_idx); + } } - goto unwind_done; } } if (!reg_ctx_sp->ReadPC (cursor_sp->start_pc)) @@ -366,6 +384,14 @@ UnwindLLDB::SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_privat UnwindLLDB::RegisterSearchResult result; result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister (lldb_regnum, regloc); + // We descended down to the live register context aka stack frame 0 and are reading the value + // out of a live register. + if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound + && regloc.type == UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext) + { + return true; + } + // If we have unwind instructions saying that register N is saved in register M in the middle of // the stack (and N can equal M here, meaning the register was not used in this function), then // change the register number we're looking for to M and keep looking for a concrete location diff --git a/source/Plugins/Process/Utility/UnwindLLDB.h b/source/Plugins/Process/Utility/UnwindLLDB.h index eb5400389df3e..35d85e2e3d26e 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.h +++ b/source/Plugins/Process/Utility/UnwindLLDB.h @@ -48,7 +48,8 @@ protected: eRegisterSavedAtMemoryLocation, // register is saved at a specific word of target mem (target_memory_location) eRegisterInRegister, // register is available in a (possible other) register (register_number) eRegisterSavedAtHostMemoryLocation, // register is saved at a word in lldb's address space - eRegisterValueInferred // register val was computed (and is in inferred_value) + eRegisterValueInferred, // register val was computed (and is in inferred_value) + eRegisterInLiveRegisterContext // register value is in a live (stack frame #0) register }; int type; union diff --git a/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/source/Plugins/Process/Utility/lldb-x86-register-enums.h index c4706d567b70b..99fca3005820c 100644 --- a/source/Plugins/Process/Utility/lldb-x86-register-enums.h +++ b/source/Plugins/Process/Utility/lldb-x86-register-enums.h @@ -12,6 +12,7 @@ namespace lldb_private { + // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) //--------------------------------------------------------------------------- // Internal codes for all i386 registers. @@ -19,100 +20,100 @@ namespace lldb_private enum { k_first_gpr_i386, - gpr_eax_i386 = k_first_gpr_i386, - gpr_ebx_i386, - gpr_ecx_i386, - gpr_edx_i386, - gpr_edi_i386, - gpr_esi_i386, - gpr_ebp_i386, - gpr_esp_i386, - gpr_eip_i386, - gpr_eflags_i386, - gpr_cs_i386, - gpr_fs_i386, - gpr_gs_i386, - gpr_ss_i386, - gpr_ds_i386, - gpr_es_i386, + lldb_eax_i386 = k_first_gpr_i386, + lldb_ebx_i386, + lldb_ecx_i386, + lldb_edx_i386, + lldb_edi_i386, + lldb_esi_i386, + lldb_ebp_i386, + lldb_esp_i386, + lldb_eip_i386, + lldb_eflags_i386, + lldb_cs_i386, + lldb_fs_i386, + lldb_gs_i386, + lldb_ss_i386, + lldb_ds_i386, + lldb_es_i386, k_first_alias_i386, - gpr_ax_i386 = k_first_alias_i386, - gpr_bx_i386, - gpr_cx_i386, - gpr_dx_i386, - gpr_di_i386, - gpr_si_i386, - gpr_bp_i386, - gpr_sp_i386, - gpr_ah_i386, - gpr_bh_i386, - gpr_ch_i386, - gpr_dh_i386, - gpr_al_i386, - gpr_bl_i386, - gpr_cl_i386, - gpr_dl_i386, - k_last_alias_i386 = gpr_dl_i386, + lldb_ax_i386 = k_first_alias_i386, + lldb_bx_i386, + lldb_cx_i386, + lldb_dx_i386, + lldb_di_i386, + lldb_si_i386, + lldb_bp_i386, + lldb_sp_i386, + lldb_ah_i386, + lldb_bh_i386, + lldb_ch_i386, + lldb_dh_i386, + lldb_al_i386, + lldb_bl_i386, + lldb_cl_i386, + lldb_dl_i386, + k_last_alias_i386 = lldb_dl_i386, k_last_gpr_i386 = k_last_alias_i386, k_first_fpr_i386, - fpu_fctrl_i386 = k_first_fpr_i386, - fpu_fstat_i386, - fpu_ftag_i386, - fpu_fop_i386, - fpu_fiseg_i386, - fpu_fioff_i386, - fpu_foseg_i386, - fpu_fooff_i386, - fpu_mxcsr_i386, - fpu_mxcsrmask_i386, - fpu_st0_i386, - fpu_st1_i386, - fpu_st2_i386, - fpu_st3_i386, - fpu_st4_i386, - fpu_st5_i386, - fpu_st6_i386, - fpu_st7_i386, - fpu_mm0_i386, - fpu_mm1_i386, - fpu_mm2_i386, - fpu_mm3_i386, - fpu_mm4_i386, - fpu_mm5_i386, - fpu_mm6_i386, - fpu_mm7_i386, - fpu_xmm0_i386, - fpu_xmm1_i386, - fpu_xmm2_i386, - fpu_xmm3_i386, - fpu_xmm4_i386, - fpu_xmm5_i386, - fpu_xmm6_i386, - fpu_xmm7_i386, - k_last_fpr_i386 = fpu_xmm7_i386, + lldb_fctrl_i386 = k_first_fpr_i386, + lldb_fstat_i386, + lldb_ftag_i386, + lldb_fop_i386, + lldb_fiseg_i386, + lldb_fioff_i386, + lldb_foseg_i386, + lldb_fooff_i386, + lldb_mxcsr_i386, + lldb_mxcsrmask_i386, + lldb_st0_i386, + lldb_st1_i386, + lldb_st2_i386, + lldb_st3_i386, + lldb_st4_i386, + lldb_st5_i386, + lldb_st6_i386, + lldb_st7_i386, + lldb_mm0_i386, + lldb_mm1_i386, + lldb_mm2_i386, + lldb_mm3_i386, + lldb_mm4_i386, + lldb_mm5_i386, + lldb_mm6_i386, + lldb_mm7_i386, + lldb_xmm0_i386, + lldb_xmm1_i386, + lldb_xmm2_i386, + lldb_xmm3_i386, + lldb_xmm4_i386, + lldb_xmm5_i386, + lldb_xmm6_i386, + lldb_xmm7_i386, + k_last_fpr_i386 = lldb_xmm7_i386, k_first_avx_i386, - fpu_ymm0_i386 = k_first_avx_i386, - fpu_ymm1_i386, - fpu_ymm2_i386, - fpu_ymm3_i386, - fpu_ymm4_i386, - fpu_ymm5_i386, - fpu_ymm6_i386, - fpu_ymm7_i386, - k_last_avx_i386 = fpu_ymm7_i386, + lldb_ymm0_i386 = k_first_avx_i386, + lldb_ymm1_i386, + lldb_ymm2_i386, + lldb_ymm3_i386, + lldb_ymm4_i386, + lldb_ymm5_i386, + lldb_ymm6_i386, + lldb_ymm7_i386, + k_last_avx_i386 = lldb_ymm7_i386, - dr0_i386, - dr1_i386, - dr2_i386, - dr3_i386, - dr4_i386, - dr5_i386, - dr6_i386, - dr7_i386, + lldb_dr0_i386, + lldb_dr1_i386, + lldb_dr2_i386, + lldb_dr3_i386, + lldb_dr4_i386, + lldb_dr5_i386, + lldb_dr6_i386, + lldb_dr7_i386, k_num_registers_i386, k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1, @@ -126,160 +127,160 @@ namespace lldb_private enum { k_first_gpr_x86_64, - gpr_rax_x86_64 = k_first_gpr_x86_64, - gpr_rbx_x86_64, - gpr_rcx_x86_64, - gpr_rdx_x86_64, - gpr_rdi_x86_64, - gpr_rsi_x86_64, - gpr_rbp_x86_64, - gpr_rsp_x86_64, - gpr_r8_x86_64, - gpr_r9_x86_64, - gpr_r10_x86_64, - gpr_r11_x86_64, - gpr_r12_x86_64, - gpr_r13_x86_64, - gpr_r14_x86_64, - gpr_r15_x86_64, - gpr_rip_x86_64, - gpr_rflags_x86_64, - gpr_cs_x86_64, - gpr_fs_x86_64, - gpr_gs_x86_64, - gpr_ss_x86_64, - gpr_ds_x86_64, - gpr_es_x86_64, + lldb_rax_x86_64 = k_first_gpr_x86_64, + lldb_rbx_x86_64, + lldb_rcx_x86_64, + lldb_rdx_x86_64, + lldb_rdi_x86_64, + lldb_rsi_x86_64, + lldb_rbp_x86_64, + lldb_rsp_x86_64, + lldb_r8_x86_64, + lldb_r9_x86_64, + lldb_r10_x86_64, + lldb_r11_x86_64, + lldb_r12_x86_64, + lldb_r13_x86_64, + lldb_r14_x86_64, + lldb_r15_x86_64, + lldb_rip_x86_64, + lldb_rflags_x86_64, + lldb_cs_x86_64, + lldb_fs_x86_64, + lldb_gs_x86_64, + lldb_ss_x86_64, + lldb_ds_x86_64, + lldb_es_x86_64, k_first_alias_x86_64, - gpr_eax_x86_64 = k_first_alias_x86_64, - gpr_ebx_x86_64, - gpr_ecx_x86_64, - gpr_edx_x86_64, - gpr_edi_x86_64, - gpr_esi_x86_64, - gpr_ebp_x86_64, - gpr_esp_x86_64, - gpr_r8d_x86_64, // Low 32 bits of r8 - gpr_r9d_x86_64, // Low 32 bits of r9 - gpr_r10d_x86_64, // Low 32 bits of r10 - gpr_r11d_x86_64, // Low 32 bits of r11 - gpr_r12d_x86_64, // Low 32 bits of r12 - gpr_r13d_x86_64, // Low 32 bits of r13 - gpr_r14d_x86_64, // Low 32 bits of r14 - gpr_r15d_x86_64, // Low 32 bits of r15 - gpr_ax_x86_64, - gpr_bx_x86_64, - gpr_cx_x86_64, - gpr_dx_x86_64, - gpr_di_x86_64, - gpr_si_x86_64, - gpr_bp_x86_64, - gpr_sp_x86_64, - gpr_r8w_x86_64, // Low 16 bits of r8 - gpr_r9w_x86_64, // Low 16 bits of r9 - gpr_r10w_x86_64, // Low 16 bits of r10 - gpr_r11w_x86_64, // Low 16 bits of r11 - gpr_r12w_x86_64, // Low 16 bits of r12 - gpr_r13w_x86_64, // Low 16 bits of r13 - gpr_r14w_x86_64, // Low 16 bits of r14 - gpr_r15w_x86_64, // Low 16 bits of r15 - gpr_ah_x86_64, - gpr_bh_x86_64, - gpr_ch_x86_64, - gpr_dh_x86_64, - gpr_al_x86_64, - gpr_bl_x86_64, - gpr_cl_x86_64, - gpr_dl_x86_64, - gpr_dil_x86_64, - gpr_sil_x86_64, - gpr_bpl_x86_64, - gpr_spl_x86_64, - gpr_r8l_x86_64, // Low 8 bits of r8 - gpr_r9l_x86_64, // Low 8 bits of r9 - gpr_r10l_x86_64, // Low 8 bits of r10 - gpr_r11l_x86_64, // Low 8 bits of r11 - gpr_r12l_x86_64, // Low 8 bits of r12 - gpr_r13l_x86_64, // Low 8 bits of r13 - gpr_r14l_x86_64, // Low 8 bits of r14 - gpr_r15l_x86_64, // Low 8 bits of r15 - k_last_alias_x86_64 = gpr_r15l_x86_64, + lldb_eax_x86_64 = k_first_alias_x86_64, + lldb_ebx_x86_64, + lldb_ecx_x86_64, + lldb_edx_x86_64, + lldb_edi_x86_64, + lldb_esi_x86_64, + lldb_ebp_x86_64, + lldb_esp_x86_64, + lldb_r8d_x86_64, // Low 32 bits of r8 + lldb_r9d_x86_64, // Low 32 bits of r9 + lldb_r10d_x86_64, // Low 32 bits of r10 + lldb_r11d_x86_64, // Low 32 bits of r11 + lldb_r12d_x86_64, // Low 32 bits of r12 + lldb_r13d_x86_64, // Low 32 bits of r13 + lldb_r14d_x86_64, // Low 32 bits of r14 + lldb_r15d_x86_64, // Low 32 bits of r15 + lldb_ax_x86_64, + lldb_bx_x86_64, + lldb_cx_x86_64, + lldb_dx_x86_64, + lldb_di_x86_64, + lldb_si_x86_64, + lldb_bp_x86_64, + lldb_sp_x86_64, + lldb_r8w_x86_64, // Low 16 bits of r8 + lldb_r9w_x86_64, // Low 16 bits of r9 + lldb_r10w_x86_64, // Low 16 bits of r10 + lldb_r11w_x86_64, // Low 16 bits of r11 + lldb_r12w_x86_64, // Low 16 bits of r12 + lldb_r13w_x86_64, // Low 16 bits of r13 + lldb_r14w_x86_64, // Low 16 bits of r14 + lldb_r15w_x86_64, // Low 16 bits of r15 + lldb_ah_x86_64, + lldb_bh_x86_64, + lldb_ch_x86_64, + lldb_dh_x86_64, + lldb_al_x86_64, + lldb_bl_x86_64, + lldb_cl_x86_64, + lldb_dl_x86_64, + lldb_dil_x86_64, + lldb_sil_x86_64, + lldb_bpl_x86_64, + lldb_spl_x86_64, + lldb_r8l_x86_64, // Low 8 bits of r8 + lldb_r9l_x86_64, // Low 8 bits of r9 + lldb_r10l_x86_64, // Low 8 bits of r10 + lldb_r11l_x86_64, // Low 8 bits of r11 + lldb_r12l_x86_64, // Low 8 bits of r12 + lldb_r13l_x86_64, // Low 8 bits of r13 + lldb_r14l_x86_64, // Low 8 bits of r14 + lldb_r15l_x86_64, // Low 8 bits of r15 + k_last_alias_x86_64 = lldb_r15l_x86_64, k_last_gpr_x86_64 = k_last_alias_x86_64, k_first_fpr_x86_64, - fpu_fctrl_x86_64 = k_first_fpr_x86_64, - fpu_fstat_x86_64, - fpu_ftag_x86_64, - fpu_fop_x86_64, - fpu_fiseg_x86_64, - fpu_fioff_x86_64, - fpu_foseg_x86_64, - fpu_fooff_x86_64, - fpu_mxcsr_x86_64, - fpu_mxcsrmask_x86_64, - fpu_st0_x86_64, - fpu_st1_x86_64, - fpu_st2_x86_64, - fpu_st3_x86_64, - fpu_st4_x86_64, - fpu_st5_x86_64, - fpu_st6_x86_64, - fpu_st7_x86_64, - fpu_mm0_x86_64, - fpu_mm1_x86_64, - fpu_mm2_x86_64, - fpu_mm3_x86_64, - fpu_mm4_x86_64, - fpu_mm5_x86_64, - fpu_mm6_x86_64, - fpu_mm7_x86_64, - fpu_xmm0_x86_64, - fpu_xmm1_x86_64, - fpu_xmm2_x86_64, - fpu_xmm3_x86_64, - fpu_xmm4_x86_64, - fpu_xmm5_x86_64, - fpu_xmm6_x86_64, - fpu_xmm7_x86_64, - fpu_xmm8_x86_64, - fpu_xmm9_x86_64, - fpu_xmm10_x86_64, - fpu_xmm11_x86_64, - fpu_xmm12_x86_64, - fpu_xmm13_x86_64, - fpu_xmm14_x86_64, - fpu_xmm15_x86_64, - k_last_fpr_x86_64 = fpu_xmm15_x86_64, + lldb_fctrl_x86_64 = k_first_fpr_x86_64, + lldb_fstat_x86_64, + lldb_ftag_x86_64, + lldb_fop_x86_64, + lldb_fiseg_x86_64, + lldb_fioff_x86_64, + lldb_foseg_x86_64, + lldb_fooff_x86_64, + lldb_mxcsr_x86_64, + lldb_mxcsrmask_x86_64, + lldb_st0_x86_64, + lldb_st1_x86_64, + lldb_st2_x86_64, + lldb_st3_x86_64, + lldb_st4_x86_64, + lldb_st5_x86_64, + lldb_st6_x86_64, + lldb_st7_x86_64, + lldb_mm0_x86_64, + lldb_mm1_x86_64, + lldb_mm2_x86_64, + lldb_mm3_x86_64, + lldb_mm4_x86_64, + lldb_mm5_x86_64, + lldb_mm6_x86_64, + lldb_mm7_x86_64, + lldb_xmm0_x86_64, + lldb_xmm1_x86_64, + lldb_xmm2_x86_64, + lldb_xmm3_x86_64, + lldb_xmm4_x86_64, + lldb_xmm5_x86_64, + lldb_xmm6_x86_64, + lldb_xmm7_x86_64, + lldb_xmm8_x86_64, + lldb_xmm9_x86_64, + lldb_xmm10_x86_64, + lldb_xmm11_x86_64, + lldb_xmm12_x86_64, + lldb_xmm13_x86_64, + lldb_xmm14_x86_64, + lldb_xmm15_x86_64, + k_last_fpr_x86_64 = lldb_xmm15_x86_64, k_first_avx_x86_64, - fpu_ymm0_x86_64 = k_first_avx_x86_64, - fpu_ymm1_x86_64, - fpu_ymm2_x86_64, - fpu_ymm3_x86_64, - fpu_ymm4_x86_64, - fpu_ymm5_x86_64, - fpu_ymm6_x86_64, - fpu_ymm7_x86_64, - fpu_ymm8_x86_64, - fpu_ymm9_x86_64, - fpu_ymm10_x86_64, - fpu_ymm11_x86_64, - fpu_ymm12_x86_64, - fpu_ymm13_x86_64, - fpu_ymm14_x86_64, - fpu_ymm15_x86_64, - k_last_avx_x86_64 = fpu_ymm15_x86_64, + lldb_ymm0_x86_64 = k_first_avx_x86_64, + lldb_ymm1_x86_64, + lldb_ymm2_x86_64, + lldb_ymm3_x86_64, + lldb_ymm4_x86_64, + lldb_ymm5_x86_64, + lldb_ymm6_x86_64, + lldb_ymm7_x86_64, + lldb_ymm8_x86_64, + lldb_ymm9_x86_64, + lldb_ymm10_x86_64, + lldb_ymm11_x86_64, + lldb_ymm12_x86_64, + lldb_ymm13_x86_64, + lldb_ymm14_x86_64, + lldb_ymm15_x86_64, + k_last_avx_x86_64 = lldb_ymm15_x86_64, - dr0_x86_64, - dr1_x86_64, - dr2_x86_64, - dr3_x86_64, - dr4_x86_64, - dr5_x86_64, - dr6_x86_64, - dr7_x86_64, + lldb_dr0_x86_64, + lldb_dr1_x86_64, + lldb_dr2_x86_64, + lldb_dr3_x86_64, + lldb_dr4_x86_64, + lldb_dr5_x86_64, + lldb_dr6_x86_64, + lldb_dr7_x86_64, k_num_registers_x86_64, k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1, diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 566816783c7ee..fb39d7318a5a5 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -405,14 +405,18 @@ enum { NT_AUXV }; +namespace FREEBSD { + enum { - NT_FREEBSD_PRSTATUS = 1, - NT_FREEBSD_FPREGSET, - NT_FREEBSD_PRPSINFO, - NT_FREEBSD_THRMISC = 7, - NT_FREEBSD_PROCSTAT_AUXV = 16 + NT_PRSTATUS = 1, + NT_FPREGSET, + NT_PRPSINFO, + NT_THRMISC = 7, + NT_PROCSTAT_AUXV = 16 }; +} + // Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details. static void ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, @@ -420,6 +424,7 @@ ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, { lldb::offset_t offset = 0; bool lp64 = (arch.GetMachine() == llvm::Triple::mips64 || + arch.GetMachine() == llvm::Triple::ppc64 || arch.GetMachine() == llvm::Triple::x86_64); int pr_version = data.GetU32(&offset); @@ -516,20 +521,20 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader * m_os = llvm::Triple::FreeBSD; switch (note.n_type) { - case NT_FREEBSD_PRSTATUS: + case FREEBSD::NT_PRSTATUS: have_prstatus = true; ParseFreeBSDPrStatus(*thread_data, note_data, arch); break; - case NT_FREEBSD_FPREGSET: + case FREEBSD::NT_FPREGSET: thread_data->fpregset = note_data; break; - case NT_FREEBSD_PRPSINFO: + case FREEBSD::NT_PRPSINFO: have_prpsinfo = true; break; - case NT_FREEBSD_THRMISC: + case FREEBSD::NT_THRMISC: ParseFreeBSDThrMisc(*thread_data, note_data); break; - case NT_FREEBSD_PROCSTAT_AUXV: + case FREEBSD::NT_PROCSTAT_AUXV: // FIXME: FreeBSD sticks an int at the beginning of the note m_auxv = DataExtractor(segment_data, note_start + 4, note_size - 4); break; diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.h b/source/Plugins/Process/elf-core/ProcessElfCore.h index 2fc2e4ee7949e..7988bee5ae531 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -68,52 +68,52 @@ public: //------------------------------------------------------------------ virtual bool CanDebug (lldb_private::Target &target, - bool plugin_specified_by_name); + bool plugin_specified_by_name) override; //------------------------------------------------------------------ // Creating a new process, or attaching to an existing one //------------------------------------------------------------------ virtual lldb_private::Error - DoLoadCore (); + DoLoadCore () override; virtual lldb_private::DynamicLoader * - GetDynamicLoader (); + GetDynamicLoader () override; //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ virtual lldb_private::ConstString - GetPluginName(); + GetPluginName() override; virtual uint32_t - GetPluginVersion(); + GetPluginVersion() override; //------------------------------------------------------------------ // Process Control //------------------------------------------------------------------ virtual lldb_private::Error - DoDestroy (); + DoDestroy () override; virtual void - RefreshStateAfterStop(); + RefreshStateAfterStop() override; //------------------------------------------------------------------ // Process Queries //------------------------------------------------------------------ virtual bool - IsAlive (); + IsAlive () override; //------------------------------------------------------------------ // Process Memory //------------------------------------------------------------------ virtual size_t - ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error); + ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override; virtual size_t - DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error); + DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override; virtual lldb::addr_t - GetImageInfoAddress (); + GetImageInfoAddress () override; lldb_private::ArchSpec GetArchitecture(); @@ -128,7 +128,7 @@ protected: virtual bool UpdateThreadList (lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list); + lldb_private::ThreadList &new_thread_list) override; private: //------------------------------------------------------------------ diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp index fbf397b933cc3..f0750a0cee18e 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp @@ -10,7 +10,7 @@ #include "lldb/Core/DataExtractor.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" -#include "RegisterContextPOSIX.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX.h" #include "RegisterContextPOSIXCore_mips64.h" using namespace lldb_private; diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp new file mode 100644 index 0000000000000..15b1b44182d7e --- /dev/null +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp @@ -0,0 +1,109 @@ +//===-- RegisterContextCorePOSIX_powerpc.cpp ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" +#include "RegisterContextPOSIX.h" +#include "RegisterContextPOSIXCore_powerpc.h" + +using namespace lldb_private; + +RegisterContextCorePOSIX_powerpc::RegisterContextCorePOSIX_powerpc(Thread &thread, + RegisterInfoInterface *register_info, + const DataExtractor &gpregset, + const DataExtractor &fpregset) + : RegisterContextPOSIX_powerpc(thread, 0, register_info) +{ + m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize())); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); + m_fpr_buffer.reset(new DataBufferHeap(fpregset.GetDataStart(), fpregset.GetByteSize())); + m_fpr.SetData(m_fpr_buffer); + m_fpr.SetByteOrder(fpregset.GetByteOrder()); +} + +RegisterContextCorePOSIX_powerpc::~RegisterContextCorePOSIX_powerpc() +{ +} + +bool +RegisterContextCorePOSIX_powerpc::ReadGPR() +{ + return true; +} + +bool +RegisterContextCorePOSIX_powerpc::ReadFPR() +{ + return true; +} + +bool +RegisterContextCorePOSIX_powerpc::WriteGPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::WriteFPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + lldb::offset_t offset = reg_info->byte_offset; + if (reg_info->name[0] == 'f') { + uint64_t v = m_fpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) + { + value = v; + return true; + } + } else { + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) + { + if (reg_info->byte_size < sizeof(v)) + value = (uint32_t)v; + else + value = v; + return true; + } + } + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::HardwareSingleStep(bool enable) +{ + return false; +} diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h new file mode 100644 index 0000000000000..e6575581b3600 --- /dev/null +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h @@ -0,0 +1,62 @@ +//===-- RegisterContextCorePOSIX_powerpc.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_RegisterContextCorePOSIX_powerpc_H_ +#define liblldb_RegisterContextCorePOSIX_powerpc_H_ + +#include "lldb/Core/DataBufferHeap.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" + +class RegisterContextCorePOSIX_powerpc : + public RegisterContextPOSIX_powerpc +{ +public: + RegisterContextCorePOSIX_powerpc (lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset, + const lldb_private::DataExtractor &fpregset); + + ~RegisterContextCorePOSIX_powerpc(); + + virtual bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + virtual bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + bool + HardwareSingleStep(bool enable); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb::DataBufferSP m_fpr_buffer; + lldb_private::DataExtractor m_gpr; + lldb_private::DataExtractor m_fpr; +}; + +#endif // #ifndef liblldb_RegisterContextCorePOSIX_powerpc_H_ diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp index 3e09c7bc20322..412c7ade82955 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp @@ -10,7 +10,7 @@ #include "lldb/Core/DataExtractor.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" -#include "RegisterContextPOSIX.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX.h" #include "RegisterContextPOSIXCore_x86_64.h" using namespace lldb_private; diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp index d9f6cc04a3435..d62bcfcff6003 100644 --- a/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -16,11 +16,13 @@ #include "ThreadElfCore.h" #include "ProcessElfCore.h" -#include "RegisterContextLinux_x86_64.h" -#include "RegisterContextFreeBSD_i386.h" -#include "RegisterContextFreeBSD_mips64.h" -#include "RegisterContextFreeBSD_x86_64.h" +#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" #include "RegisterContextPOSIXCore_mips64.h" +#include "RegisterContextPOSIXCore_powerpc.h" #include "RegisterContextPOSIXCore_x86_64.h" using namespace lldb; @@ -94,6 +96,12 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) { switch (arch.GetMachine()) { + case llvm::Triple::ppc: + reg_interface = new RegisterContextFreeBSD_powerpc32(arch); + break; + case llvm::Triple::ppc64: + reg_interface = new RegisterContextFreeBSD_powerpc64(arch); + break; case llvm::Triple::mips64: reg_interface = new RegisterContextFreeBSD_mips64(arch); break; @@ -138,6 +146,10 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) case llvm::Triple::mips64: m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); break; + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_powerpc (*this, reg_interface, m_gpregset_data, m_fpregset_data)); + break; case llvm::Triple::x86: case llvm::Triple::x86_64: m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 1f4dd93976ec8..919fa54051179 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -17,15 +17,16 @@ // C++ Includes // Other libraries and framework includes -#include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/Log.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" +#include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" -#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/Pipe.h" #include "lldb/Host/Socket.h" +#include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/TimeValue.h" #include "lldb/Target/Process.h" @@ -153,7 +154,6 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, m_history (512), m_send_acks (true), m_is_platform (is_platform), - m_listen_thread (LLDB_INVALID_HOST_THREAD), m_listen_url () { } @@ -227,9 +227,23 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); ConnectionStatus status = eConnectionStatusSuccess; - size_t bytes_written = Write (packet.GetData(), packet.GetSize(), status, NULL); + const char *packet_data = packet.GetData(); + const size_t packet_length = packet.GetSize(); + size_t bytes_written = Write (packet_data, packet_length, status, NULL); if (log) { + size_t binary_start_offset = 0; + if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) == 0) + { + const char *first_comma = strchr(packet_data, ','); + if (first_comma) + { + const char *second_comma = strchr(first_comma + 1, ','); + if (second_comma) + binary_start_offset = second_comma - packet_data + 1; + } + } + // If logging was just enabled and we have history, then dump out what // we have to the log so we get the historical context. The Dump() call that // logs all of the packet will set a boolean so that we don't dump this more @@ -237,13 +251,27 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le if (!m_history.DidDumpToLog ()) m_history.Dump (log); - log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)packet.GetSize(), packet.GetData()); + if (binary_start_offset) + { + StreamString strm; + // Print non binary data header + strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)binary_start_offset, packet_data); + const uint8_t *p; + // Print binary data exactly as sent + for (p = (uint8_t*)packet_data + binary_start_offset; *p != '#'; ++p) + strm.Printf("\\x%2.2x", *p); + // Print the checksum + strm.Printf("%*s", (int)3, p); + log->PutCString(strm.GetString().c_str()); + } + else + log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)packet_length, packet_data); } - m_history.AddPacket (packet.GetString(), packet.GetSize(), History::ePacketTypeSend, bytes_written); + m_history.AddPacket (packet.GetString(), packet_length, History::ePacketTypeSend, bytes_written); - if (bytes_written == packet.GetSize()) + if (bytes_written == packet_length) { if (GetSendAcks ()) return GetAck (); @@ -253,7 +281,7 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le else { if (log) - log->Printf ("error: failed to send packet: %.*s", (int)packet.GetSize(), packet.GetData()); + log->Printf ("error: failed to send packet: %.*s", (int)packet_length, packet_data); } } return PacketResult::ErrorSendFailed; @@ -447,8 +475,8 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri } if (log) log->Printf ("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'", - __FUNCTION__, idx, idx, m_bytes.c_str()); - m_bytes.erase(0, idx); + __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str()); + m_bytes.erase(0, idx - 1); } break; } @@ -606,7 +634,7 @@ Error GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port) { Error error; - if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread)) + if (m_listen_thread.IsJoinable()) { error.SetErrorString("listen thread already running"); } @@ -619,7 +647,7 @@ GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port) snprintf(listen_url, sizeof(listen_url), "listen://%i", port); m_listen_url = listen_url; SetConnection(new ConnectionFileDescriptor()); - m_listen_thread = Host::ThreadCreate (listen_url, GDBRemoteCommunication::ListenThread, this, &error); + m_listen_thread = ThreadLauncher::LaunchThread(listen_url, GDBRemoteCommunication::ListenThread, this, &error); } return error; } @@ -627,11 +655,8 @@ GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port) bool GDBRemoteCommunication::JoinListenThread () { - if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread)) - { - Host::ThreadJoin(m_listen_thread, NULL, NULL); - m_listen_thread = LLDB_INVALID_HOST_THREAD; - } + if (m_listen_thread.IsJoinable()) + m_listen_thread.Join(nullptr); return true; } @@ -738,6 +763,7 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, char named_pipe_path[PATH_MAX]; named_pipe_path[0] = '\0'; + Pipe port_named_pipe; bool listen = false; if (host_and_port[0]) @@ -763,15 +789,11 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, if (::mktemp (named_pipe_path)) { -#if defined(_WIN32) - if ( false ) -#else - if (::mkfifo(named_pipe_path, 0600) == 0) -#endif - { - debugserver_args.AppendArgument("--named-pipe"); - debugserver_args.AppendArgument(named_pipe_path); - } + error = port_named_pipe.CreateNew(named_pipe_path, false); + if (error.Fail()) + return error; + debugserver_args.AppendArgument("--named-pipe"); + debugserver_args.AppendArgument(named_pipe_path); } } else @@ -838,11 +860,15 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, } } while (has_env_var); - // Close STDIN, STDOUT and STDERR. We might need to redirect them - // to "/dev/null" if we run into any problems. + // Close STDIN, STDOUT and STDERR. launch_info.AppendCloseFileAction (STDIN_FILENO); launch_info.AppendCloseFileAction (STDOUT_FILENO); launch_info.AppendCloseFileAction (STDERR_FILENO); + + // Redirect STDIN, STDOUT and STDERR to "/dev/null". + launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false); + launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true); + launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true); error = Host::LaunchProcess(launch_info); @@ -850,20 +876,40 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, { if (named_pipe_path[0]) { - File name_pipe_file; - error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); + error = port_named_pipe.OpenAsReader(named_pipe_path, false); if (error.Success()) { char port_cstr[256]; port_cstr[0] = '\0'; size_t num_bytes = sizeof(port_cstr); - error = name_pipe_file.Read(port_cstr, num_bytes); - assert (error.Success()); - assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); - out_port = Args::StringToUInt32(port_cstr, 0); - name_pipe_file.Close(); + // Read port from pipe with 10 second timeout. + error = port_named_pipe.ReadWithTimeout(port_cstr, num_bytes, std::chrono::microseconds(10 * 1000000), num_bytes); + if (error.Success()) + { + assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); + out_port = Args::StringToUInt32(port_cstr, 0); + if (log) + log->Printf("GDBRemoteCommunication::%s() debugserver listens %u port", __FUNCTION__, out_port); + } + else + { + if (log) + log->Printf("GDBRemoteCommunication::%s() failed to read a port value from named pipe %s: %s", __FUNCTION__, named_pipe_path, error.AsCString()); + + } + port_named_pipe.Close(); + } + else + { + if (log) + log->Printf("GDBRemoteCommunication::%s() failed to open named pipe %s for reading: %s", __FUNCTION__, named_pipe_path, error.AsCString()); + } + const auto err = port_named_pipe.Delete(named_pipe_path); + if (err.Fail()) + { + if (log) + log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s", __FUNCTION__, named_pipe_path, err.AsCString()); } - FileSystem::Unlink(named_pipe_path); } else if (listen) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index b11d38563207c..ac203a62788a1 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -20,6 +20,7 @@ #include "lldb/lldb-public.h" #include "lldb/Core/Communication.h" #include "lldb/Core/Listener.h" +#include "lldb/Host/HostThread.h" #include "lldb/Host/Mutex.h" #include "lldb/Host/Predicate.h" #include "lldb/Host/TimeValue.h" @@ -281,8 +282,7 @@ protected: ListenThread (lldb::thread_arg_t arg); private: - - lldb::thread_t m_listen_thread; + lldb_private::HostThread m_listen_thread; std::string m_listen_url; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 5e4ed7648f950..52750de5a25f0 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -20,11 +20,11 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include "lldb/Interpreter/Args.h" -#include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/Log.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamGDBRemote.h" #include "lldb/Core/StreamString.h" +#include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Endian.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" @@ -1643,7 +1643,9 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) } else if (name.compare("triple") == 0) { - triple.swap(value); + extractor.GetStringRef ().swap (value); + extractor.SetFilePos(0); + extractor.GetHexByteString (triple); ++num_keys_decoded; } else if (name.compare ("distribution_id") == 0) @@ -2331,6 +2333,10 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot } else if (name.compare("triple") == 0) { + StringExtractor extractor; + extractor.GetStringRef().swap(value); + extractor.SetFilePos(0); + extractor.GetHexByteString (value); process_info.GetArchitecture ().SetTriple (value.c_str()); } else if (name.compare("name") == 0) @@ -2404,6 +2410,8 @@ GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceIn bool GDBRemoteCommunicationClient::GetCurrentProcessInfo () { + Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); + if (m_qProcessInfo_is_valid == eLazyBoolYes) return true; if (m_qProcessInfo_is_valid == eLazyBoolNo) @@ -2426,6 +2434,7 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () std::string triple; uint32_t pointer_byte_size = 0; StringExtractor extractor; + ByteOrder byte_order = eByteOrderInvalid; uint32_t num_keys_decoded = 0; lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; while (response.GetNameColonValue(name, value)) @@ -2444,7 +2453,10 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () } else if (name.compare("triple") == 0) { - triple = value; + StringExtractor extractor; + extractor.GetStringRef().swap(value); + extractor.SetFilePos(0); + extractor.GetHexByteString (triple); ++num_keys_decoded; } else if (name.compare("ostype") == 0) @@ -2459,10 +2471,15 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () } else if (name.compare("endian") == 0) { - if (value.compare("little") == 0 || - value.compare("big") == 0 || - value.compare("pdp") == 0) - ++num_keys_decoded; + ++num_keys_decoded; + if (value.compare("little") == 0) + byte_order = eByteOrderLittle; + else if (value.compare("big") == 0) + byte_order = eByteOrderBig; + else if (value.compare("pdp") == 0) + byte_order = eByteOrderPDP; + else + --num_keys_decoded; } else if (name.compare("ptrsize") == 0) { @@ -2496,11 +2513,34 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () } else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty()) { - m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub); + llvm::Triple triple(llvm::Twine("-") + vendor_name + "-" + os_name); + + assert(triple.getObjectFormat() != llvm::Triple::UnknownObjectFormat); + switch (triple.getObjectFormat()) { + case llvm::Triple::MachO: + m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub); + break; + case llvm::Triple::ELF: + m_process_arch.SetArchitecture (eArchTypeELF, cpu, sub); + break; + case llvm::Triple::COFF: + m_process_arch.SetArchitecture (eArchTypeCOFF, cpu, sub); + break; + case llvm::Triple::UnknownObjectFormat: + if (log) + log->Printf("error: failed to determine target architecture"); + return false; + } + if (pointer_byte_size) { assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); } + if (byte_order != eByteOrderInvalid) + { + assert (byte_order == m_process_arch.GetByteOrder()); + } + m_process_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); m_process_arch.GetTriple().setOSName(llvm::StringRef (os_name)); m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name)); @@ -2931,6 +2971,11 @@ GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtracto uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert, addr_t addr, uint32_t length) { + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64, + __FUNCTION__, insert ? "add" : "remove", addr); + // Check if the stub is known not to support this breakpoint type if (!SupportsGDBStoppointPacket(type)) return UINT8_MAX; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index ffcdd169eb9fc..a7149505e869e 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -23,11 +23,11 @@ // Other libraries and framework includes #include "llvm/ADT/Triple.h" #include "lldb/Interpreter/Args.h" -#include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Log.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamString.h" +#include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Debug.h" #include "lldb/Host/Endian.h" #include "lldb/Host/File.h" @@ -71,7 +71,7 @@ namespace //---------------------------------------------------------------------- GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), - m_platform_sp (Platform::GetDefaultPlatform ()), + m_platform_sp (Platform::GetHostPlatform ()), m_async_thread (LLDB_INVALID_HOST_THREAD), m_process_launch_info (), m_process_launch_error (), @@ -429,6 +429,14 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_vAttach: packet_result = Handle_vAttach (packet); break; + + case StringExtractorGDBRemote::eServerPacketType_D: + packet_result = Handle_D (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo: + packet_result = Handle_qThreadStopInfo (packet); + break; } } else @@ -474,13 +482,34 @@ GDBRemoteCommunicationServer::LaunchProcess () // FIXME This looks an awful lot like we could override this in // derived classes, one for lldb-platform, the other for lldb-gdbserver. if (IsGdbServer ()) - return LaunchDebugServerProcess (); + return LaunchProcessForDebugging (); else return LaunchPlatformProcess (); } +bool +GDBRemoteCommunicationServer::ShouldRedirectInferiorOutputOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const +{ + // Retrieve the file actions specified for stdout and stderr. + auto stdout_file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); + auto stderr_file_action = launch_info.GetFileActionForFD (STDERR_FILENO); + + // If neither stdout and stderr file actions are specified, we're not doing anything special, so + // assume we want to redirect stdout/stderr over gdb-remote $O messages. + if ((stdout_file_action == nullptr) && (stderr_file_action == nullptr)) + { + // Send stdout/stderr over the gdb-remote protocol. + return true; + } + + // Any other setting for either stdout or stderr implies we are either suppressing + // it (with /dev/null) or we've got it set to a PTY. Either way, we don't want the + // output over gdb-remote. + return false; +} + lldb_private::Error -GDBRemoteCommunicationServer::LaunchDebugServerProcess () +GDBRemoteCommunicationServer::LaunchProcessForDebugging () { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); @@ -503,20 +532,34 @@ GDBRemoteCommunicationServer::LaunchDebugServerProcess () return error; } - // Setup stdout/stderr mapping from inferior. - auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); - if (terminal_fd >= 0) + // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol as needed. + // llgs local-process debugging may specify PTYs, which will eliminate the need to reflect inferior + // stdout/stderr over the gdb-remote protocol. + if (ShouldRedirectInferiorOutputOverGdbRemote (m_process_launch_info)) { if (log) - log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); - error = SetSTDIOFileDescriptor (terminal_fd); - if (error.Fail ()) - return error; + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " setting up stdout/stderr redirection via $O gdb-remote commands", __FUNCTION__, m_debugged_process_sp->GetID ()); + + // Setup stdout/stderr mapping from inferior to $O + auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); + if (terminal_fd >= 0) + { + if (log) + log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); + error = SetSTDIOFileDescriptor (terminal_fd); + if (error.Fail ()) + return error; + } + else + { + if (log) + log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); + } } else { if (log) - log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " skipping stdout/stderr redirection via $O: inferior will communicate over client-provided file descriptors", __FUNCTION__, m_debugged_process_sp->GetID ()); } printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID ()); @@ -526,33 +569,10 @@ GDBRemoteCommunicationServer::LaunchDebugServerProcess () if ((pid = m_process_launch_info.GetProcessID ()) != LLDB_INVALID_PROCESS_ID) { // add to spawned pids - { - Mutex::Locker locker (m_spawned_pids_mutex); - // On an lldb-gdbserver, we would expect there to be only one. - assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed"); - m_spawned_pids.insert (pid); - } - } - - if (error.Success ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s beginning check to wait for launched application to hit first stop", __FUNCTION__); - - int iteration = 0; - // Wait for the process to hit its first stop state. - while (!StateIsStoppedState (m_debugged_process_sp->GetState (), false)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s waiting for launched process to hit first stop (%d)...", __FUNCTION__, iteration++); - - // FIXME use a finer granularity. - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s launched application has hit first stop", __FUNCTION__); - + Mutex::Locker locker (m_spawned_pids_mutex); + // On an lldb-gdbserver, we would expect there to be only one. + assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed"); + m_spawned_pids.insert (pid); } return error; @@ -699,12 +719,18 @@ GDBRemoteCommunicationServer::SendWResponse (lldb_private::NativeProcessProtocol char return_type_code; switch (exit_type) { - case ExitType::eExitTypeExit: return_type_code = 'W'; break; - case ExitType::eExitTypeSignal: return_type_code = 'X'; break; - case ExitType::eExitTypeStop: return_type_code = 'S'; break; - + case ExitType::eExitTypeExit: + return_type_code = 'W'; + break; + case ExitType::eExitTypeSignal: + return_type_code = 'X'; + break; + case ExitType::eExitTypeStop: + return_type_code = 'S'; + break; case ExitType::eExitTypeInvalid: - default: return_type_code = 'E'; break; + return_type_code = 'E'; + break; } response.PutChar (return_type_code); @@ -861,21 +887,21 @@ GDBRemoteCommunicationServer::SendStopReplyPacketForThread (lldb::tid_t tid) response.Printf ("thread:%" PRIx64 ";", tid); // Include the thread name if there is one. - const char *thread_name = thread_sp->GetName (); - if (thread_name && thread_name[0]) + const std::string thread_name = thread_sp->GetName (); + if (!thread_name.empty ()) { - size_t thread_name_len = strlen(thread_name); + size_t thread_name_len = thread_name.length (); - if (::strcspn (thread_name, "$#+-;:") == thread_name_len) + if (::strcspn (thread_name.c_str (), "$#+-;:") == thread_name_len) { response.PutCString ("name:"); - response.PutCString (thread_name); + response.PutCString (thread_name.c_str ()); } else { // The thread name contains special chars, send as hex bytes. response.PutCString ("hexname:"); - response.PutCStringAsRawHex8 (thread_name); + response.PutCStringAsRawHex8 (thread_name.c_str ()); } response.PutChar (';'); } @@ -1197,7 +1223,7 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet ArchSpec host_arch(HostInfo::GetArchitecture()); const llvm::Triple &host_triple = host_arch.GetTriple(); response.PutCString("triple:"); - response.PutCString(host_triple.getTriple().c_str()); + response.PutCStringAsRawHex8(host_triple.getTriple().c_str()); response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize()); const char* distribution_id = host_arch.GetDistributionId ().AsCString (); @@ -1252,7 +1278,6 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet } std::string s; -#if !defined(__linux__) if (HostInfo::GetOSBuildString(s)) { response.PutCString ("os_build:"); @@ -1265,7 +1290,6 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } -#endif #if defined(__APPLE__) @@ -1315,7 +1339,7 @@ CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &r { const llvm::Triple &proc_triple = proc_arch.GetTriple(); response.PutCString("triple:"); - response.PutCString(proc_triple.getTriple().c_str()); + response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); response.PutChar(';'); } } @@ -1351,7 +1375,10 @@ CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info response.Printf ("vendor:%s;", vendor.c_str ()); #else // We'll send the triple. - response.Printf ("triple:%s;", proc_triple.getTriple().c_str ()); + response.PutCString("triple:"); + response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); + response.PutChar(';'); + #endif std::string ostype = proc_triple.getOSName (); // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. @@ -2372,8 +2399,6 @@ GDBRemoteCommunicationServer::Handle_vCont_actions (StringExtractorGDBRemote &pa return SendUnimplementedResponse (packet.GetStringRef().c_str()); } - // We handle $vCont messages for c. - // TODO add C, s and S. StreamString response; response.Printf("vCont;c;C;s;S"); @@ -3388,10 +3413,8 @@ GDBRemoteCommunicationServer::Handle_interrupt (StringExtractorGDBRemote &packet return SendErrorResponse (0x15); } - // Build the ResumeActionList - stop everything. - lldb_private::ResumeActionList actions (StateType::eStateStopped, 0); - - Error error = m_debugged_process_sp->Resume (actions); + // Interrupt the process. + Error error = m_debugged_process_sp->Interrupt (); if (error.Fail ()) { if (log) @@ -3771,7 +3794,7 @@ GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet) } // Parse out software or hardware breakpoint requested. - packet.SetFilePos (strlen("Z")); + packet.SetFilePos (strlen("z")); if (packet.GetBytesLeft() < 1) return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier"); @@ -3811,7 +3834,7 @@ GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet) if (want_breakpoint) { - // Try to set the breakpoint. + // Try to clear the breakpoint. const Error error = m_debugged_process_sp->RemoveBreakpoint (breakpoint_addr); if (error.Success ()) return SendOKResponse (); @@ -4171,8 +4194,93 @@ GDBRemoteCommunicationServer::Handle_vAttach (StringExtractorGDBRemote &packet) // Notify we attached by sending a stop packet. return SendStopReasonForState (m_debugged_process_sp->GetState (), true); +} - return PacketResult::Success; +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_D (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("only supported for lldb-gdbserver"); + + // Scope for mutex locker. + Mutex::Locker locker (m_spawned_pids_mutex); + + // Fail if we don't have a current process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); + return SendErrorResponse (0x15); + } + + if (m_spawned_pids.find(m_debugged_process_sp->GetID ()) == m_spawned_pids.end()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to find PID %" PRIu64 " in spawned pids list", + __FUNCTION__, m_debugged_process_sp->GetID ()); + return SendErrorResponse (0x1); + } + + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + + // Consume the ';' after D. + packet.SetFilePos (1); + if (packet.GetBytesLeft ()) + { + if (packet.GetChar () != ';') + return SendIllFormedResponse (packet, "D missing expected ';'"); + + // Grab the PID from which we will detach (assume hex encoding). + pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendIllFormedResponse (packet, "D failed to parse the process id"); + } + + if (pid != LLDB_INVALID_PROCESS_ID && + m_debugged_process_sp->GetID () != pid) + { + return SendIllFormedResponse (packet, "Invalid pid"); + } + + if (m_stdio_communication.IsConnected ()) + { + m_stdio_communication.StopReadThread (); + } + + const Error error = m_debugged_process_sp->Detach (); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to detach from pid %" PRIu64 ": %s\n", + __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); + return SendErrorResponse (0x01); + } + + m_spawned_pids.erase (m_debugged_process_sp->GetID ()); + return SendOKResponse (); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_qThreadStopInfo (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("only supported for lldb-gdbserver"); + + packet.SetFilePos (strlen("qThreadStopInfo")); + const lldb::tid_t tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); + if (tid == LLDB_INVALID_THREAD_ID) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse thread id from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); + return SendErrorResponse (0x15); + } + return SendStopReplyPacketForThread (tid); } void diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 13c037c0287b2..07ce98e29ac6b 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -58,7 +58,7 @@ public: bool &quit); virtual bool - GetThreadSuffixSupported () + GetThreadSuffixSupported () override { return true; } @@ -152,8 +152,6 @@ public: //------------------------------------------------------------------ /// Specify the program to launch and its arguments. /// - /// The LaunchProcess () command can be executed to do the lauching. - /// /// @param[in] args /// The command line to launch. /// @@ -170,8 +168,6 @@ public: //------------------------------------------------------------------ /// Specify the launch flags for the process. /// - /// The LaunchProcess () command can be executed to do the lauching. - /// /// @param[in] launch_flags /// The launch flags to use when launching this process. /// @@ -463,6 +459,12 @@ protected: PacketResult Handle_vAttach (StringExtractorGDBRemote &packet); + PacketResult + Handle_D (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qThreadStopInfo (StringExtractorGDBRemote &packet); + void SetCurrentThreadID (lldb::tid_t tid); @@ -511,9 +513,9 @@ private: return !m_is_platform; } - /// Launch a process from lldb-gdbserver + /// Launch an inferior process from lldb-gdbserver lldb_private::Error - LaunchDebugServerProcess (); + LaunchProcessForDebugging (); /// Launch a process from lldb-platform lldb_private::Error @@ -540,6 +542,9 @@ private: void ClearProcessSpecificData (); + bool + ShouldRedirectInferiorOutputOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const; + //------------------------------------------------------------------ // For GDBRemoteCommunicationServer only //------------------------------------------------------------------ diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index f35d954caa7b1..fe99706969c85 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -14,7 +14,6 @@ #include <errno.h> #include <stdlib.h> #ifndef LLDB_DISABLE_POSIX -#include <spawn.h> #include <netinet/in.h> #include <sys/mman.h> // for mmap #endif @@ -32,7 +31,7 @@ #include "lldb/Interpreter/Args.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Debugger.h" -#include "lldb/Core/ConnectionFileDescriptor.h" +#include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" @@ -42,7 +41,9 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" #include "lldb/Core/Value.h" +#include "lldb/Host/HostThread.h" #include "lldb/Host/Symbols.h" +#include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/TimeValue.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" @@ -272,8 +273,6 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) : m_last_stop_packet_mutex (Mutex::eMutexTypeNormal), m_register_info (), m_async_broadcaster (NULL, "lldb.process.gdb-remote.async-broadcaster"), - m_async_thread (LLDB_INVALID_HOST_THREAD), - m_async_thread_state(eAsyncThreadNotStarted), m_async_thread_state_mutex(Mutex::eMutexTypeRecursive), m_thread_ids (), m_continue_c_tids (), @@ -749,8 +748,12 @@ ProcessGDBRemote::WillLaunchOrAttach () Error ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) { + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); Error error; + if (log) + log->Printf ("ProcessGDBRemote::%s() entered", __FUNCTION__); + uint32_t launch_flags = launch_info.GetFlags().Get(); const char *stdin_path = NULL; const char *stdout_path = NULL; @@ -777,10 +780,21 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) stderr_path = file_action->GetPath(); } + if (log) + { + if (stdin_path || stdout_path || stderr_path) + log->Printf ("ProcessGDBRemote::%s provided with STDIO paths via launch_info: stdin=%s, stdout=%s, stdout=%s", + __FUNCTION__, + stdin_path ? stdin_path : "<null>", + stdout_path ? stdout_path : "<null>", + stderr_path ? stderr_path : "<null>"); + else + log->Printf ("ProcessGDBRemote::%s no STDIO paths given via launch_info", __FUNCTION__); + } + // ::LogSetBitMask (GDBR_LOG_DEFAULT); // ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD); // ::LogSetLogFile ("/dev/stdout"); - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); ObjectFile * object_file = exe_module->GetObjectFile(); if (object_file) @@ -817,6 +831,13 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) if (stderr_path == NULL) stderr_path = slave_name; + + if (log) + log->Printf ("ProcessGDBRemote::%s adjusted STDIO paths for local platform (IsHost() is true) using slave: stdin=%s, stdout=%s, stdout=%s", + __FUNCTION__, + stdin_path ? stdin_path : "<null>", + stdout_path ? stdout_path : "<null>", + stderr_path ? stderr_path : "<null>"); } // Set STDIN to /dev/null if we want STDIO disabled or if either @@ -834,7 +855,14 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) if (disable_stdio || (stderr_path == NULL && (stdin_path || stdout_path))) stderr_path = "/dev/null"; - if (stdin_path) + if (log) + log->Printf ("ProcessGDBRemote::%s final STDIO paths after all adjustments: stdin=%s, stdout=%s, stdout=%s", + __FUNCTION__, + stdin_path ? stdin_path : "<null>", + stdout_path ? stdout_path : "<null>", + stderr_path ? stderr_path : "<null>"); + + if (stdin_path) m_gdb_comm.SetSTDIN (stdin_path); if (stdout_path) m_gdb_comm.SetSTDOUT (stdout_path); @@ -1026,18 +1054,38 @@ ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch) // prefer that over the Host information as it will be more specific // to our process. - if (m_gdb_comm.GetProcessArchitecture().IsValid()) - process_arch = m_gdb_comm.GetProcessArchitecture(); + const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); + if (remote_process_arch.IsValid()) + { + process_arch = remote_process_arch; + if (log) + log->Printf ("ProcessGDBRemote::%s gdb-remote had process architecture, using %s %s", + __FUNCTION__, + process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>", + process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>"); + } else + { process_arch = m_gdb_comm.GetHostArchitecture(); + if (log) + log->Printf ("ProcessGDBRemote::%s gdb-remote did not have process architecture, using gdb-remote host architecture %s %s", + __FUNCTION__, + process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>", + process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>"); + } if (process_arch.IsValid()) { ArchSpec &target_arch = GetTarget().GetArchitecture(); - if (target_arch.IsValid()) { - // If the remote host is ARM and we have apple as the vendor, then + if (log) + log->Printf ("ProcessGDBRemote::%s analyzing target arch, currently %s %s", + __FUNCTION__, + target_arch.GetArchitectureName () ? target_arch.GetArchitectureName () : "<null>", + target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : "<null>"); + + // If the remote host is ARM and we have apple as the vendor, then // ARM executables and shared libraries can have mixed ARM architectures. // You can have an armv6 executable, and if the host is armv7, then the // system will load the best possible architecture for all shared libraries @@ -1048,6 +1096,11 @@ ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch) process_arch.GetTriple().getVendor() == llvm::Triple::Apple) { GetTarget().SetArchitecture (process_arch); + if (log) + log->Printf ("ProcessGDBRemote::%s remote process is ARM/Apple, setting target arch to %s %s", + __FUNCTION__, + process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>", + process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>"); } else { @@ -1066,7 +1119,14 @@ ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch) target_triple.setEnvironment (remote_triple.getEnvironment()); } } + } + + if (log) + log->Printf ("ProcessGDBRemote::%s final target arch after adjustments for remote architecture: %s %s", + __FUNCTION__, + target_arch.GetArchitectureName () ? target_arch.GetArchitectureName () : "<null>", + target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : "<null>"); } else { @@ -1095,7 +1155,12 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid) Error ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) { + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); Error error; + + if (log) + log->Printf ("ProcessGDBRemote::%s()", __FUNCTION__); + // Clear out and clean up from any current state Clear(); if (attach_pid != LLDB_INVALID_PROCESS_ID) @@ -1118,13 +1183,14 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process if (error.Success()) { m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); - + char packet[64]; const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid); SetID (attach_pid); m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet, packet_len)); } } + return error; } @@ -1432,7 +1498,7 @@ ProcessGDBRemote::DoResume () TimeValue timeout; timeout = TimeValue::Now(); timeout.OffsetWithSeconds (5); - if (!IS_VALID_LLDB_HOST_THREAD(m_async_thread)) + if (!m_async_thread.IsJoinable()) { error.SetErrorString ("Trying to resume but the async thread is dead."); if (log) @@ -2891,30 +2957,17 @@ ProcessGDBRemote::StartAsyncThread () log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__); Mutex::Locker start_locker(m_async_thread_state_mutex); - if (m_async_thread_state == eAsyncThreadNotStarted) + if (!m_async_thread.IsJoinable()) { // Create a thread that watches our internal state and controls which // events make it to clients (into the DCProcess event queue). - m_async_thread = Host::ThreadCreate ("<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this, NULL); - if (IS_VALID_LLDB_HOST_THREAD(m_async_thread)) - { - m_async_thread_state = eAsyncThreadRunning; - return true; - } - else - return false; - } - else - { - // Somebody tried to start the async thread while it was either being started or stopped. If the former, and - // it started up successfully, then say all's well. Otherwise it is an error, since we aren't going to restart it. - if (log) - log->Printf ("ProcessGDBRemote::%s () - Called when Async thread was in state: %d.", __FUNCTION__, m_async_thread_state); - if (m_async_thread_state == eAsyncThreadRunning) - return true; - else - return false; + + m_async_thread = ThreadLauncher::LaunchThread("<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this, NULL); } + else if (log) + log->Printf("ProcessGDBRemote::%s () - Called when Async thread was already running.", __FUNCTION__); + + return m_async_thread.IsJoinable(); } void @@ -2926,7 +2979,7 @@ ProcessGDBRemote::StopAsyncThread () log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__); Mutex::Locker start_locker(m_async_thread_state_mutex); - if (m_async_thread_state == eAsyncThreadRunning) + if (m_async_thread.IsJoinable()) { m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit); @@ -2934,17 +2987,10 @@ ProcessGDBRemote::StopAsyncThread () m_gdb_comm.Disconnect(); // Disconnect from the debug server. // Stop the stdio thread - if (IS_VALID_LLDB_HOST_THREAD(m_async_thread)) - { - Host::ThreadJoin (m_async_thread, NULL, NULL); - } - m_async_thread_state = eAsyncThreadDone; - } - else - { - if (log) - log->Printf ("ProcessGDBRemote::%s () - Called when Async thread was in state: %d.", __FUNCTION__, m_async_thread_state); + m_async_thread.Join(nullptr); } + else if (log) + log->Printf("ProcessGDBRemote::%s () - Called when Async thread was not running.", __FUNCTION__); } @@ -3086,7 +3132,7 @@ ProcessGDBRemote::AsyncThread (void *arg) if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, arg, process->GetID()); - process->m_async_thread = LLDB_INVALID_HOST_THREAD; + process->m_async_thread.Reset(); return NULL; } diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 942b31c84dde1..e0c460a202d66 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -25,6 +25,7 @@ #include "lldb/Core/StringList.h" #include "lldb/Core/StructuredData.h" #include "lldb/Core/ThreadSafeValue.h" +#include "lldb/Host/HostThread.h" #include "lldb/lldb-private-forward.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" @@ -74,148 +75,148 @@ public: //------------------------------------------------------------------ virtual bool CanDebug (lldb_private::Target &target, - bool plugin_specified_by_name); + bool plugin_specified_by_name) override; virtual lldb_private::CommandObject * - GetPluginCommandObject(); + GetPluginCommandObject() override; //------------------------------------------------------------------ // Creating a new process, or attaching to an existing one //------------------------------------------------------------------ virtual lldb_private::Error - WillLaunch (lldb_private::Module* module); + WillLaunch (lldb_private::Module* module) override; virtual lldb_private::Error DoLaunch (lldb_private::Module *exe_module, - lldb_private::ProcessLaunchInfo &launch_info); + lldb_private::ProcessLaunchInfo &launch_info) override; virtual void - DidLaunch (); + DidLaunch () override; virtual lldb_private::Error - WillAttachToProcessWithID (lldb::pid_t pid); + WillAttachToProcessWithID (lldb::pid_t pid) override; virtual lldb_private::Error - WillAttachToProcessWithName (const char *process_name, bool wait_for_launch); + WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) override; virtual lldb_private::Error - DoConnectRemote (lldb_private::Stream *strm, const char *remote_url); + DoConnectRemote (lldb_private::Stream *strm, const char *remote_url) override; lldb_private::Error WillLaunchOrAttach (); virtual lldb_private::Error - DoAttachToProcessWithID (lldb::pid_t pid); + DoAttachToProcessWithID (lldb::pid_t pid) override; virtual lldb_private::Error - DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info); + DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override; virtual lldb_private::Error DoAttachToProcessWithName (const char *process_name, - const lldb_private::ProcessAttachInfo &attach_info); + const lldb_private::ProcessAttachInfo &attach_info) override; virtual void - DidAttach (lldb_private::ArchSpec &process_arch); + DidAttach (lldb_private::ArchSpec &process_arch) override; //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ virtual lldb_private::ConstString - GetPluginName(); + GetPluginName() override; virtual uint32_t - GetPluginVersion(); + GetPluginVersion() override; //------------------------------------------------------------------ // Process Control //------------------------------------------------------------------ virtual lldb_private::Error - WillResume (); + WillResume () override; virtual lldb_private::Error - DoResume (); + DoResume () override; virtual lldb_private::Error - DoHalt (bool &caused_stop); + DoHalt (bool &caused_stop) override; virtual lldb_private::Error - DoDetach (bool keep_stopped); + DoDetach (bool keep_stopped) override; virtual bool - DetachRequiresHalt() { return true; } + DetachRequiresHalt() override { return true; } virtual lldb_private::Error - DoSignal (int signal); + DoSignal (int signal) override; virtual lldb_private::Error - DoDestroy (); + DoDestroy () override; virtual void - RefreshStateAfterStop(); + RefreshStateAfterStop() override; //------------------------------------------------------------------ // Process Queries //------------------------------------------------------------------ virtual bool - IsAlive (); + IsAlive () override; virtual lldb::addr_t - GetImageInfoAddress(); + GetImageInfoAddress() override; //------------------------------------------------------------------ // Process Memory //------------------------------------------------------------------ virtual size_t - DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error); + DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override; virtual size_t - DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error); + DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error) override; virtual lldb::addr_t - DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error); + DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error) override; virtual lldb_private::Error GetMemoryRegionInfo (lldb::addr_t load_addr, - lldb_private::MemoryRegionInfo ®ion_info); + lldb_private::MemoryRegionInfo ®ion_info) override; virtual lldb_private::Error - DoDeallocateMemory (lldb::addr_t ptr); + DoDeallocateMemory (lldb::addr_t ptr) override; //------------------------------------------------------------------ // Process STDIO //------------------------------------------------------------------ virtual size_t - PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error); + PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error) override; //---------------------------------------------------------------------- // Process Breakpoints //---------------------------------------------------------------------- virtual lldb_private::Error - EnableBreakpointSite (lldb_private::BreakpointSite *bp_site); + EnableBreakpointSite (lldb_private::BreakpointSite *bp_site) override; virtual lldb_private::Error - DisableBreakpointSite (lldb_private::BreakpointSite *bp_site); + DisableBreakpointSite (lldb_private::BreakpointSite *bp_site) override; //---------------------------------------------------------------------- // Process Watchpoints //---------------------------------------------------------------------- virtual lldb_private::Error - EnableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true); + EnableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true) override; virtual lldb_private::Error - DisableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true); + DisableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true) override; virtual lldb_private::Error - GetWatchpointSupportInfo (uint32_t &num); + GetWatchpointSupportInfo (uint32_t &num) override; virtual lldb_private::Error - GetWatchpointSupportInfo (uint32_t &num, bool& after); + GetWatchpointSupportInfo (uint32_t &num, bool& after) override; virtual bool - StartNoticingNewThreads(); + StartNoticingNewThreads() override; virtual bool - StopNoticingNewThreads(); + StopNoticingNewThreads() override; GDBRemoteCommunicationClient & GetGDBRemote() @@ -224,13 +225,13 @@ public: } virtual lldb_private::Error - SendEventData(const char *data); + SendEventData(const char *data) override; //---------------------------------------------------------------------- // Override SetExitStatus so we can disconnect from the remote GDB server //---------------------------------------------------------------------- virtual bool - SetExitStatus (int exit_status, const char *cstr); + SetExitStatus (int exit_status, const char *cstr) override; void SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max); @@ -286,7 +287,7 @@ protected: virtual bool UpdateThreadList (lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list); + lldb_private::ThreadList &new_thread_list) override; lldb_private::Error LaunchAndConnectToDebugserver (const lldb_private::ProcessInfo &process_info); @@ -324,23 +325,15 @@ protected: eBroadcastBitAsyncThreadShouldExit = (1 << 1), eBroadcastBitAsyncThreadDidExit = (1 << 2) }; - - typedef enum AsyncThreadState - { - eAsyncThreadNotStarted, - eAsyncThreadRunning, - eAsyncThreadDone - } AsyncThreadState; lldb_private::Flags m_flags; // Process specific flags (see eFlags enums) GDBRemoteCommunicationClient m_gdb_comm; - lldb::pid_t m_debugserver_pid; + std::atomic<lldb::pid_t> m_debugserver_pid; StringExtractorGDBRemote m_last_stop_packet; lldb_private::Mutex m_last_stop_packet_mutex; GDBRemoteDynamicRegisterInfo m_register_info; lldb_private::Broadcaster m_async_broadcaster; - lldb::thread_t m_async_thread; - AsyncThreadState m_async_thread_state; + lldb_private::HostThread m_async_thread; lldb_private::Mutex m_async_thread_state_mutex; typedef std::vector<lldb::tid_t> tid_collection; typedef std::vector< std::pair<lldb::tid_t,int> > tid_sig_collection; @@ -395,7 +388,7 @@ protected: std::string &dispatch_queue_name); lldb_private::DynamicLoader * - GetDynamicLoader (); + GetDynamicLoader () override; private: //------------------------------------------------------------------ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp index bc2e7a62b76ef..14fc2cea23299 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp @@ -73,14 +73,14 @@ DWARFAbbreviationDeclaration::Extract(const DWARFDataExtractor& data, lldb::offs void DWARFAbbreviationDeclaration::Dump(Stream *s) const { -// *ostrm_ptr << std::setfill(' ') << std::dec << '[' << std::setw(3) << std::right << m_code << ']' << ' ' << std::setw(30) << std::left << DW_TAG_value_to_name(m_tag) << DW_CHILDREN_value_to_name(m_has_children) << std::endl; -// -// DWARFAttribute::const_iterator pos; -// -// for (pos = m_attributes.begin(); pos != m_attributes.end(); ++pos) -// *ostrm_ptr << " " << std::setw(29) << std::left << DW_AT_value_to_name(pos->attr()) << ' ' << DW_FORM_value_to_name(pos->form()) << std::endl; -// -// *ostrm_ptr << std::endl; + s->Printf("Debug Abbreviation Declaration: code = 0x%4.4x, tag = %s, has_children = %s\n", m_code, DW_TAG_value_to_name(m_tag), DW_CHILDREN_value_to_name(m_has_children)); + + DWARFAttribute::const_iterator pos; + + for (pos = m_attributes.begin(); pos != m_attributes.end(); ++pos) + s->Printf(" attr = %s, form = %s\n", DW_AT_value_to_name(pos->get_attr()), DW_FORM_value_to_name(pos->get_form())); + + s->Printf("\n"); } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index b2e64ad9f8c83..067449a289be0 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -49,7 +49,8 @@ DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF* dwarf2Data) : m_producer (eProducerInvalid), m_producer_version_major (0), m_producer_version_minor (0), - m_producer_version_update (0) + m_producer_version_update (0), + m_is_dwarf64 (false) { } @@ -66,6 +67,7 @@ DWARFCompileUnit::Clear() m_func_aranges_ap.reset(); m_user_data = NULL; m_producer = eProducerInvalid; + m_is_dwarf64 = false; } bool @@ -79,9 +81,10 @@ DWARFCompileUnit::Extract(const DWARFDataExtractor &debug_info, lldb::offset_t * { dw_offset_t abbr_offset; const DWARFDebugAbbrev *abbr = m_dwarf2Data->DebugAbbrev(); - m_length = debug_info.GetU32(offset_ptr); + m_length = debug_info.GetDWARFInitialLength(offset_ptr); + m_is_dwarf64 = debug_info.IsDWARF64(); m_version = debug_info.GetU16(offset_ptr); - abbr_offset = debug_info.GetU32(offset_ptr); + abbr_offset = debug_info.GetDWARFOffset(offset_ptr); m_addr_size = debug_info.GetU8 (offset_ptr); bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset()-1); @@ -168,7 +171,7 @@ DWARFCompileUnit::ExtractDIEsIfNeeded (bool cu_die_only) die_index_stack.reserve(32); die_index_stack.push_back(0); bool prev_die_had_children = false; - const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize()); + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize(), m_is_dwarf64); while (offset < next_cu_offset && die.FastExtract (debug_info_data, this, fixed_form_sizes, &offset)) { @@ -347,6 +350,14 @@ DWARFCompileUnit::GetAddressByteSize(const DWARFCompileUnit* cu) return DWARFCompileUnit::GetDefaultAddressSize(); } +bool +DWARFCompileUnit::IsDWARF64(const DWARFCompileUnit* cu) +{ + if (cu) + return cu->IsDWARF64(); + return false; +} + uint8_t DWARFCompileUnit::GetDefaultAddressSize() { @@ -619,7 +630,7 @@ DWARFCompileUnit::Index (const uint32_t cu_idx, { const DWARFDataExtractor* debug_str = &m_dwarf2Data->get_debug_str_data(); - const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize()); + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize(), m_is_dwarf64); Log *log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_LOOKUPS)); @@ -761,7 +772,7 @@ DWARFCompileUnit::Index (const uint32_t cu_idx, case DW_AT_specification: if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value)) - specification_die_offset = form_value.Reference(this); + specification_die_offset = form_value.Reference(); break; } } @@ -1030,3 +1041,9 @@ DWARFCompileUnit::GetProducerVersionUpdate() return m_producer_version_update; } +bool +DWARFCompileUnit::IsDWARF64() const +{ + return m_is_dwarf64; +} + diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index ed1894b8a9f6b..3e904892dbd5a 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -41,11 +41,11 @@ public: bool Verify(lldb_private::Stream *s) const; void Dump(lldb_private::Stream *s) const; dw_offset_t GetOffset() const { return m_offset; } - uint32_t Size() const { return 11; /* Size in bytes of the compile unit header */ } + uint32_t Size() const { return m_is_dwarf64 ? 23 : 11; /* Size in bytes of the compile unit header */ } bool ContainsDIEOffset(dw_offset_t die_offset) const { return die_offset >= GetFirstDIEOffset() && die_offset < GetNextCompileUnitOffset(); } dw_offset_t GetFirstDIEOffset() const { return m_offset + Size(); } - dw_offset_t GetNextCompileUnitOffset() const { return m_offset + m_length + 4; } - size_t GetDebugInfoSize() const { return m_length + 4 - Size(); /* Size in bytes of the .debug_info data associated with this compile unit. */ } + dw_offset_t GetNextCompileUnitOffset() const { return m_offset + m_length + (m_is_dwarf64 ? 12 : 4); } + size_t GetDebugInfoSize() const { return m_length + (m_is_dwarf64 ? 12 : 4) - Size(); /* Size in bytes of the .debug_info data associated with this compile unit. */ } uint32_t GetLength() const { return m_length; } uint16_t GetVersion() const { return m_version; } const DWARFAbbreviationDeclarationSet* GetAbbreviations() const { return m_abbrevs; } @@ -118,6 +118,9 @@ public: static uint8_t GetAddressByteSize(const DWARFCompileUnit* cu); + static bool + IsDWARF64(const DWARFCompileUnit* cu); + static uint8_t GetDefaultAddressSize(); @@ -183,6 +186,9 @@ public: uint32_t GetProducerVersionUpdate(); + bool + IsDWARF64() const; + protected: SymbolFileDWARF* m_dwarf2Data; const DWARFAbbreviationDeclarationSet *m_abbrevs; @@ -191,13 +197,14 @@ protected: std::unique_ptr<DWARFDebugAranges> m_func_aranges_ap; // A table similar to the .debug_aranges table, but this one points to the exact DW_TAG_subprogram DIEs dw_addr_t m_base_addr; dw_offset_t m_offset; - uint32_t m_length; + dw_offset_t m_length; uint16_t m_version; uint8_t m_addr_size; Producer m_producer; uint32_t m_producer_version_major; uint32_t m_producer_version_minor; uint32_t m_producer_version_update; + bool m_is_dwarf64; void ParseProducerInfo (); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h index 6e5b974a71ff0..ba2e8ad08accb 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h @@ -33,6 +33,9 @@ public: size_t GetDWARFSizeofInitialLength() const { return m_is_dwarf64 ? 12 : 4; } + bool + IsDWARF64() const { return m_is_dwarf64; } + protected: mutable bool m_is_dwarf64; }; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index a8c553e2d2ca1..393434800c017 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -555,8 +555,15 @@ static dw_offset_t DumpCallback if (dumpInfo->die_offset == DW_INVALID_OFFSET) { // We are dumping everything - cu->Dump(s); - return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this Compile Unit + if (cu) + { + cu->Dump(s); + return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this Compile Unit + } + else + { + return DW_INVALID_OFFSET; + } } else { @@ -568,7 +575,7 @@ static dw_offset_t DumpCallback // We are dumping only a single DIE possibly with it's children and // we must find it's compile unit before we can dump it properly - if (dumpInfo->die_offset < cu->GetFirstDIEOffset()) + if (cu && dumpInfo->die_offset < cu->GetFirstDIEOffset()) { // Not found, maybe the DIE offset provided wasn't correct? // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " was not found." << endl; @@ -577,7 +584,7 @@ static dw_offset_t DumpCallback else { // See if the DIE is in this compile unit? - if (dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) + if (cu && dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) { // This DIE is in this compile unit! if (s->GetVerbose()) @@ -590,7 +597,14 @@ static dw_offset_t DumpCallback else { // Skip to the next compile unit as the DIE isn't in the current one! - return cu->GetNextCompileUnitOffset(); + if (cu) + { + return cu->GetNextCompileUnitOffset(); + } + else + { + return DW_INVALID_OFFSET; + } } } } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 856a7fa7a2ff0..10b51ffe0a8ad 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -88,9 +88,10 @@ DWARFDebugInfoEntry::Attributes::RemoveAttribute(dw_attr_t attr) bool DWARFDebugInfoEntry::Attributes::ExtractFormValueAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, DWARFFormValue &form_value) const { + form_value.SetCompileUnit(CompileUnitAtIndex(i)); form_value.SetForm(FormAtIndex(i)); lldb::offset_t offset = DIEOffsetAtIndex(i); - return form_value.ExtractValue(dwarf2Data->get_debug_info_data(), &offset, CompileUnitAtIndex(i)); + return form_value.ExtractValue(dwarf2Data->get_debug_info_data(), &offset); } uint64_t @@ -107,7 +108,7 @@ DWARFDebugInfoEntry::Attributes::FormValueAsUnsignedAtIndex(SymbolFileDWARF* dwa { DWARFFormValue form_value; if (ExtractFormValueAtIndex(dwarf2Data, i, form_value)) - return form_value.Reference(CompileUnitAtIndex(i)); + return form_value.Reference(); return fail_value; } @@ -190,7 +191,7 @@ DWARFDebugInfoEntry::FastExtract if (cu->GetVersion() <= 2) form_size = cu->GetAddressByteSize(); else - form_size = 4; // 4 bytes for DWARF 32, 8 bytes for DWARF 64, but we don't support DWARF64 yet + form_size = cu->IsDWARF64() ? 8 : 4; break; // 0 sized form @@ -212,7 +213,6 @@ DWARFDebugInfoEntry::FastExtract break; // 4 byte values - case DW_FORM_strp : case DW_FORM_data4 : case DW_FORM_ref4 : form_size = 4; @@ -237,11 +237,12 @@ DWARFDebugInfoEntry::FastExtract form = debug_info_data.GetULEB128 (&offset); break; + case DW_FORM_strp : case DW_FORM_sec_offset : - if (cu->GetAddressByteSize () == 4) - debug_info_data.GetU32 (offset_ptr); - else + if (cu->IsDWARF64 ()) debug_info_data.GetU64 (offset_ptr); + else + debug_info_data.GetU32 (offset_ptr); break; default: @@ -284,7 +285,6 @@ DWARFDebugInfoEntry::Extract const DWARFDataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); // const DWARFDataExtractor& debug_str_data = dwarf2Data->get_debug_str_data(); const uint32_t cu_end_offset = cu->GetNextCompileUnitOffset(); - const uint8_t cu_addr_size = cu->GetAddressByteSize(); lldb::offset_t offset = *offset_ptr; // if (offset >= cu_end_offset) // Log::Error("DIE at offset 0x%8.8x is beyond the end of the current compile unit (0x%8.8x)", m_offset, cu_end_offset); @@ -319,8 +319,8 @@ DWARFDebugInfoEntry::Extract if (isCompileUnitTag && ((attr == DW_AT_entry_pc) || (attr == DW_AT_low_pc))) { - DWARFFormValue form_value(form); - if (form_value.ExtractValue(debug_info_data, &offset, cu)) + DWARFFormValue form_value(cu, form); + if (form_value.ExtractValue(debug_info_data, &offset)) { if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc) ((DWARFCompileUnit*)cu)->SetBaseAddress(form_value.Unsigned()); @@ -348,13 +348,13 @@ DWARFDebugInfoEntry::Extract // Compile unit address sized values case DW_FORM_addr : - form_size = cu_addr_size; + form_size = cu->GetAddressByteSize(); break; case DW_FORM_ref_addr : if (cu->GetVersion() <= 2) - form_size = cu_addr_size; + form_size = cu->GetAddressByteSize(); else - form_size = 4; // 4 bytes for DWARF 32, 8 bytes for DWARF 64, but we don't support DWARF64 yet + form_size = cu->IsDWARF64() ? 8 : 4; break; // 0 sized form @@ -376,10 +376,6 @@ DWARFDebugInfoEntry::Extract break; // 4 byte values - case DW_FORM_strp : - form_size = 4; - break; - case DW_FORM_data4 : case DW_FORM_ref4 : form_size = 4; @@ -404,11 +400,12 @@ DWARFDebugInfoEntry::Extract form_is_indirect = true; break; + case DW_FORM_strp : case DW_FORM_sec_offset : - if (cu->GetAddressByteSize () == 4) - debug_info_data.GetU32 (offset_ptr); - else + if (cu->IsDWARF64 ()) debug_info_data.GetU64 (offset_ptr); + else + debug_info_data.GetU32 (offset_ptr); break; default: @@ -781,8 +778,8 @@ DWARFDebugInfoEntry::GetDIENamesAndRanges for (i=0; i<numAttributes; ++i) { abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); - DWARFFormValue form_value(form); - if (form_value.ExtractValue(debug_info_data, &offset, cu)) + DWARFFormValue form_value(cu, form); + if (form_value.ExtractValue(debug_info_data, &offset)) { switch (attr) { @@ -832,11 +829,11 @@ DWARFDebugInfoEntry::GetDIENamesAndRanges break; case DW_AT_abstract_origin: - die_offsets.push_back(form_value.Reference(cu)); + die_offsets.push_back(form_value.Reference()); break; case DW_AT_specification: - die_offsets.push_back(form_value.Reference(cu)); + die_offsets.push_back(form_value.Reference()); break; case DW_AT_decl_file: @@ -1033,7 +1030,7 @@ DWARFDebugInfoEntry::DumpLocation const char *obj_file_name = NULL; ObjectFile *obj_file = dwarf2Data->GetObjectFile(); if (obj_file) - obj_file_name = obj_file->GetFileSpec().GetFilename().AsCString(); + obj_file_name = obj_file->GetFileSpec().GetFilename().AsCString("<Unknown>"); const char *die_name = GetName (dwarf2Data, cu); s.Printf ("0x%8.8x/0x%8.8x: %-30s (from %s in %s)", cu->GetOffset(), @@ -1077,9 +1074,9 @@ DWARFDebugInfoEntry::DumpAttribute s.Printf( "[%s", DW_FORM_value_to_name(form)); } - DWARFFormValue form_value(form); + DWARFFormValue form_value(cu, form); - if (!form_value.ExtractValue(debug_info_data, offset_ptr, cu)) + if (!form_value.ExtractValue(debug_info_data, offset_ptr)) return; if (show_form) @@ -1097,7 +1094,7 @@ DWARFDebugInfoEntry::DumpAttribute // Always dump form value if verbose is enabled if (verbose) { - form_value.Dump(s, debug_str_data, cu); + form_value.Dump(s, debug_str_data); } @@ -1130,7 +1127,7 @@ DWARFDebugInfoEntry::DumpAttribute if (blockData) { if (!verbose) - form_value.Dump(s, debug_str_data, cu); + form_value.Dump(s, debug_str_data); // Location description is inlined in data in the form value DWARFDataExtractor locationData(debug_info_data, (*offset_ptr) - form_value.Unsigned(), form_value.Unsigned()); @@ -1147,13 +1144,13 @@ DWARFDebugInfoEntry::DumpAttribute if (dwarf2Data) { if ( !verbose ) - form_value.Dump(s, debug_str_data, cu); + form_value.Dump(s, debug_str_data); DWARFLocationList::Dump(s, cu, dwarf2Data->get_debug_loc_data(), debug_loc_offset); } else { if ( !verbose ) - form_value.Dump(s, NULL, cu); + form_value.Dump(s, NULL); } } } @@ -1162,8 +1159,8 @@ DWARFDebugInfoEntry::DumpAttribute case DW_AT_abstract_origin: case DW_AT_specification: { - uint64_t abstract_die_offset = form_value.Reference(cu); - form_value.Dump(s, debug_str_data, cu); + uint64_t abstract_die_offset = form_value.Reference(); + form_value.Dump(s, debug_str_data); // *ostrm_ptr << HEX32 << abstract_die_offset << " ( "; if ( verbose ) s.PutCString(" ( "); GetName(dwarf2Data, cu, abstract_die_offset, s); @@ -1173,9 +1170,9 @@ DWARFDebugInfoEntry::DumpAttribute case DW_AT_type: { - uint64_t type_die_offset = form_value.Reference(cu); + uint64_t type_die_offset = form_value.Reference(); if (!verbose) - form_value.Dump(s, debug_str_data, cu); + form_value.Dump(s, debug_str_data); s.PutCString(" ( "); AppendTypeName(dwarf2Data, cu, type_die_offset, s); s.PutCString(" )"); @@ -1185,7 +1182,7 @@ DWARFDebugInfoEntry::DumpAttribute case DW_AT_ranges: { if ( !verbose ) - form_value.Dump(s, debug_str_data, cu); + form_value.Dump(s, debug_str_data); lldb::offset_t ranges_offset = form_value.Unsigned(); dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0; if (dwarf2Data) @@ -1195,7 +1192,7 @@ DWARFDebugInfoEntry::DumpAttribute default: if ( !verbose ) - form_value.Dump(s, debug_str_data, cu); + form_value.Dump(s, debug_str_data); break; } @@ -1226,13 +1223,12 @@ DWARFDebugInfoEntry::GetAttributes const DWARFDataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); if (fixed_form_sizes == NULL) - fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize(cu->GetAddressByteSize()); + fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize(cu->GetAddressByteSize(), cu->IsDWARF64()); const uint32_t num_attributes = abbrevDecl->NumAttributes(); uint32_t i; dw_attr_t attr; dw_form_t form; - DWARFFormValue form_value; for (i=0; i<num_attributes; ++i) { abbrevDecl->GetAttrAndFormByIndexUnchecked (i, attr, form); @@ -1259,11 +1255,11 @@ DWARFDebugInfoEntry::GetAttributes if ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin)) { - form_value.SetForm(form); - if (form_value.ExtractValue(debug_info_data, &offset, cu)) + DWARFFormValue form_value (cu, form); + if (form_value.ExtractValue(debug_info_data, &offset)) { const DWARFDebugInfoEntry* die = NULL; - dw_offset_t die_offset = form_value.Reference(cu); + dw_offset_t die_offset = form_value.Reference(); if (cu->ContainsDIEOffset(die_offset)) { die = const_cast<DWARFCompileUnit*>(cu)->GetDIEPtr(die_offset); @@ -1331,8 +1327,9 @@ DWARFDebugInfoEntry::GetAttributeValue DWARFFormValue::SkipValue(abbrevDecl->GetFormByIndex(idx++), debug_info_data, &offset, cu); const dw_offset_t attr_offset = offset; + form_value.SetCompileUnit(cu); form_value.SetForm(abbrevDecl->GetFormByIndex(idx)); - if (form_value.ExtractValue(debug_info_data, &offset, cu)) + if (form_value.ExtractValue(debug_info_data, &offset)) { if (end_attr_offset_ptr) *end_attr_offset_ptr = offset; @@ -1423,7 +1420,7 @@ DWARFDebugInfoEntry::GetAttributeValueAsReference { DWARFFormValue form_value; if (GetAttributeValue(dwarf2Data, cu, attr, form_value)) - return form_value.Reference(cu); + return form_value.Reference(); return fail_value; } @@ -1590,7 +1587,7 @@ DWARFDebugInfoEntry::GetName if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value)) { DWARFCompileUnitSP cu_sp_ptr; - const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr); + const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(), &cu_sp_ptr); if (die) return die->GetName(dwarf2Data, cu_sp_ptr.get()); } @@ -1661,7 +1658,7 @@ DWARFDebugInfoEntry::GetPubname // The specification DIE may be in another compile unit so we need // to get a die and its compile unit. DWARFCompileUnitSP cu_sp_ptr; - const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr); + const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(), &cu_sp_ptr); if (die) return die->GetPubname(dwarf2Data, cu_sp_ptr.get()); } @@ -1798,7 +1795,7 @@ DWARFDebugInfoEntry::AppendTypeName DWARFFormValue form_value; if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_type, form_value)) { - uint64_t next_die_offset = form_value.Reference(cu); + uint64_t next_die_offset = form_value.Reference(); result = AppendTypeName(dwarf2Data, cu, next_die_offset, s); } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp index 6a2649463b545..11589aede7086 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp @@ -418,12 +418,16 @@ DWARFDebugLine::ParsePrologue(const DWARFDataExtractor& debug_line_data, lldb::o const char * s; prologue->total_length = debug_line_data.GetDWARFInitialLength(offset_ptr); prologue->version = debug_line_data.GetU16(offset_ptr); - if (prologue->version < 2 || prologue->version > 3) + if (prologue->version < 2 || prologue->version > 4) return false; prologue->prologue_length = debug_line_data.GetDWARFOffset(offset_ptr); const lldb::offset_t end_prologue_offset = prologue->prologue_length + *offset_ptr; prologue->min_inst_length = debug_line_data.GetU8(offset_ptr); + if (prologue->version >= 4) + prologue->maximum_operations_per_instruction = debug_line_data.GetU8(offset_ptr); + else + prologue->maximum_operations_per_instruction = 1; prologue->default_is_stmt = debug_line_data.GetU8(offset_ptr); prologue->line_base = debug_line_data.GetU8(offset_ptr); prologue->line_range = debug_line_data.GetU8(offset_ptr); @@ -486,13 +490,16 @@ DWARFDebugLine::ParseSupportFiles (const lldb::ModuleSP &module_sp, (void)debug_line_data.GetDWARFInitialLength(&offset); const char * s; uint32_t version = debug_line_data.GetU16(&offset); - if (version < 2 || version > 3) + if (version < 2 || version > 4) return false; const dw_offset_t end_prologue_offset = debug_line_data.GetDWARFOffset(&offset) + offset; - // Skip instruction length, default is stmt, line base, line range and - // opcode base, and all opcode lengths + // Skip instruction length, default is stmt, line base, line range offset += 4; + // For DWARF4, skip maximum operations per instruction + if (version >= 4) + offset += 1; + // Skip opcode base, and all opcode lengths const uint8_t opcode_base = debug_line_data.GetU8(&offset); offset += opcode_base - 1; std::vector<std::string> include_directories; @@ -650,7 +657,10 @@ DWARFDebugLine::ParseStatementTable // relocatable address. All of the other statement program opcodes // that affect the address register add a delta to it. This instruction // stores a relocatable value into it instead. - state.address = debug_line_data.GetAddress(offset_ptr); + if (arg_size == 4) + state.address = debug_line_data.GetU32(offset_ptr); + else // arg_size == 8 + state.address = debug_line_data.GetU64(offset_ptr); break; case DW_LNE_define_file: diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h index 0caaf596add58..7da0e76a22be3 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h @@ -75,6 +75,7 @@ public: uint16_t version; // Version identifier for the statement information format. uint32_t prologue_length;// The number of bytes following the prologue_length field to the beginning of the first byte of the statement program itself. uint8_t min_inst_length;// The size in bytes of the smallest target machine instruction. Statement program opcodes that alter the address register first multiply their operands by this value. + uint8_t maximum_operations_per_instruction; // New in DWARF4. The maximum number of individual operations that may be encoded in an instruction. uint8_t default_is_stmt;// The initial value of theis_stmtregister. int8_t line_base; // This parameter affects the meaning of the special opcodes. See below. uint8_t line_range; // This parameter affects the meaning of the special opcodes. See below. diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp index 488e9820b6fab..8469b78d0dd56 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp @@ -87,7 +87,7 @@ DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data) DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); - const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize()); + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize(), cu->IsDWARF64()); bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index ab8e68ab5516e..a8c550e9176f2 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -96,36 +96,92 @@ g_form_sizes_addr8[] = 8, // 0x20 DW_FORM_ref_sig8 }; +// Difference with g_form_sizes_addr8: +// DW_FORM_strp and DW_FORM_sec_offset are 8 instead of 4 +static uint8_t +g_form_sizes_addr8_dwarf64[] = +{ + 0, // 0x00 unused + 8, // 0x01 DW_FORM_addr + 0, // 0x02 unused + 0, // 0x03 DW_FORM_block2 + 0, // 0x04 DW_FORM_block4 + 2, // 0x05 DW_FORM_data2 + 4, // 0x06 DW_FORM_data4 + 8, // 0x07 DW_FORM_data8 + 0, // 0x08 DW_FORM_string + 0, // 0x09 DW_FORM_block + 0, // 0x0a DW_FORM_block1 + 1, // 0x0b DW_FORM_data1 + 1, // 0x0c DW_FORM_flag + 0, // 0x0d DW_FORM_sdata + 8, // 0x0e DW_FORM_strp + 0, // 0x0f DW_FORM_udata + 0, // 0x10 DW_FORM_ref_addr (addr size for DWARF2 and earlier, 4 bytes for DWARF32, 8 bytes for DWARF32 in DWARF 3 and later + 1, // 0x11 DW_FORM_ref1 + 2, // 0x12 DW_FORM_ref2 + 4, // 0x13 DW_FORM_ref4 + 8, // 0x14 DW_FORM_ref8 + 0, // 0x15 DW_FORM_ref_udata + 0, // 0x16 DW_FORM_indirect + 8, // 0x17 DW_FORM_sec_offset + 0, // 0x18 DW_FORM_exprloc + 0, // 0x19 DW_FORM_flag_present + 0, // 0x1a + 0, // 0x1b + 0, // 0x1c + 0, // 0x1d + 0, // 0x1e + 0, // 0x1f + 8, // 0x20 DW_FORM_ref_sig8 +}; + const uint8_t * -DWARFFormValue::GetFixedFormSizesForAddressSize (uint8_t addr_size) +DWARFFormValue::GetFixedFormSizesForAddressSize (uint8_t addr_size, bool is_dwarf64) { - switch (addr_size) - { - case 4: return g_form_sizes_addr4; - case 8: return g_form_sizes_addr8; + if (!is_dwarf64) { + switch (addr_size) + { + case 4: return g_form_sizes_addr4; + case 8: return g_form_sizes_addr8; + } + } else { + if (addr_size == 8) + return g_form_sizes_addr8_dwarf64; + // is_dwarf64 && addr_size == 4 : no provider does this. } return NULL; } -DWARFFormValue::DWARFFormValue(dw_form_t form) : +DWARFFormValue::DWARFFormValue() : + m_cu (NULL), + m_form(0), + m_value() +{ +} + +DWARFFormValue::DWARFFormValue(const DWARFCompileUnit* cu, dw_form_t form) : + m_cu (cu), m_form(form), m_value() { } bool -DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* offset_ptr, const DWARFCompileUnit* cu) +DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* offset_ptr) { bool indirect = false; bool is_block = false; m_value.data = NULL; + uint8_t ref_addr_size; // Read the value for the form into value and follow and DW_FORM_indirect instances we run into do { indirect = false; switch (m_form) { - case DW_FORM_addr: m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu)); break; + case DW_FORM_addr: assert(m_cu); + m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(m_cu)); break; case DW_FORM_block2: m_value.value.uval = data.GetU16(offset_ptr); is_block = true; break; case DW_FORM_block4: m_value.value.uval = data.GetU32(offset_ptr); is_block = true; break; case DW_FORM_data2: m_value.value.uval = data.GetU16(offset_ptr); break; @@ -142,15 +198,17 @@ DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* off case DW_FORM_data1: m_value.value.uval = data.GetU8(offset_ptr); break; case DW_FORM_flag: m_value.value.uval = data.GetU8(offset_ptr); break; case DW_FORM_sdata: m_value.value.sval = data.GetSLEB128(offset_ptr); break; - case DW_FORM_strp: m_value.value.uval = data.GetU32(offset_ptr); break; + case DW_FORM_strp: assert(m_cu); + m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); break; // case DW_FORM_APPLE_db_str: case DW_FORM_udata: m_value.value.uval = data.GetULEB128(offset_ptr); break; - case DW_FORM_ref_addr: - if (cu->GetVersion() <= 2) - m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu)); - else - m_value.value.uval = data.GetU32(offset_ptr); // 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet - break; + case DW_FORM_ref_addr: assert(m_cu); + ref_addr_size = 4; + if (m_cu->GetVersion() <= 2) + ref_addr_size = m_cu->GetAddressByteSize(); + else + ref_addr_size = m_cu->IsDWARF64() ? 8 : 4; + m_value.value.uval = data.GetMaxU64(offset_ptr, ref_addr_size); break; case DW_FORM_ref1: m_value.value.uval = data.GetU8(offset_ptr); break; case DW_FORM_ref2: m_value.value.uval = data.GetU16(offset_ptr); break; case DW_FORM_ref4: m_value.value.uval = data.GetU32(offset_ptr); break; @@ -161,7 +219,8 @@ DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* off indirect = true; break; - case DW_FORM_sec_offset: m_value.value.uval = data.GetU32(offset_ptr); break; + case DW_FORM_sec_offset: assert(m_cu); + m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); break; case DW_FORM_flag_present: m_value.value.uval = 1; break; case DW_FORM_ref_sig8: m_value.value.uval = data.GetU64(offset_ptr); break; default: @@ -183,14 +242,15 @@ DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* off } bool -DWARFFormValue::SkipValue(const DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu) const +DWARFFormValue::SkipValue(const DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr) const { - return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, cu); + return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, m_cu); } bool DWARFFormValue::SkipValue(dw_form_t form, const DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu) { + uint8_t ref_addr_size; switch (form) { // Blocks if inlined data that have a length field and the data bytes @@ -212,10 +272,13 @@ DWARFFormValue::SkipValue(dw_form_t form, const DWARFDataExtractor& debug_info_d return true; case DW_FORM_ref_addr: + ref_addr_size = 4; + assert (cu); // CU must be valid for DW_FORM_ref_addr objects or we will get this wrong if (cu->GetVersion() <= 2) - *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu); + ref_addr_size = cu->GetAddressByteSize(); else - *offset_ptr += 4;// 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet + ref_addr_size = cu->IsDWARF64() ? 8 : 4; + *offset_ptr += ref_addr_size; return true; // 0 bytes values (implied from DW_FORM) @@ -237,11 +300,12 @@ DWARFFormValue::SkipValue(dw_form_t form, const DWARFDataExtractor& debug_info_d // 32 bit for DWARF 32, 64 for DWARF 64 case DW_FORM_sec_offset: - *offset_ptr += 4; + case DW_FORM_strp: + assert(cu); + *offset_ptr += (cu->IsDWARF64() ? 8 : 4); return true; // 4 byte values - case DW_FORM_strp: case DW_FORM_data4: case DW_FORM_ref4: *offset_ptr += 4; @@ -278,7 +342,7 @@ DWARFFormValue::SkipValue(dw_form_t form, const DWARFDataExtractor& debug_info_d void -DWARFFormValue::Dump(Stream &s, const DWARFDataExtractor* debug_str_data, const DWARFCompileUnit* cu) const +DWARFFormValue::Dump(Stream &s, const DWARFDataExtractor* debug_str_data) const { uint64_t uvalue = Unsigned(); bool cu_relative_offset = false; @@ -348,7 +412,8 @@ DWARFFormValue::Dump(Stream &s, const DWARFDataExtractor* debug_str_data, const case DW_FORM_ref_addr: { - if (cu->GetVersion() <= 2) + assert (m_cu); // CU must be valid for DW_FORM_ref_addr objects or we will get this wrong + if (m_cu->GetVersion() <= 2) s.Address(uvalue, sizeof (uint64_t) * 2); else s.Address(uvalue, 4 * 2);// 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet @@ -370,10 +435,11 @@ DWARFFormValue::Dump(Stream &s, const DWARFDataExtractor* debug_str_data, const if (cu_relative_offset) { + assert (m_cu); // CU must be valid for DW_FORM_ref forms that are compile unit relative or we will get this wrong if (verbose) s.PutCString(" => "); - s.Printf("{0x%8.8" PRIx64 "}", (uvalue + (cu ? cu->GetOffset() : 0))); + s.Printf("{0x%8.8" PRIx64 "}", uvalue + m_cu->GetOffset()); } } @@ -388,7 +454,7 @@ DWARFFormValue::AsCString(const DWARFDataExtractor* debug_str_data_ptr) const } uint64_t -DWARFFormValue::Reference(const DWARFCompileUnit* cu) const +DWARFFormValue::Reference() const { uint64_t die_offset = m_value.value.uval; switch (m_form) @@ -398,7 +464,8 @@ DWARFFormValue::Reference(const DWARFCompileUnit* cu) const case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: - die_offset += (cu ? cu->GetOffset() : 0); + assert (m_cu); // CU must be valid for DW_FORM_ref forms that are compile unit relative or we will get this wrong + die_offset += m_cu->GetOffset(); break; default: @@ -429,32 +496,6 @@ DWARFFormValue::Reference (dw_offset_t base_offset) const return die_offset; } -//---------------------------------------------------------------------- -// Resolve any compile unit specific references so that we don't need -// the compile unit at a later time in order to work with the form -// value. -//---------------------------------------------------------------------- -bool -DWARFFormValue::ResolveCompileUnitReferences(const DWARFCompileUnit* cu) -{ - switch (m_form) - { - case DW_FORM_ref1: - case DW_FORM_ref2: - case DW_FORM_ref4: - case DW_FORM_ref8: - case DW_FORM_ref_udata: - m_value.value.uval += cu->GetOffset(); - m_form = DW_FORM_ref_addr; - return true; - break; - - default: - break; - } - - return false; -} const uint8_t* DWARFFormValue::BlockData() const @@ -496,7 +537,7 @@ DWARFFormValue::IsDataForm(const dw_form_t form) } int -DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_value, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const DWARFDataExtractor* debug_str_data_ptr) +DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_value, const DWARFDataExtractor* debug_str_data_ptr) { dw_form_t a_form = a_value.Form(); dw_form_t b_form = b_value.Form(); @@ -577,8 +618,8 @@ DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_ case DW_FORM_ref8: case DW_FORM_ref_udata: { - uint64_t a = a_value.Reference(a_cu); - uint64_t b = b_value.Reference(b_cu); + uint64_t a = a_value.Reference(); + uint64_t b = b_value.Reference(); if (a < b) return -1; if (a > b) diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index d6c580c7ab1be..392df26a088e1 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -45,35 +45,34 @@ public: eValueTypeBlock }; - DWARFFormValue(dw_form_t form = 0); + DWARFFormValue(); + DWARFFormValue(const DWARFCompileUnit* cu, dw_form_t form); + const DWARFCompileUnit* GetCompileUnit () const { return m_cu; } + void SetCompileUnit (const DWARFCompileUnit* cu) { m_cu = cu; } dw_form_t Form() const { return m_form; } void SetForm(dw_form_t form) { m_form = form; } const ValueType& Value() const { return m_value; } - void Dump(lldb_private::Stream &s, const lldb_private::DWARFDataExtractor* debug_str_data, const DWARFCompileUnit* cu) const; + void Dump(lldb_private::Stream &s, const lldb_private::DWARFDataExtractor* debug_str_data) const; bool ExtractValue(const lldb_private::DWARFDataExtractor& data, - lldb::offset_t* offset_ptr, - const DWARFCompileUnit* cu); + lldb::offset_t* offset_ptr); bool IsInlinedCStr() const { return (m_value.data != NULL) && m_value.data == (const uint8_t*)m_value.value.cstr; } const uint8_t* BlockData() const; - uint64_t Reference(const DWARFCompileUnit* cu) const; + uint64_t Reference() const; uint64_t Reference (dw_offset_t offset) const; - bool ResolveCompileUnitReferences(const DWARFCompileUnit* cu); bool Boolean() const { return m_value.value.uval != 0; } uint64_t Unsigned() const { return m_value.value.uval; } void SetUnsigned(uint64_t uval) { m_value.value.uval = uval; } int64_t Signed() const { return m_value.value.sval; } void SetSigned(int64_t sval) { m_value.value.sval = sval; } const char* AsCString(const lldb_private::DWARFDataExtractor* debug_str_data_ptr) const; - bool SkipValue(const lldb_private::DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu) const; + bool SkipValue(const lldb_private::DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr) const; static bool SkipValue(const dw_form_t form, const lldb_private::DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu); -// static bool TransferValue(dw_form_t form, const lldb_private::DWARFDataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff); -// static bool TransferValue(const DWARFFormValue& formValue, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff); -// static bool PutUnsigned(dw_form_t form, dw_offset_t offset, uint64_t value, BinaryStreamBuf& out_buff, const DWARFCompileUnit* cu, bool fixup_cu_relative_refs); static bool IsBlockForm(const dw_form_t form); static bool IsDataForm(const dw_form_t form); - static const uint8_t * GetFixedFormSizesForAddressSize (uint8_t addr_size); - static int Compare (const DWARFFormValue& a, const DWARFFormValue& b, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const lldb_private::DWARFDataExtractor* debug_str_data_ptr); + static const uint8_t * GetFixedFormSizesForAddressSize (uint8_t addr_size, bool is_dwarf64); + static int Compare (const DWARFFormValue& a, const DWARFFormValue& b, const lldb_private::DWARFDataExtractor* debug_str_data_ptr); protected: + const DWARFCompileUnit* m_cu; // Compile unit for this form dw_form_t m_form; // Form for this value ValueType m_value; // Contains all data for the form }; diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h index ab0c37beeac91..f8a8cc60467dd 100644 --- a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h +++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h @@ -442,9 +442,9 @@ struct DWARFMappedHash for (size_t i=0; i<num_atoms; ++i) { - DWARFFormValue form_value (header_data.atoms[i].form); + DWARFFormValue form_value (NULL, header_data.atoms[i].form); - if (!form_value.ExtractValue(data, offset_ptr, NULL)) + if (!form_value.ExtractValue(data, offset_ptr)) return false; switch (header_data.atoms[i].type) @@ -481,7 +481,7 @@ struct DWARFMappedHash if (i > 0) strm.PutCString (", "); - DWARFFormValue form_value (header_data.atoms[i].form); + DWARFFormValue form_value (NULL, header_data.atoms[i].form); switch (header_data.atoms[i].type) { case eAtomTypeDIEOffset: // DIE offset, check form for encoding diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 842260dbc3ba5..b3a5476227f44 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1457,7 +1457,7 @@ SymbolFileDWARF::ParseTemplateDIE (DWARFCompileUnit* dwarf_cu, case DW_TAG_template_type_parameter: case DW_TAG_template_value_parameter: { - const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize(), dwarf_cu->IsDWARF64()); DWARFDebugInfoEntry::Attributes attributes; const size_t num_attributes = die->GetAttributes (this, @@ -1486,7 +1486,7 @@ SymbolFileDWARF::ParseTemplateDIE (DWARFCompileUnit* dwarf_cu, case DW_AT_type: if (attributes.ExtractFormValueAtIndex(this, i, form_value)) { - const dw_offset_t type_die_offset = form_value.Reference(dwarf_cu); + const dw_offset_t type_die_offset = form_value.Reference(); lldb_type = ResolveTypeUID(type_die_offset); if (lldb_type) clang_type = lldb_type->GetClangForwardType(); @@ -1752,7 +1752,7 @@ SymbolFileDWARF::ParseChildMembers size_t count = 0; const DWARFDebugInfoEntry *die; - const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize(), dwarf_cu->IsDWARF64()); uint32_t member_idx = 0; BitfieldInfo last_field_info; ModuleSP module = GetObjectFile()->GetModule(); @@ -1803,7 +1803,7 @@ SymbolFileDWARF::ParseChildMembers case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break; - case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break; + case DW_AT_type: encoding_uid = form_value.Reference(); break; case DW_AT_bit_offset: bit_offset = form_value.Unsigned(); break; case DW_AT_bit_size: bit_size = form_value.Unsigned(); break; case DW_AT_byte_size: byte_size = form_value.Unsigned(); break; @@ -2201,7 +2201,7 @@ SymbolFileDWARF::ParseChildMembers case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; - case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break; + case DW_AT_type: encoding_uid = form_value.Reference(); break; case DW_AT_data_member_location: if (form_value.BlockData()) { @@ -2990,7 +2990,7 @@ SymbolFileDWARF::ResolveSymbolContext(const FileSpec& file_spec, uint32_t line, if (block_die != NULL) sc.block = block.FindBlockByID (MakeUserID(block_die->GetOffset())); - else + else if (function_die != NULL) sc.block = block.FindBlockByID (MakeUserID(function_die->GetOffset())); } } @@ -3033,7 +3033,7 @@ SymbolFileDWARF::Index () m_indexed = true; Timer scoped_timer (__PRETTY_FUNCTION__, "SymbolFileDWARF::Index (%s)", - GetObjectFile()->GetFileSpec().GetFilename().AsCString()); + GetObjectFile()->GetFileSpec().GetFilename().AsCString("<Unknown>")); DWARFDebugInfo* debug_info = DebugInfo(); if (debug_info) @@ -3197,13 +3197,13 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat if (m_apple_names_ap.get()) { const char *name_cstr = name.GetCString(); - const char *base_name_start; - const char *base_name_end = NULL; + llvm::StringRef basename; + llvm::StringRef context; - if (!CPPLanguageRuntime::StripNamespacesFromVariableName(name_cstr, base_name_start, base_name_end)) - base_name_start = name_cstr; + if (!CPPLanguageRuntime::ExtractContextAndIdentifier(name_cstr, context, basename)) + basename = name_cstr; - m_apple_names_ap->FindByName (base_name_start, die_offsets); + m_apple_names_ap->FindByName (basename.data(), die_offsets); } } else @@ -3402,7 +3402,7 @@ SymbolFileDWARF::ResolveFunction (DWARFCompileUnit *cu, break; } } - assert (die->Tag() == DW_TAG_subprogram); + assert (die && die->Tag() == DW_TAG_subprogram); if (GetFunction (cu, die, sc)) { Address addr; @@ -4231,7 +4231,7 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc, if (parent_die == NULL) return 0; - const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize(), dwarf_cu->IsDWARF64()); size_t arg_idx = 0; const DWARFDebugInfoEntry *die; @@ -4266,7 +4266,7 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc, case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break; - case DW_AT_type: param_type_die_offset = form_value.Reference(dwarf_cu); break; + case DW_AT_type: param_type_die_offset = form_value.Reference(); break; case DW_AT_artificial: is_artificial = form_value.Boolean(); break; case DW_AT_location: // if (form_value.BlockData()) @@ -4409,7 +4409,7 @@ SymbolFileDWARF::ParseChildEnumerators size_t enumerators_added = 0; const DWARFDebugInfoEntry *die; - const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize(), dwarf_cu->IsDWARF64()); for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) { @@ -4488,7 +4488,7 @@ SymbolFileDWARF::ParseChildArrayInfo return; const DWARFDebugInfoEntry *die; - const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize(), dwarf_cu->IsDWARF64()); for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) { const dw_tag_t tag = die->Tag(); @@ -4929,7 +4929,7 @@ SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry { DEBUG_PRINTF ("resolved 0x%8.8" PRIx64 " from %s to 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ")\n", MakeUserID(die->GetOffset()), - m_obj_file->GetFileSpec().GetFilename().AsCString(), + m_obj_file->GetFileSpec().GetFilename().AsCString("<Unknown>"), MakeUserID(type_die->GetOffset()), MakeUserID(type_cu->GetOffset())); @@ -5060,189 +5060,6 @@ SymbolFileDWARF::DIEDeclContextsMatch (DWARFCompileUnit* cu1, const DWARFDebugIn return true; } -// This function can be used when a DIE is found that is a forward declaration -// DIE and we want to try and find a type that has the complete definition. -// "cu" and "die" must be from this SymbolFileDWARF -TypeSP -SymbolFileDWARF::FindDefinitionTypeForDIE (DWARFCompileUnit* cu, - const DWARFDebugInfoEntry *die, - const ConstString &type_name) -{ - TypeSP type_sp; - -#if defined (LLDB_CONFIGURATION_DEBUG) - // You can't and shouldn't call this function with a compile unit from - // another SymbolFileDWARF instance. - assert (DebugInfo()->ContainsCompileUnit (cu)); -#endif - - if (cu == NULL || die == NULL || !type_name) - return type_sp; - - std::string qualified_name; - - Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION|DWARF_LOG_LOOKUPS)); - if (log) - { - die->GetQualifiedName(this, cu, qualified_name); - GetObjectFile()->GetModule()->LogMessage (log, - "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x (%s), name='%s')", - die->GetOffset(), - qualified_name.c_str(), - type_name.GetCString()); - } - - DIEArray die_offsets; - - if (m_using_apple_tables) - { - if (m_apple_types_ap.get()) - { - const bool has_tag = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeTag); - const bool has_qualified_name_hash = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeQualNameHash); - if (has_tag && has_qualified_name_hash) - { - if (qualified_name.empty()) - die->GetQualifiedName(this, cu, qualified_name); - - const uint32_t qualified_name_hash = MappedHash::HashStringUsingDJB (qualified_name.c_str()); - if (log) - GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTagAndQualifiedNameHash()"); - m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash (type_name.GetCString(), die->Tag(), qualified_name_hash, die_offsets); - } - else if (has_tag) - { - if (log) - GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTag()"); - m_apple_types_ap->FindByNameAndTag (type_name.GetCString(), die->Tag(), die_offsets); - } - else - { - m_apple_types_ap->FindByName (type_name.GetCString(), die_offsets); - } - } - } - else - { - if (!m_indexed) - Index (); - - m_type_index.Find (type_name, die_offsets); - } - - const size_t num_matches = die_offsets.size(); - - const dw_tag_t die_tag = die->Tag(); - - DWARFCompileUnit* type_cu = NULL; - const DWARFDebugInfoEntry* type_die = NULL; - if (num_matches) - { - DWARFDebugInfo* debug_info = DebugInfo(); - for (size_t i=0; i<num_matches; ++i) - { - const dw_offset_t die_offset = die_offsets[i]; - type_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &type_cu); - - if (type_die) - { - bool try_resolving_type = false; - - // Don't try and resolve the DIE we are looking for with the DIE itself! - if (type_die != die) - { - const dw_tag_t type_die_tag = type_die->Tag(); - // Make sure the tags match - if (type_die_tag == die_tag) - { - // The tags match, lets try resolving this type - try_resolving_type = true; - } - else - { - // The tags don't match, but we need to watch our for a - // forward declaration for a struct and ("struct foo") - // ends up being a class ("class foo { ... };") or - // vice versa. - switch (type_die_tag) - { - case DW_TAG_class_type: - // We had a "class foo", see if we ended up with a "struct foo { ... };" - try_resolving_type = (die_tag == DW_TAG_structure_type); - break; - case DW_TAG_structure_type: - // We had a "struct foo", see if we ended up with a "class foo { ... };" - try_resolving_type = (die_tag == DW_TAG_class_type); - break; - default: - // Tags don't match, don't event try to resolve - // using this type whose name matches.... - break; - } - } - } - - if (try_resolving_type) - { - if (log) - { - std::string qualified_name; - type_die->GetQualifiedName(this, cu, qualified_name); - GetObjectFile()->GetModule()->LogMessage (log, - "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x, name='%s') trying die=0x%8.8x (%s)", - die->GetOffset(), - type_name.GetCString(), - type_die->GetOffset(), - qualified_name.c_str()); - } - - // Make sure the decl contexts match all the way up - if (DIEDeclContextsMatch(cu, die, type_cu, type_die)) - { - Type *resolved_type = ResolveType (type_cu, type_die, false); - if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) - { - DEBUG_PRINTF ("resolved 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ") from %s to 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ")\n", - MakeUserID(die->GetOffset()), - MakeUserID(cu->GetOffset()), - m_obj_file->GetFileSpec().GetFilename().AsCString(), - MakeUserID(type_die->GetOffset()), - MakeUserID(type_cu->GetOffset())); - - m_die_to_type[die] = resolved_type; - type_sp = resolved_type->shared_from_this(); - break; - } - } - } - else - { - if (log) - { - std::string qualified_name; - type_die->GetQualifiedName(this, cu, qualified_name); - GetObjectFile()->GetModule()->LogMessage (log, - "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x, name='%s') ignoring die=0x%8.8x (%s)", - die->GetOffset(), - type_name.GetCString(), - type_die->GetOffset(), - qualified_name.c_str()); - } - } - } - else - { - if (m_using_apple_tables) - { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n", - die_offset, type_name.GetCString()); - } - } - - } - } - return type_sp; -} TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &dwarf_decl_ctx) @@ -5828,7 +5645,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, break; case DW_AT_byte_size: byte_size = form_value.Unsigned(); break; case DW_AT_encoding: encoding = form_value.Unsigned(); break; - case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break; + case DW_AT_type: encoding_uid = form_value.Reference(); break; default: case DW_AT_sibling: break; @@ -6403,7 +6220,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, type_name_cstr = form_value.AsCString(&get_debug_str_data()); type_name_const_str.SetCString(type_name_cstr); break; - case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break; + case DW_AT_type: encoding_uid = form_value.Reference(); break; case DW_AT_byte_size: byte_size = form_value.Unsigned(); break; case DW_AT_accessibility: break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; case DW_AT_declaration: break; //is_forward_declaration = form_value.Boolean(); break; @@ -6521,7 +6338,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, case DW_AT_linkage_name: case DW_AT_MIPS_linkage_name: break; // mangled = form_value.AsCString(&get_debug_str_data()); break; - case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break; + case DW_AT_type: type_die_offset = form_value.Reference(); break; case DW_AT_accessibility: accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; case DW_AT_declaration: break; // is_forward_declaration = form_value.Boolean(); break; case DW_AT_inline: is_inline = form_value.Boolean(); break; @@ -6541,15 +6358,15 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, break; case DW_AT_specification: - specification_die_offset = form_value.Reference(dwarf_cu); + specification_die_offset = form_value.Reference(); break; case DW_AT_abstract_origin: - abstract_origin_die_offset = form_value.Reference(dwarf_cu); + abstract_origin_die_offset = form_value.Reference(); break; case DW_AT_object_pointer: - object_pointer_die_offset = form_value.Reference(dwarf_cu); + object_pointer_die_offset = form_value.Reference(); break; case DW_AT_allocated: @@ -6985,7 +6802,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, type_name_const_str.SetCString(type_name_cstr); break; - case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break; + case DW_AT_type: type_die_offset = form_value.Reference(); break; case DW_AT_byte_size: break; // byte_size = form_value.Unsigned(); break; case DW_AT_byte_stride: byte_stride = form_value.Unsigned(); break; case DW_AT_bit_stride: bit_stride = form_value.Unsigned(); break; @@ -7019,17 +6836,26 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, byte_stride = element_type->GetByteSize(); ClangASTType array_element_type = element_type->GetClangForwardType(); uint64_t array_element_bit_stride = byte_stride * 8 + bit_stride; - uint64_t num_elements = 0; - std::vector<uint64_t>::const_reverse_iterator pos; - std::vector<uint64_t>::const_reverse_iterator end = element_orders.rend(); - for (pos = element_orders.rbegin(); pos != end; ++pos) + if (element_orders.size() > 0) + { + uint64_t num_elements = 0; + std::vector<uint64_t>::const_reverse_iterator pos; + std::vector<uint64_t>::const_reverse_iterator end = element_orders.rend(); + for (pos = element_orders.rbegin(); pos != end; ++pos) + { + num_elements = *pos; + clang_type = ast.CreateArrayType (array_element_type, + num_elements, + is_vector); + array_element_type = clang_type; + array_element_bit_stride = num_elements ? + array_element_bit_stride * num_elements : + array_element_bit_stride; + } + } + else { - num_elements = *pos; - clang_type = ast.CreateArrayType (array_element_type, - num_elements, - is_vector); - array_element_type = clang_type; - array_element_bit_stride = num_elements ? array_element_bit_stride * num_elements : array_element_bit_stride; + clang_type = ast.CreateArrayType (array_element_type, 0, is_vector); } ConstString empty_name; type_sp.reset( new Type (MakeUserID(die->GetOffset()), @@ -7065,9 +6891,9 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, switch (attr) { case DW_AT_type: - type_die_offset = form_value.Reference(dwarf_cu); break; + type_die_offset = form_value.Reference(); break; case DW_AT_containing_type: - containing_type_die_offset = form_value.Reference(dwarf_cu); break; + containing_type_die_offset = form_value.Reference(); break; } } } @@ -7114,7 +6940,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, { symbol_context_scope = sc.comp_unit; } - else if (sc.function != NULL) + else if (sc.function != NULL && sc_parent_die) { symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset())); if (symbol_context_scope == NULL) @@ -7347,7 +7173,6 @@ SymbolFileDWARF::ParseVariableDIE const lldb::addr_t func_low_pc ) { - VariableSP var_sp (m_die_to_variable_sp[die]); if (var_sp) return var_sp; // Already been parsed! @@ -7380,6 +7205,7 @@ SymbolFileDWARF::ParseVariableDIE { dw_attr_t attr = attributes.AttributeAtIndex(i); DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) { switch (attr) @@ -7390,7 +7216,7 @@ SymbolFileDWARF::ParseVariableDIE case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break; case DW_AT_linkage_name: case DW_AT_MIPS_linkage_name: mangled = form_value.AsCString(&get_debug_str_data()); break; - case DW_AT_type: type_uid = form_value.Reference(dwarf_cu); break; + case DW_AT_type: type_uid = form_value.Reference(); break; case DW_AT_external: is_external = form_value.Boolean(); break; case DW_AT_const_value: // If we have already found a DW_AT_location attribute, ignore this attribute. @@ -7409,7 +7235,7 @@ SymbolFileDWARF::ParseVariableDIE else if (DWARFFormValue::IsDataForm(form_value.Form())) { // Retrieve the value as a data expression. - const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (attributes.CompileUnitAtIndex(i)->GetAddressByteSize(), attributes.CompileUnitAtIndex(i)->IsDWARF64()); uint32_t data_offset = attributes.DIEOffsetAtIndex(i); uint32_t data_length = fixed_form_sizes[form_value.Form()]; if (data_length == 0) @@ -7417,7 +7243,7 @@ SymbolFileDWARF::ParseVariableDIE const uint8_t *data_pointer = form_value.BlockData(); if (data_pointer) { - data_length = form_value.Unsigned(); + form_value.Unsigned(); } else if (DWARFFormValue::IsDataForm(form_value.Form())) { @@ -7433,7 +7259,7 @@ SymbolFileDWARF::ParseVariableDIE // Retrieve the value as a string expression. if (form_value.Form() == DW_FORM_strp) { - const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (attributes.CompileUnitAtIndex(i)->GetAddressByteSize(), attributes.CompileUnitAtIndex(i)->IsDWARF64()); uint32_t data_offset = attributes.DIEOffsetAtIndex(i); uint32_t data_length = fixed_form_sizes[form_value.Form()]; location.CopyOpcodeData(module, debug_info_data, data_offset, data_length); @@ -7470,7 +7296,7 @@ SymbolFileDWARF::ParseVariableDIE { location.CopyOpcodeData(module, debug_loc_data, debug_loc_offset, loc_list_length); assert (func_low_pc != LLDB_INVALID_ADDRESS); - location.SetLocationListSlide (func_low_pc - dwarf_cu->GetBaseAddress()); + location.SetLocationListSlide (func_low_pc - attributes.CompileUnitAtIndex(i)->GetBaseAddress()); } } } diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 178e5142d94bf..230e1a5d3984d 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -421,11 +421,6 @@ protected: const DWARFMappedHash::MemoryTable &memory_table, lldb_private::SymbolContextList& sc_list); - lldb::TypeSP FindDefinitionTypeForDIE ( - DWARFCompileUnit* dwarf_cu, - const DWARFDebugInfoEntry *die, - const lldb_private::ConstString &type_name); - lldb::TypeSP FindDefinitionTypeForDWARFDeclContext ( const DWARFDeclContext &die_decl_ctx); diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index b8d56d3909e98..7e484bd8dc738 100644 --- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -146,7 +146,8 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& if (log && log->GetVerbose ()) { StreamString strm; - inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL); + const char *disassemble_format = "${frame.pc}: "; + inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL, NULL, NULL, disassemble_format); log->PutCString (strm.GetData()); } diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp index 32a21d2b8bb87..dbf37d8a4de0a 100644 --- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp +++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp @@ -23,6 +23,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/Target.h" #include "lldb/Target/UnwindAssembly.h" +#include "lldb/Utility/RegisterNumber.h" using namespace lldb; using namespace lldb_private; @@ -318,7 +319,8 @@ AssemblyParse_x86::nonvolatile_reg_p (int machine_regno) #define REX_W_DSTREG(opcode) ((opcode) & 0x1) // pushq %rbp [0x55] -bool AssemblyParse_x86::push_rbp_pattern_p () +bool +AssemblyParse_x86::push_rbp_pattern_p () { uint8_t *p = m_cur_insn_bytes; if (*p == 0x55) @@ -327,7 +329,8 @@ bool AssemblyParse_x86::push_rbp_pattern_p () } // pushq $0 ; the first instruction in start() [0x6a 0x00] -bool AssemblyParse_x86::push_0_pattern_p () +bool +AssemblyParse_x86::push_0_pattern_p () { uint8_t *p = m_cur_insn_bytes; if (*p == 0x6a && *(p + 1) == 0x0) @@ -337,7 +340,8 @@ bool AssemblyParse_x86::push_0_pattern_p () // pushq $0 // pushl $0 -bool AssemblyParse_x86::push_imm_pattern_p () +bool +AssemblyParse_x86::push_imm_pattern_p () { uint8_t *p = m_cur_insn_bytes; if (*p == 0x68 || *p == 0x6a) @@ -347,7 +351,8 @@ bool AssemblyParse_x86::push_imm_pattern_p () // movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5] // movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5] -bool AssemblyParse_x86::mov_rsp_rbp_pattern_p () +bool +AssemblyParse_x86::mov_rsp_rbp_pattern_p () { uint8_t *p = m_cur_insn_bytes; if (m_wordsize == 8 && *p == 0x48) @@ -360,7 +365,8 @@ bool AssemblyParse_x86::mov_rsp_rbp_pattern_p () } // subq $0x20, %rsp -bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount) +bool +AssemblyParse_x86::sub_rsp_pattern_p (int& amount) { uint8_t *p = m_cur_insn_bytes; if (m_wordsize == 8 && *p == 0x48) @@ -381,7 +387,8 @@ bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount) } // addq $0x20, %rsp -bool AssemblyParse_x86::add_rsp_pattern_p (int& amount) +bool +AssemblyParse_x86::add_rsp_pattern_p (int& amount) { uint8_t *p = m_cur_insn_bytes; if (m_wordsize == 8 && *p == 0x48) @@ -403,7 +410,8 @@ bool AssemblyParse_x86::add_rsp_pattern_p (int& amount) // pushq %rbx // pushl %ebx -bool AssemblyParse_x86::push_reg_p (int& regno) +bool +AssemblyParse_x86::push_reg_p (int& regno) { uint8_t *p = m_cur_insn_bytes; int regno_prefix_bit = 0; @@ -423,7 +431,8 @@ bool AssemblyParse_x86::push_reg_p (int& regno) // popq %rbx // popl %ebx -bool AssemblyParse_x86::pop_reg_p (int& regno) +bool +AssemblyParse_x86::pop_reg_p (int& regno) { uint8_t *p = m_cur_insn_bytes; int regno_prefix_bit = 0; @@ -443,14 +452,16 @@ bool AssemblyParse_x86::pop_reg_p (int& regno) // popq %rbp [0x5d] // popl %ebp [0x5d] -bool AssemblyParse_x86::pop_rbp_pattern_p () +bool +AssemblyParse_x86::pop_rbp_pattern_p () { uint8_t *p = m_cur_insn_bytes; return (*p == 0x5d); } // call $0 [0xe8 0x0 0x0 0x0 0x0] -bool AssemblyParse_x86::call_next_insn_pattern_p () +bool +AssemblyParse_x86::call_next_insn_pattern_p () { uint8_t *p = m_cur_insn_bytes; return (*p == 0xe8) && (*(p+1) == 0x0) && (*(p+2) == 0x0) @@ -468,7 +479,8 @@ bool AssemblyParse_x86::call_next_insn_pattern_p () // the actual location. The positive value returned for the offset // is a convention used elsewhere for CFA offsets et al. -bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset) +bool +AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset) { uint8_t *p = m_cur_insn_bytes; int src_reg_prefix_bit = 0; @@ -602,7 +614,6 @@ bool AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan) { UnwindPlan::RowSP row(new UnwindPlan::Row); - int non_prologue_insn_count = 0; m_cur_insn = m_func_bounds.GetBaseAddress (); int current_func_text_offset = 0; int current_sp_bytes_offset_from_cfa = 0; @@ -638,20 +649,38 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan) *newrow = *row.get(); row.reset(newrow); + // Track which registers have been saved so far in the prologue. + // If we see another push of that register, it's not part of the prologue. + // The register numbers used here are the machine register #'s + // (i386_register_numbers, x86_64_register_numbers). + std::vector<bool> saved_registers(32, false); + const bool prefer_file_cache = true; + // Once the prologue has completed we'll save a copy of the unwind instructions + // If there is an epilogue in the middle of the function, after that epilogue we'll reinstate + // the unwind setup -- we assume that some code path jumps over the mid-function epilogue + + UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI + int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the epilogue started executed + std::vector<bool> prologue_completed_saved_registers; + Target *target = m_exe_ctx.GetTargetPtr(); - while (m_func_bounds.ContainsFileAddress (m_cur_insn) && non_prologue_insn_count < 10) + while (m_func_bounds.ContainsFileAddress (m_cur_insn)) { int stack_offset, insn_len; int machine_regno; // register numbers masked directly out of instructions uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB numbering scheme + bool in_epilogue = false; // we're in the middle of an epilogue sequence + bool row_updated = false; // The UnwindPlan::Row 'row' has been updated + if (!instruction_length (m_cur_insn, insn_len) || insn_len == 0 || insn_len > kMaxInstructionByteSize) { // An unrecognized/junk instruction break; } + if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, insn_len, error) == static_cast<size_t>(-1)) { @@ -661,216 +690,193 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan) if (push_rbp_pattern_p ()) { - row->SetOffset (current_func_text_offset + insn_len); current_sp_bytes_offset_from_cfa += m_wordsize; row->SetCFAOffset (current_sp_bytes_offset_from_cfa); UnwindPlan::Row::RegisterLocation regloc; regloc.SetAtCFAPlusOffset (-row->GetCFAOffset()); row->SetRegisterInfo (m_lldb_fp_regnum, regloc); - unwind_plan.AppendRow (row); - // Allocate a new Row, populate it with the existing Row contents. - newrow = new UnwindPlan::Row; - *newrow = *row.get(); - row.reset(newrow); - goto loopnext; + saved_registers[m_machine_fp_regnum] = true; + row_updated = true; } - if (mov_rsp_rbp_pattern_p ()) + else if (mov_rsp_rbp_pattern_p ()) { - row->SetOffset (current_func_text_offset + insn_len); row->SetCFARegister (m_lldb_fp_regnum); - unwind_plan.AppendRow (row); - // Allocate a new Row, populate it with the existing Row contents. - newrow = new UnwindPlan::Row; - *newrow = *row.get(); - row.reset(newrow); - goto loopnext; + row_updated = true; } // This is the start() function (or a pthread equivalent), it starts with a pushl $0x0 which puts the // saved pc value of 0 on the stack. In this case we want to pretend we didn't see a stack movement at all -- // normally the saved pc value is already on the stack by the time the function starts executing. - if (push_0_pattern_p ()) + else if (push_0_pattern_p ()) { - goto loopnext; } - if (push_reg_p (machine_regno)) + else if (push_reg_p (machine_regno)) { current_sp_bytes_offset_from_cfa += m_wordsize; - bool need_to_push_row = false; // the PUSH instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer, // we need to add a new row of instructions. if (row->GetCFARegister() == m_lldb_sp_regnum) { - need_to_push_row = true; row->SetCFAOffset (current_sp_bytes_offset_from_cfa); + row_updated = true; } // record where non-volatile (callee-saved, spilled) registers are saved on the stack - if (nonvolatile_reg_p (machine_regno) && machine_regno_to_lldb_regno (machine_regno, lldb_regno)) + if (nonvolatile_reg_p (machine_regno) + && machine_regno_to_lldb_regno (machine_regno, lldb_regno) + && saved_registers[machine_regno] == false) { - need_to_push_row = true; UnwindPlan::Row::RegisterLocation regloc; regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa); row->SetRegisterInfo (lldb_regno, regloc); + saved_registers[machine_regno] = true; + row_updated = true; } - if (need_to_push_row) - { - row->SetOffset (current_func_text_offset + insn_len); - unwind_plan.AppendRow (row); - // Allocate a new Row, populate it with the existing Row contents. - newrow = new UnwindPlan::Row; - *newrow = *row.get(); - row.reset(newrow); - } - goto loopnext; } - if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset) && nonvolatile_reg_p (machine_regno)) + else if (pop_reg_p (machine_regno)) { - if (machine_regno_to_lldb_regno (machine_regno, lldb_regno)) + current_sp_bytes_offset_from_cfa -= m_wordsize; + + if (nonvolatile_reg_p (machine_regno) + && machine_regno_to_lldb_regno (machine_regno, lldb_regno) + && saved_registers[machine_regno] == true) { - row->SetOffset (current_func_text_offset + insn_len); - UnwindPlan::Row::RegisterLocation regloc; + saved_registers[machine_regno] = false; + row->RemoveRegisterInfo (lldb_regno); - // stack_offset for 'movq %r15, -80(%rbp)' will be 80. - // In the Row, we want to express this as the offset from the CFA. If the frame base - // is rbp (like the above instruction), the CFA offset for rbp is probably 16. So we - // want to say that the value is stored at the CFA address - 96. - regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset())); + if (machine_regno == m_machine_fp_regnum) + { + row->SetCFARegister (m_lldb_sp_regnum); + } - row->SetRegisterInfo (lldb_regno, regloc); - unwind_plan.AppendRow (row); - // Allocate a new Row, populate it with the existing Row contents. - newrow = new UnwindPlan::Row; - *newrow = *row.get(); - row.reset(newrow); - goto loopnext; + in_epilogue = true; + row_updated = true; } - } - if (sub_rsp_pattern_p (stack_offset)) - { - current_sp_bytes_offset_from_cfa += stack_offset; + // the POP instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer, + // we need to add a new row of instructions. if (row->GetCFARegister() == m_lldb_sp_regnum) { - row->SetOffset (current_func_text_offset + insn_len); row->SetCFAOffset (current_sp_bytes_offset_from_cfa); - unwind_plan.AppendRow (row); - // Allocate a new Row, populate it with the existing Row contents. - newrow = new UnwindPlan::Row; - *newrow = *row.get(); - row.reset(newrow); + row_updated = true; } - goto loopnext; } - if (ret_pattern_p ()) + else if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset) + && nonvolatile_reg_p (machine_regno) + && machine_regno_to_lldb_regno (machine_regno, lldb_regno) + && saved_registers[machine_regno] == false) { - // we know where the end of the function is; set the limit on the PlanValidAddressRange - // in case our initial "high pc" value was overly large - // int original_size = m_func_bounds.GetByteSize(); - // int calculated_size = m_cur_insn.GetOffset() - m_func_bounds.GetBaseAddress().GetOffset() + insn_len + 1; - // m_func_bounds.SetByteSize (calculated_size); - // unwind_plan.SetPlanValidAddressRange (m_func_bounds); - break; - } + saved_registers[machine_regno] = true; - // FIXME recognize the i386 picbase setup instruction sequence, - // 0x1f16: call 0x1f1b ; main + 11 at /private/tmp/a.c:3 - // 0x1f1b: popl %eax - // and record the temporary stack movements if the CFA is not expressed in terms of ebp. + UnwindPlan::Row::RegisterLocation regloc; - non_prologue_insn_count++; -loopnext: - m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len); - current_func_text_offset += insn_len; - } + // stack_offset for 'movq %r15, -80(%rbp)' will be 80. + // In the Row, we want to express this as the offset from the CFA. If the frame base + // is rbp (like the above instruction), the CFA offset for rbp is probably 16. So we + // want to say that the value is stored at the CFA address - 96. + regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset())); - // Now look at the byte at the end of the AddressRange for a limited attempt at describing the - // epilogue. We're looking for the sequence + row->SetRegisterInfo (lldb_regno, regloc); - // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp) - // [ 0xc3 ] ret + row_updated = true; + } - // or + else if (sub_rsp_pattern_p (stack_offset)) + { + current_sp_bytes_offset_from_cfa += stack_offset; + if (row->GetCFARegister() == m_lldb_sp_regnum) + { + row->SetCFAOffset (current_sp_bytes_offset_from_cfa); + row_updated = true; + } + } - // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp) - // [ 0xe9 xx xx xx xx ] jmp objc_retainAutoreleaseReturnValue (this is sometimes the final insn in the function) + else if (add_rsp_pattern_p (stack_offset)) + { + current_sp_bytes_offset_from_cfa -= stack_offset; + if (row->GetCFARegister() == m_lldb_sp_regnum) + { + row->SetCFAOffset (current_sp_bytes_offset_from_cfa); + row_updated = true; + } + in_epilogue = true; + } - // or + else if (ret_pattern_p () && prologue_completed_row.get()) + { + // Reinstate the saved prologue setup for any instructions + // that come after the ret instruction - // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp) - // [ 0xc3 ] ret - // [ 0xe8 xx xx xx xx ] call __stack_chk_fail (this is sometimes the final insn in the function) + UnwindPlan::Row *newrow = new UnwindPlan::Row; + *newrow = *prologue_completed_row.get(); + row.reset (newrow); + current_sp_bytes_offset_from_cfa = prologue_completed_sp_bytes_offset_from_cfa; - // We want to add a Row describing how to unwind when we're stopped on the 'ret' instruction where the - // CFA is no longer defined in terms of rbp, but is now defined in terms of rsp like on function entry. - // (or the 'jmp' instruction in the second case) + saved_registers.clear(); + saved_registers.resize(prologue_completed_saved_registers.size(), false); + for (size_t i = 0; i < prologue_completed_saved_registers.size(); ++i) + { + saved_registers[i] = prologue_completed_saved_registers[i]; + } - uint64_t ret_insn_offset = LLDB_INVALID_ADDRESS; - Address end_of_fun(m_func_bounds.GetBaseAddress()); - end_of_fun.SetOffset (end_of_fun.GetOffset() + m_func_bounds.GetByteSize()); + in_epilogue = true; + row_updated = true; + } - if (m_func_bounds.GetByteSize() > 7) - { - uint8_t bytebuf[7]; - Address last_seven_bytes(end_of_fun); - last_seven_bytes.SetOffset (last_seven_bytes.GetOffset() - 7); - if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7, - error) != static_cast<size_t>(-1)) + // call next instruction + // call 0 + // => pop %ebx + // This is used in i386 programs to get the PIC base address for finding global data + else if (call_next_insn_pattern_p ()) { - if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov & ret - { - ret_insn_offset = m_func_bounds.GetByteSize() - 1; - } - else if (bytebuf[1] == 0x5d && bytebuf[2] == 0xe9) // mov & jmp - { - // When the pc is sitting on the 'jmp' instruction, we have the same - // unwind state as if it was sitting on a 'ret' instruction. - ret_insn_offset = m_func_bounds.GetByteSize() - 5; - } - else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov & ret & call + current_sp_bytes_offset_from_cfa += m_wordsize; + if (row->GetCFARegister() == m_lldb_sp_regnum) { - ret_insn_offset = m_func_bounds.GetByteSize() - 6; + row->SetCFAOffset (current_sp_bytes_offset_from_cfa); + row_updated = true; } } - } - else if (m_func_bounds.GetByteSize() > 2) - { - uint8_t bytebuf[2]; - Address last_two_bytes(end_of_fun); - last_two_bytes.SetOffset (last_two_bytes.GetOffset() - 2); - if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2, - error) != static_cast<size_t>(-1)) + + if (row_updated) { - if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov & ret + if (current_func_text_offset + insn_len < m_func_bounds.GetByteSize()) { - ret_insn_offset = m_func_bounds.GetByteSize() - 1; + row->SetOffset (current_func_text_offset + insn_len); + unwind_plan.AppendRow (row); + // Allocate a new Row, populate it with the existing Row contents. + newrow = new UnwindPlan::Row; + *newrow = *row.get(); + row.reset(newrow); } } - } - if (ret_insn_offset != LLDB_INVALID_ADDRESS) - { - // Create a fresh, empty Row and RegisterLocation - don't mention any other registers - UnwindPlan::RowSP epi_row(new UnwindPlan::Row); - UnwindPlan::Row::RegisterLocation epi_regloc; - - // When the ret instruction is about to be executed, here's our state - epi_row->SetOffset (ret_insn_offset); - epi_row->SetCFARegister (m_lldb_sp_regnum); - epi_row->SetCFAOffset (m_wordsize); + if (in_epilogue == false && row_updated) + { + // If we're not in an epilogue sequence, save the updated Row + UnwindPlan::Row *newrow = new UnwindPlan::Row; + *newrow = *row.get(); + prologue_completed_row.reset (newrow); - // caller's stack pointer value before the call insn is the CFA address - epi_regloc.SetIsCFAPlusOffset (0); - epi_row->SetRegisterInfo (m_lldb_sp_regnum, epi_regloc); + prologue_completed_saved_registers.clear(); + prologue_completed_saved_registers.resize(saved_registers.size(), false); + for (size_t i = 0; i < saved_registers.size(); ++i) + { + prologue_completed_saved_registers[i] = saved_registers[i]; + } + } - // saved instruction pointer can be found at CFA - wordsize - epi_regloc.SetAtCFAPlusOffset (-m_wordsize); - epi_row->SetRegisterInfo (m_lldb_ip_regnum, epi_regloc); + // We may change the sp value without adding a new Row necessarily -- keep + // track of it either way. + if (in_epilogue == false) + { + prologue_completed_sp_bytes_offset_from_cfa = current_sp_bytes_offset_from_cfa; + } - unwind_plan.AppendRow (epi_row); + m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len); + current_func_text_offset += insn_len; } unwind_plan.SetSourceName ("assembly insn profiling"); @@ -902,12 +908,20 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAOffset() != m_wordsize) return false; + UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset (-1); + Target *target = m_exe_ctx.GetTargetPtr(); m_cur_insn = func.GetBaseAddress(); uint64_t offset = 0; int row_id = 1; bool unwind_plan_updated = false; UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row)); + + // After a mid-function epilogue we will need to re-insert the original unwind rules + // so unwinds work for the remainder of the function. These aren't common with clang/gcc + // on x86 but it is possible. + bool reinstate_unwind_state = false; + while (func.ContainsFileAddress (m_cur_insn)) { int insn_len; @@ -930,10 +944,29 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin offset += insn_len; m_cur_insn.SetOffset(m_cur_insn.GetOffset() + insn_len); + if (reinstate_unwind_state) + { + // that was the last instruction of this function + if (func.ContainsFileAddress (m_cur_insn) == false) + continue; + + UnwindPlan::RowSP new_row(new UnwindPlan::Row()); + *new_row = *original_last_row; + new_row->SetOffset (offset); + unwind_plan.AppendRow (new_row); + row.reset (new UnwindPlan::Row()); + *row = *new_row; + reinstate_unwind_state = false; + unwind_plan_updated = true; + continue; + } + // If we already have one row for this instruction, we can continue. while (row_id < unwind_plan.GetRowCount() && unwind_plan.GetRowAtIndex (row_id)->GetOffset() <= offset) + { row_id++; + } UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex (row_id - 1); if (original_row->GetOffset() == offset) { @@ -1032,6 +1065,11 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin unwind_plan_updated = true; continue; } + if (ret_pattern_p ()) + { + reinstate_unwind_state = true; + continue; + } } else if (cfa_reg == m_lldb_fp_regnum) { @@ -1053,6 +1091,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); unwind_plan.InsertRow (new_row); unwind_plan_updated = true; + reinstate_unwind_state = true; continue; } } @@ -1074,6 +1113,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin unwind_plan_source += " plus augmentation from assembly parsing"; unwind_plan.SetSourceName (unwind_plan_source.c_str()); unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes); } return true; } @@ -1239,17 +1279,130 @@ UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& func, Th bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan) { - ExecutionContext exe_ctx (thread.shared_from_this()); - AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func); - return asm_parse.augment_unwind_plan_from_call_site (func, unwind_plan); + bool do_augment_unwindplan = true; + + UnwindPlan::RowSP first_row = unwind_plan.GetRowForFunctionOffset (0); + UnwindPlan::RowSP last_row = unwind_plan.GetRowForFunctionOffset (-1); + + int wordsize = 8; + ProcessSP process_sp (thread.GetProcess()); + if (process_sp) + { + wordsize = process_sp->GetTarget().GetArchitecture().GetAddressByteSize(); + } + + RegisterNumber sp_regnum (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + RegisterNumber pc_regnum (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + + // Does this UnwindPlan describe the prologue? I want to see that the CFA is set + // in terms of the stack pointer plus an offset, and I want to see that rip is + // retrieved at the CFA-wordsize. + // If there is no description of the prologue, don't try to augment this eh_frame + // unwinder code, fall back to assembly parsing instead. + + if (first_row->GetCFAType() != UnwindPlan::Row::CFAType::CFAIsRegisterPlusOffset + || RegisterNumber (thread, unwind_plan.GetRegisterKind(), first_row->GetCFARegister()) != sp_regnum + || first_row->GetCFAOffset() != wordsize) + { + return false; + } + UnwindPlan::Row::RegisterLocation first_row_pc_loc; + if (first_row->GetRegisterInfo (pc_regnum.GetAsKind (unwind_plan.GetRegisterKind()), first_row_pc_loc) == false + || first_row_pc_loc.IsAtCFAPlusOffset() == false + || first_row_pc_loc.GetOffset() != -wordsize) + { + return false; + } + + + // It looks like the prologue is described. + // Is the epilogue described? If it is, no need to do any augmentation. + + if (first_row != last_row && first_row->GetOffset() != last_row->GetOffset()) + { + // The first & last row have the same CFA register + // and the same CFA offset value + // and the CFA register is esp/rsp (the stack pointer). + + // We're checking that both of them have an unwind rule like "CFA=esp+4" or CFA+rsp+8". + + if (first_row->GetCFAType() == last_row->GetCFAType() + && first_row->GetCFARegister() == last_row->GetCFARegister() + && first_row->GetCFAOffset() == last_row->GetCFAOffset()) + { + // Get the register locations for eip/rip from the first & last rows. + // Are they both CFA plus an offset? Is it the same offset? + + UnwindPlan::Row::RegisterLocation last_row_pc_loc; + if (last_row->GetRegisterInfo (pc_regnum.GetAsKind (unwind_plan.GetRegisterKind()), last_row_pc_loc)) + { + if (last_row_pc_loc.IsAtCFAPlusOffset() + && first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset()) + { + + // One last sanity check: Is the unwind rule for getting the caller pc value + // "deref the CFA-4" or "deref the CFA-8"? + + // If so, we have an UnwindPlan that already describes the epilogue and we don't need + // to modify it at all. + + if (first_row_pc_loc.GetOffset() == -wordsize) + { + do_augment_unwindplan = false; + } + } + } + } + } + + if (do_augment_unwindplan) + { + ExecutionContext exe_ctx (thread.shared_from_this()); + AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func); + return asm_parse.augment_unwind_plan_from_call_site (func, unwind_plan); + } + + return false; } bool UnwindAssembly_x86::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan) { - ExecutionContext exe_ctx (thread.shared_from_this()); - AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func); - return asm_parse.get_fast_unwind_plan (func, unwind_plan); + // if prologue is + // 55 pushl %ebp + // 89 e5 movl %esp, %ebp + // or + // 55 pushq %rbp + // 48 89 e5 movq %rsp, %rbp + + // We should pull in the ABI architecture default unwind plan and return that + + llvm::SmallVector <uint8_t, 4> opcode_data; + + ProcessSP process_sp = thread.GetProcess(); + if (process_sp) + { + Target &target (process_sp->GetTarget()); + const bool prefer_file_cache = true; + Error error; + if (target.ReadMemory (func.GetBaseAddress (), prefer_file_cache, opcode_data.data(), + 4, error) == 4) + { + uint8_t i386_push_mov[] = {0x55, 0x89, 0xe5}; + uint8_t x86_64_push_mov[] = {0x55, 0x48, 0x89, 0xe5}; + + if (memcmp (opcode_data.data(), i386_push_mov, sizeof (i386_push_mov)) == 0 + || memcmp (opcode_data.data(), x86_64_push_mov, sizeof (x86_64_push_mov)) == 0) + { + ABISP abi_sp = process_sp->GetABI(); + if (abi_sp) + { + return abi_sp->CreateDefaultUnwindPlan (unwind_plan); + } + } + } + } + return false; } bool |