diff options
Diffstat (limited to 'source/Plugins')
152 files changed, 16094 insertions, 1642 deletions
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp index abf873ff3dd1..a9f8f3b668dc 100644 --- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp +++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp @@ -24,6 +24,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include "Utility/ARM_DWARF_Registers.h" @@ -144,7 +145,7 @@ static RegisterInfo g_register_infos[] = { "r13_svc", "sp_svc", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_svc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL}, { "r14_svc", "lr_svc", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_svc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL} }; -static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo); +static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); static bool g_register_info_names_constified = false; const lldb_private::RegisterInfo * @@ -214,7 +215,7 @@ ABIMacOSX_arm::PrepareTrivialCall (Thread &thread, llvm::ArrayRef<addr_t>::iterator ai = args.begin(), ae = args.end(); - for (size_t i = 0; i < (sizeof(reg_names) / sizeof(reg_names[0])); ++i) + for (size_t i = 0; i < llvm::array_lengthof(reg_names); ++i) { if (ai == ae) break; @@ -522,7 +523,13 @@ ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObj if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType()) { DataExtractor data; - size_t num_bytes = new_value_sp->GetData(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) { diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp new file mode 100644 index 000000000000..8f7962d095fc --- /dev/null +++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp @@ -0,0 +1,1103 @@ +//===-- ABIMacOSX_arm64.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ABIMacOSX_arm64.h" + +#include "lldb/Core/ConstString.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/Scalar.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" + +#include "Utility/ARM64_DWARF_Registers.h" + +#include <vector> + +using namespace lldb; +using namespace lldb_private; + +static const char *pluginDesc = "Mac OS X ABI for arm64 targets"; +static const char *pluginShort = "abi.macosx-arm64"; + + +static RegisterInfo g_register_infos[] = +{ + // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE + // ========== ======= == === ============= =================== =================== ====================== =========================== ======================= ====================== + { "x0", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x0, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x1", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x1, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x2", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x2, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x3", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x3, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x4", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x4, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x5", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x5, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x6", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x6, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x7", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x7, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x8", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x9", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x10", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x11", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x12", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x13", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x14", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x15", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x16", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x17", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x18", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x19", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x20", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x21", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x22", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x23", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x24", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x25", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x26", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x27", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x28", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "fp", "x29", 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x29, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "lr", "x30", 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x30, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "sp", "x31", 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x31, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "pc", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "cpsr", "psr", 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + + { "v0", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v1", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v2", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v3", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v4", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v5", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v6", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v7", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v8", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v9", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v10", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v11", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v12", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v13", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v14", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v15", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v16", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v17", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v18", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v19", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v20", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v21", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v22", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v23", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v24", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v25", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v26", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v27", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v28", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v29", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v30", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v31", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + + { "fpsr", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "fpcr", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + + { "s0", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s1", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s2", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s3", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s4", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s5", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s6", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s7", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s8", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s9", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s10", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s11", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s12", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s13", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s14", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s15", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s16", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s17", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s18", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s19", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s20", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s21", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s22", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s23", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s24", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s25", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s26", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s27", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s28", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s29", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s30", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s31", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + + { "d0", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d1", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d2", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d3", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d4", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d5", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d6", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d7", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d8", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d9", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d10", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d11", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d12", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d13", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d14", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d15", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d16", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d17", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d18", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d19", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d20", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d21", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d22", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d23", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d24", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d25", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d26", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d27", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d28", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d29", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d30", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d31", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL } +}; + +static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); +static bool g_register_info_names_constified = false; + +const lldb_private::RegisterInfo * +ABIMacOSX_arm64::GetRegisterInfoArray (uint32_t &count) +{ + // Make the C-string names and alt_names for the register infos into const + // C-string values by having the ConstString unique the names in the global + // constant C-string pool. + if (!g_register_info_names_constified) + { + g_register_info_names_constified = true; + for (uint32_t i=0; i<k_num_register_infos; ++i) + { + if (g_register_infos[i].name) + g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString(); + if (g_register_infos[i].alt_name) + g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString(); + } + } + count = k_num_register_infos; + return g_register_infos; +} + +size_t +ABIMacOSX_arm64::GetRedZoneSize () const +{ + return 128; +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ +ABISP +ABIMacOSX_arm64::CreateInstance (const ArchSpec &arch) +{ + static ABISP g_abi_sp; + if (arch.GetTriple().getArch() == llvm::Triple::aarch64) + { + if (!g_abi_sp) + g_abi_sp.reset (new ABIMacOSX_arm64); + return g_abi_sp; + } + return ABISP(); +} + +bool +ABIMacOSX_arm64::PrepareTrivialCall (Thread &thread, + lldb::addr_t sp, + lldb::addr_t func_addr, + lldb::addr_t return_addr, + llvm::ArrayRef<lldb::addr_t> args) const +{ + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + { + StreamString s; + s.Printf("ABISysV_x86_64::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%d = 0x%" PRIx64, static_cast<int>(i + 1), args[i]); + s.PutCString (")"); + log->PutCString(s.GetString().c_str()); + } + + const uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + const uint32_t ra_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + + // x0 - x7 contain first 8 simple args + if (args.size() > 8) // TODO handle more than 6 arguments + return false; + + for (size_t i = 0; i < args.size(); ++i) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); + if (log) + log->Printf("About to write arg%d (0x%" PRIx64 ") into %s", + static_cast<int>(i + 1), args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // Set "lr" to the return address + if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfoAtIndex (ra_reg_num), return_addr)) + return false; + + // Set "sp" to the requested value + if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfoAtIndex (sp_reg_num), sp)) + return false; + + // Set "pc" to the address requested + if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfoAtIndex (pc_reg_num), func_addr)) + return false; + + return true; +} + + +bool +ABIMacOSX_arm64::GetArgumentValues (Thread &thread, ValueList &values) const +{ + uint32_t num_values = values.GetSize(); + + ExecutionContext exe_ctx (thread.shared_from_this()); + + // Extract the register context so we can read arguments from registers + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + + if (!reg_ctx) + return false; + + addr_t sp = 0; + + for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) + { + // We currently only support extracting values with Clang QualTypes. + // Do we care about others? + Value *value = values.GetValueAtIndex(value_idx); + + if (!value) + return false; + + ClangASTType value_type = value->GetClangType(); + if (value_type) + { + bool is_signed = false; + size_t bit_width = 0; + if (value_type.IsIntegerType (is_signed)) + { + bit_width = value_type.GetBitSize(); + } + else if (value_type.IsPointerOrReferenceType ()) + { + bit_width = value_type.GetBitSize(); + } + else + { + // We only handle integer, pointer and reference types currently... + return false; + } + + if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8)) + { + if (value_idx < 8) + { + // Arguments 1-6 are in x0-x5... + const RegisterInfo *reg_info = NULL; + // Search by generic ID first, then fall back to by name + uint32_t arg_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx); + if (arg_reg_num != LLDB_INVALID_REGNUM) + { + reg_info = reg_ctx->GetRegisterInfoAtIndex(arg_reg_num); + } + else + { + switch (value_idx) + { + case 0: reg_info = reg_ctx->GetRegisterInfoByName("x0"); break; + case 1: reg_info = reg_ctx->GetRegisterInfoByName("x1"); break; + case 2: reg_info = reg_ctx->GetRegisterInfoByName("x2"); break; + case 3: reg_info = reg_ctx->GetRegisterInfoByName("x3"); break; + case 4: reg_info = reg_ctx->GetRegisterInfoByName("x4"); break; + case 5: reg_info = reg_ctx->GetRegisterInfoByName("x5"); break; + case 6: reg_info = reg_ctx->GetRegisterInfoByName("x6"); break; + case 7: reg_info = reg_ctx->GetRegisterInfoByName("x7"); break; + } + } + + if (reg_info) + { + RegisterValue reg_value; + + if (reg_ctx->ReadRegister(reg_info, reg_value)) + { + if (is_signed) + reg_value.SignExtend(bit_width); + if (!reg_value.GetScalarValue(value->GetScalar())) + return false; + continue; + } + } + return false; + } + else + { + if (sp == 0) + { + // Read the stack pointer if we already haven't read it + sp = reg_ctx->GetSP(0); + if (sp == 0) + return false; + } + + // Arguments 5 on up are on the stack + const uint32_t arg_byte_size = (bit_width + (8-1)) / 8; + Error error; + if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(sp, arg_byte_size, is_signed, value->GetScalar(), error)) + return false; + + sp += arg_byte_size; + // Align up to the next 8 byte boundary if needed + if (sp % 8) + { + sp >>= 3; + sp += 1; + sp <<= 3; + } + } + } + } + } + return true; +} + +Error +ABIMacOSX_arm64::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 return_value_type = new_value_sp->GetClangType(); + if (!return_value_type) + { + error.SetErrorString ("Null clang type for return value."); + return error; + } + + Thread *thread = frame_sp->GetThread().get(); + + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + if (reg_ctx) + { + DataExtractor data; + Error data_error; + const uint64_t byte_size = 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; + } + + const uint32_t type_flags = return_value_type.GetTypeInfo (NULL); + if (type_flags & ClangASTType::eTypeIsScalar || + type_flags & ClangASTType::eTypeIsPointer) + { + if (type_flags & ClangASTType::eTypeIsInteger || + type_flags & ClangASTType::eTypeIsPointer ) + { + // Extract the register context so we can read arguments from registers + lldb::offset_t offset = 0; + if (byte_size <= 16) + { + const RegisterInfo *x0_info = reg_ctx->GetRegisterInfoByName("x0", 0); + if (byte_size <= 8) + { + uint64_t raw_value = data.GetMaxU64(&offset, byte_size); + + if (!reg_ctx->WriteRegisterFromUnsigned (x0_info, raw_value)) + error.SetErrorString ("failed to write register x0"); + } + else + { + uint64_t raw_value = data.GetMaxU64(&offset, 8); + + if (reg_ctx->WriteRegisterFromUnsigned (x0_info, raw_value)) + { + const RegisterInfo *x1_info = reg_ctx->GetRegisterInfoByName("x1", 0); + raw_value = data.GetMaxU64(&offset, byte_size - offset); + + if (!reg_ctx->WriteRegisterFromUnsigned (x1_info, raw_value)) + error.SetErrorString ("failed to write register x1"); + } + } + } + else + { + error.SetErrorString("We don't support returning longer than 128 bit integer values at present."); + } + } + else if (type_flags & ClangASTType::eTypeIsFloat) + { + if (type_flags & ClangASTType::eTypeIsComplex) + { + // Don't handle complex yet. + error.SetErrorString ("returning complex float values are not supported"); + } + else + { + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) + { + if (byte_size <= 16) + { + if (byte_size <= RegisterValue::GetMaxByteSize()) + { + RegisterValue reg_value; + error = reg_value.SetValueFromData (v0_info, data, 0, true); + if (error.Success()) + { + if (!reg_ctx->WriteRegister (v0_info, reg_value)) + error.SetErrorString ("failed to write register v0"); + } + } + else + { + error.SetErrorStringWithFormat ("returning float values with a byte size of %" PRIu64 " are not supported", byte_size); + } + } + else + { + error.SetErrorString("returning float values longer than 128 bits are not supported"); + } + } + else + { + error.SetErrorString("v0 register is not available on this target"); + } + } + } + } + else if (type_flags & ClangASTType::eTypeIsVector) + { + if (byte_size > 0) + { + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) + { + if (byte_size <= v0_info->byte_size) + { + RegisterValue reg_value; + error = reg_value.SetValueFromData (v0_info, data, 0, true); + if (error.Success()) + { + if (!reg_ctx->WriteRegister (v0_info, reg_value)) + error.SetErrorString ("failed to write register v0"); + } + } + } + } + } + } + else + { + error.SetErrorString("no registers are available"); + } + + return error; +} + +bool +ABIMacOSX_arm64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t lr_reg_num = arm64_dwarf::lr; + uint32_t sp_reg_num = arm64_dwarf::sp; + uint32_t pc_reg_num = arm64_dwarf::pc; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our previous Call Frame Address is the stack pointer + row->SetCFARegister (sp_reg_num); + + // Our 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 ("arm64 at-func-entry default"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + + return true; +} + +bool +ABIMacOSX_arm64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t fp_reg_num = arm64_dwarf::fp; + uint32_t pc_reg_num = arm64_dwarf::pc; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + const int32_t ptr_size = 8; + + row->SetCFARegister (fp_reg_num); + row->SetCFAOffset (2 * ptr_size); + row->SetOffset (0); + + row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); + row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); + + unwind_plan.AppendRow (row); + unwind_plan.SetSourceName ("arm64-apple-darwin default unwind plan"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); + return true; +} + +// AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says +// registers x19 through x28 and sp are callee preserved. +// v8-v15 are non-volatile (and specifically only the lower 8 bytes of these regs), +// the rest of the fp/SIMD registers are volatile. + +// We treat x29 as callee preserved also, else the unwinder won't try to +// retrieve fp saves. + +bool +ABIMacOSX_arm64::RegisterIsVolatile (const RegisterInfo *reg_info) +{ + if (reg_info) + { + const char *name = reg_info->name; + + // Sometimes we'll be called with the "alternate" name for these registers; + // recognize them as non-volatile. + + if (name[0] == 'p' && name[1] == 'c') // pc + return false; + if (name[0] == 'f' && name[1] == 'p') // fp + return false; + if (name[0] == 's' && name[1] == 'p') // sp + return false; + if (name[0] == 'l' && name[1] == 'r') // lr + return false; + + if (name[0] == 'x') + { + // Volatile registers: x0-x18, x30 (lr) + // Return false for the non-volatile gpr regs, true for everything else + switch (name[1]) + { + case '1': + switch (name[2]) + { + case '9': + return false; // x19 is non-volatile + default: + return true; + } + break; + case '2': + switch (name[2]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + return false; // x20 - 28 are non-volatile + case '9': + return false; // x29 aka fp treat as non-volatile on Darwin + default: + return true; + } + case '3': // x30 aka lr treat as non-volatile + if (name[2] == '0') + return false; + default: + return true; + } + } + else if (name[0] == 'v' || name[0] == 's' || name[0] == 'd') + { + // Volatile registers: v0-7, v16-v31 + // Return false for non-volatile fp/SIMD regs, true for everything else + switch (name[1]) + { + case '8': + case '9': + return false; // v8-v9 are non-volatile + case '1': + switch (name[2]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + return false; // v10-v15 are non-volatile + default: + return true; + } + default: + return true; + } + } + } + return true; +} + +static bool +LoadValueFromConsecutiveGPRRegisters (ExecutionContext &exe_ctx, + RegisterContext *reg_ctx, + const ClangASTType &value_type, + bool is_return_value, // false => parameter, true => return value + uint32_t &NGRN, // NGRN (see ABI documentation) + uint32_t &NSRN, // NSRN (see ABI documentation) + DataExtractor &data) +{ + const size_t byte_size = value_type.GetByteSize(); + + if (byte_size == 0) + return false; + + std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0)); + const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); + Error error; + + ClangASTType base_type; + const uint32_t homogeneous_count = value_type.IsHomogeneousAggregate (&base_type); + if (homogeneous_count > 0 && homogeneous_count <= 8) + { + printf ("ClangASTContext::IsHomogeneousAggregate() => %u\n", homogeneous_count); + // Make sure we have enough registers + if (NSRN < 8 && (8-NSRN) >= homogeneous_count) + { + if (!base_type) + return false; + const size_t base_byte_size = base_type.GetByteSize(); + printf ("ClangASTContext::IsHomogeneousAggregate() => base_byte_size = %" PRIu64 "\n", (uint64_t) base_byte_size); + uint32_t data_offset = 0; + + for (uint32_t i=0; i<homogeneous_count; ++i) + { + char v_name[8]; + ::snprintf (v_name, sizeof(v_name), "v%u", NSRN); + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(v_name, 0); + if (reg_info == NULL) + return false; + + if (base_byte_size > reg_info->byte_size) + return false; + + RegisterValue reg_value; + + if (!reg_ctx->ReadRegister(reg_info, reg_value)) + return false; + + // Make sure we have enough room in "heap_data_ap" + if ((data_offset + base_byte_size) <= heap_data_ap->GetByteSize()) + { + const size_t bytes_copied = reg_value.GetAsMemoryData (reg_info, + heap_data_ap->GetBytes()+data_offset, + base_byte_size, + byte_order, + error); + if (bytes_copied != base_byte_size) + return false; + data_offset += bytes_copied; + ++NSRN; + } + else + return false; + } + data.SetByteOrder(byte_order); + data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); + data.SetData(DataBufferSP (heap_data_ap.release())); + return true; + } + } + + const size_t max_reg_byte_size = 16; + if (byte_size <= max_reg_byte_size) + { + size_t bytes_left = byte_size; + uint32_t data_offset = 0; + while (data_offset < byte_size) + { + if (NGRN >= 8) + return false; + + uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN); + if (reg_num == LLDB_INVALID_REGNUM) + return false; + + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num); + if (reg_info == NULL) + return false; + + RegisterValue reg_value; + + if (!reg_ctx->ReadRegister(reg_info, reg_value)) + return false; + + const size_t curr_byte_size = std::min<size_t>(8,bytes_left); + const size_t bytes_copied = reg_value.GetAsMemoryData (reg_info, heap_data_ap->GetBytes()+data_offset, curr_byte_size, byte_order, error); + if (bytes_copied == 0) + return false; + if (bytes_copied >= bytes_left) + break; + data_offset += bytes_copied; + bytes_left -= bytes_copied; + ++NGRN; + } + } + else + { + const RegisterInfo *reg_info = NULL; + if (is_return_value) + { + // We are assuming we are decoding this immediately after returning + // from a function call and that the address of the structure is in x8 + reg_info = reg_ctx->GetRegisterInfoByName("x8", 0); + } + else + { + // We are assuming we are stopped at the first instruction in a function + // and that the ABI is being respected so all parameters appear where they + // should be (functions with no external linkage can legally violate the ABI). + if (NGRN >= 8) + return false; + + uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN); + if (reg_num == LLDB_INVALID_REGNUM) + return false; + reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num); + if (reg_info == NULL) + return false; + ++NGRN; + } + + if (reg_info == NULL) + return false; + + const lldb::addr_t value_addr = reg_ctx->ReadRegisterAsUnsigned(reg_info, LLDB_INVALID_ADDRESS); + + if (value_addr == LLDB_INVALID_ADDRESS) + return false; + + if (exe_ctx.GetProcessRef().ReadMemory (value_addr, + heap_data_ap->GetBytes(), + heap_data_ap->GetByteSize(), + error) != heap_data_ap->GetByteSize()) + { + return false; + } + } + + data.SetByteOrder(byte_order); + data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); + data.SetData(DataBufferSP (heap_data_ap.release())); + return true; +} + +ValueObjectSP +ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_clang_type) const +{ + ValueObjectSP return_valobj_sp; + Value value; + + ExecutionContext exe_ctx (thread.shared_from_this()); + if (exe_ctx.GetTargetPtr() == NULL || exe_ctx.GetProcessPtr() == NULL) + return return_valobj_sp; + + //value.SetContext (Value::eContextTypeClangType, return_clang_type); + value.SetClangType(return_clang_type); + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return return_valobj_sp; + + 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) + { + value.SetValueType(Value::eValueTypeScalar); + + bool success = false; + if (type_flags & ClangASTType::eTypeIsInteger || + type_flags & ClangASTType::eTypeIsPointer ) + { + // Extract the register context so we can read arguments from registers + if (byte_size <= 8) + { + const RegisterInfo *x0_reg_info = reg_ctx->GetRegisterInfoByName("x0", 0); + if (x0_reg_info) + { + uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, 0); + const bool is_signed = (type_flags & ClangASTType::eTypeIsSigned) != 0; + switch (byte_size) + { + default: + break; + case 16: // uint128_t + // In register x0 and x1 + { + const RegisterInfo *x1_reg_info = reg_ctx->GetRegisterInfoByName("x1", 0); + + if (x1_reg_info) + { + if (byte_size <= x0_reg_info->byte_size + x1_reg_info->byte_size) + { + std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0)); + const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); + RegisterValue x0_reg_value; + RegisterValue x1_reg_value; + if (reg_ctx->ReadRegister(x0_reg_info, x0_reg_value) && + reg_ctx->ReadRegister(x1_reg_info, x1_reg_value)) + { + Error error; + if (x0_reg_value.GetAsMemoryData (x0_reg_info, heap_data_ap->GetBytes()+0, 8, byte_order, error) && + x1_reg_value.GetAsMemoryData (x1_reg_info, heap_data_ap->GetBytes()+8, 8, byte_order, error)) + { + DataExtractor data (DataBufferSP (heap_data_ap.release()), + byte_order, + exe_ctx.GetProcessRef().GetAddressByteSize()); + + return_valobj_sp = ValueObjectConstResult::Create (&thread, + return_clang_type, + ConstString(""), + data); + return return_valobj_sp; + } + } + } + } + } + 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 & ClangASTType::eTypeIsFloat) + { + if (type_flags & ClangASTType::eTypeIsComplex) + { + // Don't handle complex yet. + } + else + { + if (byte_size <= sizeof(long double)) + { + const RegisterInfo *v0_reg_info = reg_ctx->GetRegisterInfoByName("v0", 0); + RegisterValue v0_value; + if (reg_ctx->ReadRegister (v0_reg_info, v0_value)) + { + DataExtractor data; + if (v0_value.GetData(data)) + { + lldb::offset_t offset = 0; + if (byte_size == sizeof(float)) + { + value.GetScalar() = data.GetFloat(&offset); + success = true; + } + else if (byte_size == sizeof(double)) + { + value.GetScalar() = data.GetDouble(&offset); + success = true; + } + else if (byte_size == sizeof(long double)) + { + value.GetScalar() = data.GetLongDouble(&offset); + success = true; + } + } + } + } + } + } + + if (success) + return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(), + value, + ConstString("")); + + } + else if (type_flags & ClangASTType::eTypeIsVector) + { + if (byte_size > 0) + { + + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) + { + if (byte_size <= v0_info->byte_size) + { + std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0)); + const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); + RegisterValue reg_value; + if (reg_ctx->ReadRegister(v0_info, reg_value)) + { + Error error; + if (reg_value.GetAsMemoryData (v0_info, + heap_data_ap->GetBytes(), + heap_data_ap->GetByteSize(), + byte_order, + error)) + { + DataExtractor data (DataBufferSP (heap_data_ap.release()), + byte_order, + exe_ctx.GetProcessRef().GetAddressByteSize()); + return_valobj_sp = ValueObjectConstResult::Create (&thread, + return_clang_type, + ConstString(""), + data); + } + } + } + } + } + } + else if (type_flags & ClangASTType::eTypeIsStructUnion || + type_flags & ClangASTType::eTypeIsClass) + { + DataExtractor data; + + uint32_t NGRN = 0; // Search ABI docs for NGRN + uint32_t NSRN = 0; // Search ABI docs for NSRN + const bool is_return_value = true; + if (LoadValueFromConsecutiveGPRRegisters (exe_ctx, reg_ctx, return_clang_type, is_return_value, NGRN, NSRN, data)) + { + return_valobj_sp = ValueObjectConstResult::Create (&thread, + return_clang_type, + ConstString(""), + data); + } + } + return return_valobj_sp; +} + +void +ABIMacOSX_arm64::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + pluginDesc, + CreateInstance); +} + +void +ABIMacOSX_arm64::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +ConstString +ABIMacOSX_arm64::GetPluginNameStatic() +{ + static ConstString g_plugin_name("ABIMacOSX_arm64"); + return g_plugin_name; +} + +const char * +ABIMacOSX_arm64::GetShortPluginName() +{ + return pluginShort; +} + +uint32_t +ABIMacOSX_arm64::GetPluginVersion() +{ + return 1; +} + diff --git a/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h new file mode 100644 index 000000000000..0753b23ce2a2 --- /dev/null +++ b/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h @@ -0,0 +1,145 @@ +//===-- ABIMacOSX_arm64.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ABIMacOSX_arm64_h_ +#define liblldb_ABIMacOSX_arm64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Target/ABI.h" + +class ABIMacOSX_arm64 : + public lldb_private::ABI +{ +public: + ~ABIMacOSX_arm64() { } + + 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 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 () + { + // 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 + // 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 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) + { + if (pc & (4ull - 1ull)) + return false; // Not 4 byte aligned + + // Anything else if fair game.. + return true; + } + + virtual bool + FunctionCallsChangeCFA () + { + return false; + } + + 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); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + static lldb_private::ConstString + GetPluginNameStatic(); + + virtual lldb_private::ConstString + GetPluginName() + { + return GetPluginNameStatic(); + } + + virtual const char * + GetShortPluginName(); + + virtual uint32_t + GetPluginVersion(); + + virtual lldb_private::Error + SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value); + +protected: + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl (lldb_private::Thread &thread, + lldb_private::ClangASTType &ast_type) const; + +private: + ABIMacOSX_arm64() : + lldb_private::ABI() + { + // Call CreateInstance instead. + } +}; + +#endif // liblldb_ABI_h_ diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp index 8596381b3cbc..9a1ea11cbae7 100644 --- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp +++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp @@ -199,7 +199,7 @@ static RegisterInfo g_register_infos[] = { "ymm7" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm7 , LLDB_INVALID_REGNUM , gdb_ymm7 , LLDB_INVALID_REGNUM }, NULL, NULL} }; -static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo); +static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); static bool g_register_info_names_constified = false; const lldb_private::RegisterInfo * @@ -600,7 +600,13 @@ ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueOb if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType()) { DataExtractor data; - size_t num_bytes = new_value_sp->GetData(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) { diff --git a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp new file mode 100644 index 000000000000..0f01c568ed3e --- /dev/null +++ b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp @@ -0,0 +1,554 @@ +//===-- ABISysV_hexagon.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_hexagon.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/Triple.h" + +#include "llvm/IR/Type.h" + +using namespace lldb; +using namespace lldb_private; + +static RegisterInfo g_register_infos[] = +{ + // hexagon-core.xml + { "r00" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 0, 0, LLDB_INVALID_REGNUM, 0, 0 }, NULL, NULL }, + { "r01" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 1, 1, LLDB_INVALID_REGNUM, 1, 1 }, NULL, NULL }, + { "r02" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 2, 2, LLDB_INVALID_REGNUM, 2, 2 }, NULL, NULL }, + { "r03" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 3, 3, LLDB_INVALID_REGNUM, 3, 3 }, NULL, NULL }, + { "r04" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 4, 4, LLDB_INVALID_REGNUM, 4, 4 }, NULL, NULL }, + { "r05" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 5, 5, LLDB_INVALID_REGNUM, 5, 5 }, NULL, NULL }, + { "r06" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 6, 6, LLDB_INVALID_REGNUM, 6, 6 }, NULL, NULL }, + { "r07" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 7, 7, LLDB_INVALID_REGNUM, 7, 7 }, NULL, NULL }, + { "r08" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 8, 8, LLDB_INVALID_REGNUM, 8, 8 }, NULL, NULL }, + { "r09" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 9, 9, LLDB_INVALID_REGNUM, 9, 9 }, NULL, NULL }, + { "r10" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 10, 10, LLDB_INVALID_REGNUM, 10, 10 }, NULL, NULL }, + { "r11" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 11, 11, LLDB_INVALID_REGNUM, 11, 11 }, NULL, NULL }, + { "r12" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 12, 12, LLDB_INVALID_REGNUM, 12, 12 }, NULL, NULL }, + { "r13" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 13, 13, LLDB_INVALID_REGNUM, 13, 13 }, NULL, NULL }, + { "r14" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 14, 14, LLDB_INVALID_REGNUM, 14, 14 }, NULL, NULL }, + { "r15" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 15, 15, LLDB_INVALID_REGNUM, 15, 15 }, NULL, NULL }, + { "r16" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 16, 16, LLDB_INVALID_REGNUM, 16, 16 }, NULL, NULL }, + { "r17" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 17, 17, LLDB_INVALID_REGNUM, 17, 17 }, NULL, NULL }, + { "r18" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 18, 18, LLDB_INVALID_REGNUM, 18, 18 }, NULL, NULL }, + { "r19" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 19, 19, LLDB_INVALID_REGNUM, 19, 19 }, NULL, NULL }, + { "r20" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 20, 20, LLDB_INVALID_REGNUM, 20, 20 }, NULL, NULL }, + { "r21" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 21, 21, LLDB_INVALID_REGNUM, 21, 21 }, NULL, NULL }, + { "r22" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 22, 22, LLDB_INVALID_REGNUM, 22, 22 }, NULL, NULL }, + { "r23" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 23, 23, LLDB_INVALID_REGNUM, 23, 23 }, NULL, NULL }, + { "r24" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 24, 24, LLDB_INVALID_REGNUM, 24, 24 }, NULL, NULL }, + { "r25" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 25, 25, LLDB_INVALID_REGNUM, 25, 25 }, NULL, NULL }, + { "r26" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 26, 26, LLDB_INVALID_REGNUM, 26, 26 }, NULL, NULL }, + { "r27" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 27, 27, LLDB_INVALID_REGNUM, 27, 27 }, NULL, NULL }, + { "r28" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 28, 28, LLDB_INVALID_REGNUM, 28, 28 }, NULL, NULL }, + { "sp" ,"r29", 4, 0, eEncodingUint, eFormatAddressInfo, { 29, 29, LLDB_REGNUM_GENERIC_SP, 29, 29 }, NULL, NULL }, + { "fp" ,"r30", 4, 0, eEncodingUint, eFormatAddressInfo, { 30, 30, LLDB_REGNUM_GENERIC_FP, 30, 30 }, NULL, NULL }, + { "lr" ,"r31", 4, 0, eEncodingUint, eFormatAddressInfo, { 31, 31, LLDB_REGNUM_GENERIC_RA, 31, 31 }, NULL, NULL }, + { "sa0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 32, 32, LLDB_INVALID_REGNUM, 32, 32 }, NULL, NULL }, + { "lc0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 33, 33, LLDB_INVALID_REGNUM, 33, 33 }, NULL, NULL }, + { "sa1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 34, 34, LLDB_INVALID_REGNUM, 34, 34 }, NULL, NULL }, + { "lc1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 35, 35, LLDB_INVALID_REGNUM, 35, 35 }, NULL, NULL }, + // --> hexagon-v4/5/55/56-sim.xml + { "p3_0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 36, 36, LLDB_INVALID_REGNUM, 36, 36 }, NULL, NULL }, +// PADDING { + { "p00" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 37, 37, LLDB_INVALID_REGNUM, 37, 37 }, NULL, NULL }, +// } + { "m0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 38, 38, LLDB_INVALID_REGNUM, 38, 38 }, NULL, NULL }, + { "m1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 39, 39, LLDB_INVALID_REGNUM, 39, 39 }, NULL, NULL }, + { "usr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 40, 40, LLDB_INVALID_REGNUM, 40, 40 }, NULL, NULL }, + { "pc" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 41, 41, LLDB_REGNUM_GENERIC_PC, 41, 41 }, NULL, NULL }, + { "ugp" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 42, 42, LLDB_INVALID_REGNUM, 42, 42 }, NULL, NULL }, + { "gp" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 43, 43, LLDB_INVALID_REGNUM, 43, 43 }, NULL, NULL }, + { "cs0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 44, 44, LLDB_INVALID_REGNUM, 44, 44 }, NULL, NULL }, + { "cs1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 45, 45, LLDB_INVALID_REGNUM, 45, 45 }, NULL, NULL }, +// PADDING { + { "p01" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 46, 46, LLDB_INVALID_REGNUM, 46, 46 }, NULL, NULL }, + { "p02" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 47, 47, LLDB_INVALID_REGNUM, 47, 47 }, NULL, NULL }, + { "p03" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 48, 48, LLDB_INVALID_REGNUM, 48, 48 }, NULL, NULL }, + { "p04" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 49, 49, LLDB_INVALID_REGNUM, 49, 49 }, NULL, NULL }, + { "p05" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 50, 50, LLDB_INVALID_REGNUM, 50, 50 }, NULL, NULL }, + { "p06" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 51, 51, LLDB_INVALID_REGNUM, 51, 51 }, NULL, NULL }, + { "p07" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 52, 52, LLDB_INVALID_REGNUM, 52, 52 }, NULL, NULL }, + { "p08" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 53, 53, LLDB_INVALID_REGNUM, 53, 53 }, NULL, NULL }, + { "p09" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 54, 54, LLDB_INVALID_REGNUM, 54, 54 }, NULL, NULL }, + { "p10" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 55, 55, LLDB_INVALID_REGNUM, 55, 55 }, NULL, NULL }, + { "p11" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 56, 56, LLDB_INVALID_REGNUM, 56, 56 }, NULL, NULL }, + { "p12" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 57, 57, LLDB_INVALID_REGNUM, 57, 57 }, NULL, NULL }, + { "p13" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 58, 58, LLDB_INVALID_REGNUM, 58, 58 }, NULL, NULL }, + { "p14" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 59, 59, LLDB_INVALID_REGNUM, 59, 59 }, NULL, NULL }, + { "p15" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 60, 60, LLDB_INVALID_REGNUM, 60, 60 }, NULL, NULL }, + { "p16" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 61, 61, LLDB_INVALID_REGNUM, 61, 61 }, NULL, NULL }, + { "p17" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 62, 62, LLDB_INVALID_REGNUM, 62, 62 }, NULL, NULL }, + { "p18" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 63, 63, LLDB_INVALID_REGNUM, 63, 63 }, NULL, NULL }, +// } + { "sgp0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 64, 64, LLDB_INVALID_REGNUM, 64, 64 }, NULL, NULL }, +// PADDING { + { "p19" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 65, 65, LLDB_INVALID_REGNUM, 65, 65 }, NULL, NULL }, +// } + { "stid" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 66, 66, LLDB_INVALID_REGNUM, 66, 66 }, NULL, NULL }, + { "elr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 67, 67, LLDB_INVALID_REGNUM, 67, 67 }, NULL, NULL }, + { "badva0", "", 4, 0, eEncodingUint, eFormatAddressInfo, { 68, 68, LLDB_INVALID_REGNUM, 68, 68 }, NULL, NULL }, + { "badva1", "", 4, 0, eEncodingUint, eFormatAddressInfo, { 69, 69, LLDB_INVALID_REGNUM, 69, 69 }, NULL, NULL }, + { "ssr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 70, 70, LLDB_INVALID_REGNUM, 70, 70 }, NULL, NULL }, + { "ccr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 71, 71, LLDB_INVALID_REGNUM, 71, 71 }, NULL, NULL }, + { "htid" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 72, 72, LLDB_INVALID_REGNUM, 72, 72 }, NULL, NULL }, +// PADDING { + { "p20" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 73, 73, LLDB_INVALID_REGNUM, 73, 73 }, NULL, NULL }, +// } + { "imask" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 74, 74, LLDB_INVALID_REGNUM, 74, 74 }, NULL, NULL }, +// PADDING { + { "p21" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 75, 75, LLDB_INVALID_REGNUM, 75, 75 }, NULL, NULL }, + { "p22" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 76, 76, LLDB_INVALID_REGNUM, 76, 76 }, NULL, NULL }, + { "p23" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 77, 77, LLDB_INVALID_REGNUM, 77, 77 }, NULL, NULL }, + { "p24" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 78, 78, LLDB_INVALID_REGNUM, 78, 78 }, NULL, NULL }, + { "p25" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 79, 79, LLDB_INVALID_REGNUM, 79, 79 }, NULL, NULL }, + // } + { "g0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 80, 80, LLDB_INVALID_REGNUM, 80, 80 }, NULL, NULL }, + { "g1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 81, 81, LLDB_INVALID_REGNUM, 81, 81 }, NULL, NULL }, + { "g2" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 82, 82, LLDB_INVALID_REGNUM, 82, 82 }, NULL, NULL }, + { "g3" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 83, 83, LLDB_INVALID_REGNUM, 83, 83 }, NULL, NULL } +}; + +static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo); +static bool g_register_info_names_constified = false; + +const lldb_private::RegisterInfo * +ABISysV_hexagon::GetRegisterInfoArray ( uint32_t &count ) +{ + // Make the C-string names and alt_names for the register infos into const + // C-string values by having the ConstString unique the names in the global + // constant C-string pool. + if (!g_register_info_names_constified) + { + g_register_info_names_constified = true; + for (uint32_t i=0; i<k_num_register_infos; ++i) + { + if (g_register_infos[i].name) + g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString(); + if (g_register_infos[i].alt_name) + g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString(); + } + } + count = k_num_register_infos; + return g_register_infos; +} + +/* + http://en.wikipedia.org/wiki/Red_zone_%28computing%29 + + In computing, a red zone is a fixed size area in memory beyond the stack pointer that has not been + "allocated". This region of memory is not to be modified by interrupt/exception/signal handlers. + This allows the space to be used for temporary data without the extra overhead of modifying the + stack pointer. The x86-64 ABI mandates a 128 byte red zone.[1] The OpenRISC toolchain assumes a + 128 byte red zone though it is not documented. +*/ +size_t +ABISysV_hexagon::GetRedZoneSize () const +{ + return 0; +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ +ABISP +ABISysV_hexagon::CreateInstance ( const ArchSpec &arch ) +{ + static ABISP g_abi_sp; + if (arch.GetTriple().getArch() == llvm::Triple::hexagon) + { + if (!g_abi_sp) + g_abi_sp.reset (new ABISysV_hexagon); + return g_abi_sp; + } + return ABISP(); +} + +bool +ABISysV_hexagon::PrepareTrivialCall ( Thread &thread, + lldb::addr_t sp , + lldb::addr_t pc , + lldb::addr_t ra , + llvm::ArrayRef<addr_t> args ) const +{ + // we don't use the traditional trivial call specialized for jit + return false; +} + +/* + +// AD: +// . safeguard the current stack +// . how can we know that the called function will create its own frame properly? +// . we could manually make a new stack first: +// 2. push RA +// 3. push FP +// 4. FP = SP +// 5. SP = SP ( since no locals in our temp frame ) + +// AD 6/05/2014 +// . variable argument list parameters are not passed via registers, they are passed on +// the stack. This presents us with a problem, since we need to know when the valist +// starts. Currently I can find out if a function is varg, but not how many +// real parameters it takes. Thus I don't know when to start spilling the vargs. For +// the time being, to progress, I will assume that it takes on real parameter before +// the vargs list starts. + +// AD 06/05/2014 +// . how do we adhere to the stack alignment requirements + +// AD 06/05/2014 +// . handle 64bit values and their register / stack requirements + +*/ +#define HEX_ABI_DEBUG 1 +bool +ABISysV_hexagon::PrepareTrivialCall ( Thread &thread, + lldb::addr_t sp , + lldb::addr_t pc , + lldb::addr_t ra , + llvm::Type &prototype, + llvm::ArrayRef<ABI::CallArgument> args) const +{ + // default number of register passed arguments for varg functions + const int nVArgRegParams = 1; + Error error; + + // grab the process so we have access to the memory for spilling + lldb::ProcessSP proc = thread.GetProcess( ); + + // push host data onto target + for ( size_t i = 0; i < args.size( ); i++ ) + { + const ABI::CallArgument &arg = args[i]; + // skip over target values + if ( arg.type == ABI::CallArgument::TargetValue ) + continue; + // round up to 8 byte multiple + size_t argSize = ( arg.size | 0x7 ) + 1; + + // create space on the stack for this data + sp -= argSize; + + // write this argument onto the stack of the host process + proc.get( )->WriteMemory( sp, arg.data, arg.size, error ); + if ( error.Fail( ) ) + return false; + + // update the argument with the target pointer + //XXX: This is a gross hack for getting around the const + *((size_t*)(&arg.value)) = sp; + } + + +#if HEX_ABI_DEBUG + // print the original stack pointer + printf( "sp : %04lx \n", sp ); +#endif + + // make sure number of parameters matches prototype + assert( prototype.getFunctionNumParams( ) == args.size( ) ); + + // check if this is a variable argument function + bool isVArg = prototype.isFunctionVarArg(); + + // get the register context for modifying all of the registers + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + // number of arguments passed by register + int nRegArgs = nVArgRegParams; + if (! isVArg ) + { + // number of arguments is limited by [R0 : R5] space + nRegArgs = args.size( ); + if ( nRegArgs > 6 ) + nRegArgs = 6; + } + + // pass arguments that are passed via registers + for ( int i = 0; i < nRegArgs; i++ ) + { + // get the parameter as a u32 + uint32_t param = (uint32_t)args[i].value; + // write argument into register + if (!reg_ctx->WriteRegisterFromUnsigned( i, param )) + return false; + } + + // number of arguments to spill onto stack + int nSpillArgs = args.size( ) - nRegArgs; + // make space on the stack for arguments + sp -= 4 * nSpillArgs; + // align stack on an 8 byte boundary + if ( sp & 7 ) + sp -= 4; + + // arguments that are passed on the stack + for ( size_t i = nRegArgs, offs=0; i < args.size( ); i++ ) + { + // get the parameter as a u32 + uint32_t param = (uint32_t)args[i].value; + // write argument to stack + proc->WriteMemory( sp + offs, (void*)¶m, sizeof( param ), error ); + if ( !error.Success( ) ) + return false; + // + offs += 4; + } + + // update registers with current function call state + reg_ctx->WriteRegisterFromUnsigned ( 41, pc ); + reg_ctx->WriteRegisterFromUnsigned ( 31, ra ); + reg_ctx->WriteRegisterFromUnsigned ( 29, sp ); +// reg_ctx->WriteRegisterFromUnsigned ( FP ??? ); + +#if HEX_ABI_DEBUG + // quick and dirty stack dumper for debugging + for ( int i = -8; i < 8; i++ ) + { + uint32_t data = 0; + lldb::addr_t addr = sp + i * 4; + proc->ReadMemory( addr, (void*)&data, sizeof( data ), error ); + printf( "\n0x%04lx 0x%08x ", addr, data ); + if ( i == 0 ) printf( "<<-- sp" ); + } + printf( "\n" ); +#endif + + return true; +} + +bool +ABISysV_hexagon::GetArgumentValues ( Thread &thread, ValueList &values ) const +{ + return false; +} + +Error +ABISysV_hexagon::SetReturnValueObject ( lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp ) +{ + Error error; + return error; +} + +ValueObjectSP +ABISysV_hexagon::GetReturnValueObjectSimple ( Thread &thread, ClangASTType &return_clang_type ) const +{ + ValueObjectSP return_valobj_sp; + return return_valobj_sp; +} + +ValueObjectSP +ABISysV_hexagon::GetReturnValueObjectImpl ( Thread &thread, ClangASTType &return_clang_type ) const +{ + ValueObjectSP return_valobj_sp; + return return_valobj_sp; +} + +// called when we are on the first instruction of a new function +// for hexagon the return address is in RA (R31) +bool +ABISysV_hexagon::CreateFunctionEntryUnwindPlan ( UnwindPlan &unwind_plan ) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindGeneric); + unwind_plan.SetReturnAddressRegister(LLDB_REGNUM_GENERIC_RA); + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our Call Frame Address is the stack pointer value + row->SetCFARegister(LLDB_REGNUM_GENERIC_SP); + row->SetCFAOffset(4); + row->SetOffset(0); + + // The previous PC is in the LR + row->SetRegisterLocationToRegister(LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_RA, true); + unwind_plan.AppendRow(row); + + unwind_plan.SetSourceName("hexagon at-func-entry default"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + return true; +} + +bool +ABISysV_hexagon::CreateDefaultUnwindPlan ( UnwindPlan &unwind_plan ) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindGeneric); + + uint32_t fp_reg_num = LLDB_REGNUM_GENERIC_FP; + uint32_t sp_reg_num = LLDB_REGNUM_GENERIC_SP; + uint32_t pc_reg_num = LLDB_REGNUM_GENERIC_PC; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + row->SetCFARegister(LLDB_REGNUM_GENERIC_FP); + row->SetCFAOffset(8); + + row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num,-8, true); + row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num,-4, true); + row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); + + unwind_plan.AppendRow(row); + unwind_plan.SetSourceName("hexagon default unwind plan"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + return true; +} + +/* + Register Usage Saved By + + R0 - R5 parameters(a) - + R6 - R15 Scratch(b) Caller + R16 - R27 Scratch Callee + R28 Scratch(b) Caller + R29 - R31 Stack Frames Callee(c) + P3:0 Processor State Caller + + a = the caller can change parameter values + b = R14 - R15 and R28 are used by the procedure linkage table + c = R29 - R31 are saved and restored by allocframe() and deallocframe() +*/ +bool +ABISysV_hexagon::RegisterIsVolatile ( const RegisterInfo *reg_info ) +{ + return !RegisterIsCalleeSaved( reg_info ); +} + +bool +ABISysV_hexagon::RegisterIsCalleeSaved ( const RegisterInfo *reg_info ) +{ + int reg = ((reg_info->byte_offset) / 4); + + bool save = (reg >= 16) && (reg <= 27); + save |= (reg >= 29) && (reg <= 32); + + return save; +} + +void +ABISysV_hexagon::Initialize( void ) +{ + PluginManager::RegisterPlugin + ( + GetPluginNameStatic(), + "System V ABI for hexagon targets", + CreateInstance + ); +} + +void +ABISysV_hexagon::Terminate( void ) +{ + PluginManager::UnregisterPlugin( CreateInstance ); +} + +lldb_private::ConstString +ABISysV_hexagon::GetPluginNameStatic() +{ + static ConstString g_name( "sysv-hexagon" ); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +ABISysV_hexagon::GetPluginName( void ) +{ + return GetPluginNameStatic(); +} + +uint32_t +ABISysV_hexagon::GetPluginVersion( void ) +{ + return 1; +} + +// get value object specialized to work with llvm IR types +lldb::ValueObjectSP +ABISysV_hexagon::GetReturnValueObjectImpl( lldb_private::Thread &thread, llvm::Type &retType ) const +{ + Value value; + ValueObjectSP vObjSP; + + // get the current register context + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return vObjSP; + + // for now just pop R0 to find the return value + const lldb_private::RegisterInfo *r0_info = reg_ctx->GetRegisterInfoAtIndex( 0 ); + if ( r0_info == nullptr ) + return vObjSP; + + // void return type + if ( retType.isVoidTy( ) ) + { + value.GetScalar( ) = 0; + } + // integer / pointer return type + else + if ( retType.isIntegerTy( ) || retType.isPointerTy( ) ) + { + // read r0 register value + lldb_private::RegisterValue r0_value; + if ( !reg_ctx->ReadRegister( r0_info, r0_value ) ) + return vObjSP; + + // push r0 into value + uint32_t r0_u32 = r0_value.GetAsUInt32( ); + + // account for integer size + if ( retType.isIntegerTy() && retType.isSized() ) + { + uint64_t size = retType.getScalarSizeInBits( ); + uint64_t mask = ( 1ull << size ) - 1; + // mask out higher order bits then the type we expect + r0_u32 &= mask; + } + + value.GetScalar( ) = r0_u32; + } + // unsupported return type + else + return vObjSP; + + // pack the value into a ValueObjectSP + vObjSP = ValueObjectConstResult::Create + ( + thread.GetStackFrameAtIndex(0).get(), + value, + ConstString("") + ); + return vObjSP; +} diff --git a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h new file mode 100644 index 000000000000..989c4a16710a --- /dev/null +++ b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h @@ -0,0 +1,148 @@ +//===-- ABISysV_hexagon.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_hexagon_h_ +#define liblldb_ABISysV_hexagon_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/ABI.h" + +class ABISysV_hexagon : + public lldb_private::ABI +{ +public: + + ~ABISysV_hexagon( void ) + { + } + + virtual size_t + GetRedZoneSize ( void ) 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; + + // special thread plan for GDB style non-jit function calls + virtual bool + PrepareTrivialCall ( lldb_private::Thread &thread, + lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::Type &prototype, + llvm::ArrayRef<ABI::CallArgument> 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; + + // specialized to work with llvm IR types + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl ( lldb_private::Thread &thread, llvm::Type &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 ( void ) + { + return true; + } + + virtual bool + CallFrameAddressIsValid ( lldb::addr_t cfa ) + { + // Make sure the stack call frame addresses are 8 byte aligned + if (cfa & 0x07) + 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 ( void ) + { + return true; + } + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoArray ( uint32_t &count ); + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize ( void ); + + static void + Terminate ( void ); + + static lldb::ABISP + CreateInstance ( const lldb_private::ArchSpec &arch ); + + static lldb_private::ConstString + GetPluginNameStatic ( void ); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName ( void ); + + virtual uint32_t + GetPluginVersion ( void ); + +protected: + void + CreateRegisterMapIfNeeded ( void ); + + bool + RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info); + +private: + ABISysV_hexagon ( void ) : lldb_private::ABI() { } // Call CreateInstance instead. +}; + +#endif // liblldb_ABISysV_hexagon_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 a8ef6a51399c..b537415bf055 100644 --- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp +++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp @@ -28,6 +28,7 @@ #include "lldb/Target/StackFrame.h" #include "lldb/Target/Thread.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" using namespace lldb; @@ -251,7 +252,7 @@ static RegisterInfo g_register_infos[] = { "ymm15" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm15 , gcc_dwarf_ymm15 , LLDB_INVALID_REGNUM , gdb_ymm15 , LLDB_INVALID_REGNUM }, NULL, NULL} }; -static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo); +static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); static bool g_register_info_names_constified = false; const lldb_private::RegisterInfo * @@ -316,8 +317,8 @@ ABISysV_x86_64::PrepareTrivialCall (Thread &thread, (uint64_t)func_addr, (uint64_t)return_addr); - for (int i = 0; i < args.size(); ++i) - s.Printf (", arg%d = 0x%" PRIx64, i + 1, args[i]); + 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()); } @@ -331,11 +332,11 @@ ABISysV_x86_64::PrepareTrivialCall (Thread &thread, if (args.size() > 6) // TODO handle more than 6 arguments return false; - for (int i = 0; i < args.size(); ++i) + 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%d (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name); + 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; } @@ -562,7 +563,13 @@ ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueOb const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("rax", 0); DataExtractor data; - size_t num_bytes = new_value_sp->GetData(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) { @@ -589,8 +596,14 @@ ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueOb const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0); RegisterValue xmm0_value; DataExtractor data; - size_t num_bytes = new_value_sp->GetData(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(); diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp index e9b8a9f573a3..c14371d0589c 100644 --- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp @@ -10,10 +10,10 @@ #include "DisassemblerLLVMC.h" #include "llvm-c/Disassembler.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCExternalSymbolizer.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCInstrInfo.h" @@ -48,7 +48,7 @@ class InstructionLLVMC : public lldb_private::Instruction { public: InstructionLLVMC (DisassemblerLLVMC &disasm, - const lldb_private::Address &address, + const lldb_private::Address &address, AddressClass addr_class) : Instruction (address, addr_class), m_disasm_sp (disasm.shared_from_this()), @@ -57,12 +57,12 @@ public: m_using_file_addr (false) { } - + virtual ~InstructionLLVMC () { } - + virtual bool DoesBranch () { @@ -99,7 +99,7 @@ public: } return m_does_branch == eLazyBoolYes; } - + DisassemblerLLVMC::LLVMCDisassembler * GetDisasmToUse (bool &is_alternate_isa) { @@ -108,7 +108,7 @@ public: if (llvm_disasm.m_alternate_disasm_ap.get() != NULL) { const AddressClass address_class = GetAddressClass (); - + if (address_class == eAddressClassCodeAlternateISA) { is_alternate_isa = true; @@ -117,7 +117,7 @@ public: } return llvm_disasm.m_disasm_ap.get(); } - + virtual size_t Decode (const lldb_private::Disassembler &disassembler, const lldb_private::DataExtractor &data, @@ -129,7 +129,7 @@ public: DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC(); const ArchSpec &arch = llvm_disasm.GetArchitecture(); const lldb::ByteOrder byte_order = data.GetByteOrder(); - + const uint32_t min_op_byte_size = arch.GetMinimumOpcodeByteSize(); const uint32_t max_op_byte_size = arch.GetMaximumOpcodeByteSize(); if (min_op_byte_size == max_op_byte_size) @@ -170,7 +170,7 @@ public: { bool is_alternate_isa = false; DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa); - + const llvm::Triple::ArchType machine = arch.GetMachine(); if (machine == llvm::Triple::arm || machine == llvm::Triple::thumb) { @@ -204,7 +204,7 @@ public: const size_t opcode_data_len = data.BytesLeft(data_offset); const addr_t pc = m_address.GetFileAddress(); llvm::MCInst inst; - + llvm_disasm.Lock(this, NULL); const size_t inst_size = mc_disasm_ptr->GetMCInst(opcode_data, opcode_data_len, @@ -222,7 +222,7 @@ public: } return m_opcode.GetByteSize(); } - + void AppendComment (std::string &description) { @@ -234,7 +234,7 @@ public: m_comment.append(description); } } - + virtual void CalculateMnemonicOperandsAndComment (const lldb_private::ExecutionContext *exe_ctx) { @@ -244,19 +244,19 @@ public: if (m_opcode.GetData(data)) { char out_string[512]; - + DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC(); DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr; - + if (address_class == eAddressClassCodeAlternateISA) mc_disasm_ptr = llvm_disasm.m_alternate_disasm_ap.get(); else mc_disasm_ptr = llvm_disasm.m_disasm_ap.get(); - + lldb::addr_t pc = m_address.GetFileAddress(); m_using_file_addr = true; - + const bool data_from_file = GetDisassemblerLLVMC().m_data_from_file; bool use_hex_immediates = true; Disassembler::HexImmediateStyle hex_style = Disassembler::eHexStyleC; @@ -280,9 +280,9 @@ public: } } } - + llvm_disasm.Lock(this, exe_ctx); - + const uint8_t *opcode_data = data.GetDataStart(); const size_t opcode_data_len = data.GetByteSize(); llvm::MCInst inst; @@ -298,7 +298,7 @@ public: } llvm_disasm.Unlock(); - + if (inst_size == 0) { m_comment.assign ("unknown opcode"); @@ -371,11 +371,11 @@ public: } } - + static RegularExpression s_regex("[ \t]*([^ ^\t]+)[ \t]*([^ ^\t].*)?", REG_EXTENDED); - + RegularExpression::Match matches(3); - + if (s_regex.Execute(out_string, &matches)) { matches.GetMatchAtIndex(out_string, 1, m_opcode_name); @@ -383,13 +383,13 @@ public: } } } - + bool IsValid () const { return m_is_valid; } - + bool UsingFileAddress() const { @@ -400,14 +400,14 @@ public: { return m_opcode.GetByteSize(); } - + DisassemblerLLVMC & GetDisassemblerLLVMC () { return *(DisassemblerLLVMC *)m_disasm_sp.get(); } protected: - + DisassemblerSP m_disasm_sp; // for ownership LazyBool m_does_branch; bool m_is_valid; @@ -426,15 +426,15 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, uns m_is_valid = false; return; } - + m_instr_info_ap.reset(curr_target->createMCInstrInfo()); m_reg_info_ap.reset (curr_target->createMCRegInfo(triple)); - + std::string features_str; m_subtarget_info_ap.reset(curr_target->createMCSubtargetInfo(triple, "", features_str)); - + std::unique_ptr<llvm::MCRegisterInfo> reg_info(curr_target->createMCRegInfo(triple)); m_asm_info_ap.reset(curr_target->createMCAsmInfo(*reg_info, triple)); @@ -443,24 +443,25 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, uns m_is_valid = false; return; } - + m_context_ap.reset(new llvm::MCContext(m_asm_info_ap.get(), m_reg_info_ap.get(), 0)); - - m_disasm_ap.reset(curr_target->createMCDisassembler(*m_subtarget_info_ap.get())); + + m_disasm_ap.reset(curr_target->createMCDisassembler(*m_subtarget_info_ap.get(), *m_context_ap.get())); if (m_disasm_ap.get() && m_context_ap.get()) { - llvm::OwningPtr<llvm::MCRelocationInfo> RelInfo(curr_target->createMCRelocationInfo(triple, *m_context_ap.get())); + std::unique_ptr<llvm::MCRelocationInfo> RelInfo(curr_target->createMCRelocationInfo(triple, *m_context_ap.get())); if (!RelInfo) { m_is_valid = false; return; } - m_disasm_ap->setupForSymbolicDisassembly(NULL, - DisassemblerLLVMC::SymbolLookupCallback, - (void *) &owner, - m_context_ap.get(), - RelInfo); - + std::unique_ptr<llvm::MCSymbolizer> symbolizer_up(curr_target->createMCSymbolizer(triple, NULL, + DisassemblerLLVMC::SymbolLookupCallback, + (void *) &owner, + m_context_ap.get(), RelInfo.release())); + m_disasm_ap->setSymbolizer(std::move(symbolizer_up)); + + unsigned asm_printer_variant; if (flavor == ~0U) asm_printer_variant = m_asm_info_ap->getAssemblerDialect(); @@ -468,7 +469,7 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, uns { asm_printer_variant = flavor; } - + m_instr_printer_ap.reset(curr_target->createMCInstPrinter(asm_printer_variant, *m_asm_info_ap.get(), *m_instr_info_ap.get(), @@ -497,7 +498,7 @@ namespace { 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; } @@ -545,7 +546,7 @@ DisassemblerLLVMC::LLVMCDisassembler::PrintMCInst (llvm::MCInst &mc_inst, const size_t output_size = std::min(dst_len - 1, inst_string.size()); std::memcpy(dst, inst_string.data(), output_size); dst[output_size] = '\0'; - + return output_size; } @@ -572,7 +573,7 @@ DisassemblerLLVMC::FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, c llvm::Triple triple = arch.GetTriple(); if (flavor == NULL || strcmp (flavor, "default") == 0) return true; - + if (triple.getArch() == llvm::Triple::x86 || triple.getArch() == llvm::Triple::x86_64) { if (strcmp (flavor, "intel") == 0 || strcmp (flavor, "att") == 0) @@ -583,7 +584,7 @@ DisassemblerLLVMC::FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, c else return false; } - + Disassembler * DisassemblerLLVMC::CreateInstance (const ArchSpec &arch, const char *flavor) @@ -591,7 +592,7 @@ DisassemblerLLVMC::CreateInstance (const ArchSpec &arch, const char *flavor) if (arch.GetTriple().getArch() != llvm::Triple::UnknownArch) { std::unique_ptr<DisassemblerLLVMC> disasm_ap (new DisassemblerLLVMC(arch, flavor)); - + if (disasm_ap.get() && disasm_ap->IsValid()) return disasm_ap.release(); } @@ -608,10 +609,10 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s { m_flavor.assign("default"); } - + const char *triple = arch.GetTriple().getTriple().c_str(); unsigned flavor = ~0U; - + // So far the only supported flavor is "intel" on x86. The base class will set this // correctly coming in. if (arch.GetTriple().getArch() == llvm::Triple::x86 @@ -626,7 +627,7 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s flavor = 0; } } - + ArchSpec thumb_arch(arch); if (arch.GetTriple().getArch() == llvm::Triple::arm) { @@ -643,15 +644,15 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s } thumb_arch.GetTriple().setArchName(llvm::StringRef(thumb_arch_name.c_str())); } - - // Cortex-M3 devices (e.g. armv7m) can only execute thumb (T2) instructions, + + // Cortex-M3 devices (e.g. armv7m) can only execute thumb (T2) instructions, // so hardcode the primary disassembler to thumb mode. Same for Cortex-M4 (armv7em). // // Handle the Cortex-M0 (armv6m) the same; the ISA is a subset of the T and T32 - // instructions defined in ARMv7-A. + // instructions defined in ARMv7-A. if (arch.GetTriple().getArch() == llvm::Triple::arm - && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m + && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m || arch.GetCore() == ArchSpec::Core::eCore_arm_armv7em || arch.GetCore() == ArchSpec::Core::eCore_arm_armv6m)) { @@ -693,33 +694,33 @@ DisassemblerLLVMC::DecodeInstructions (const Address &base_addr, { if (!append) m_instruction_list.Clear(); - + if (!IsValid()) return 0; - + m_data_from_file = data_from_file; uint32_t data_cursor = data_offset; const size_t data_byte_size = data.GetByteSize(); uint32_t instructions_parsed = 0; Address inst_addr(base_addr); - + while (data_cursor < data_byte_size && instructions_parsed < num_instructions) { - + AddressClass address_class = eAddressClassCode; - + if (m_alternate_disasm_ap.get() != NULL) address_class = inst_addr.GetAddressClass (); - + InstructionSP inst_sp(new InstructionLLVMC(*this, - inst_addr, + inst_addr, address_class)); - + if (!inst_sp) break; - + uint32_t inst_size = inst_sp->Decode(*this, data, data_cursor); - + if (inst_size == 0) break; @@ -728,7 +729,7 @@ DisassemblerLLVMC::DecodeInstructions (const Address &base_addr, inst_addr.Slide(inst_size); instructions_parsed++; } - + return data_cursor - data_offset; } @@ -736,9 +737,9 @@ void DisassemblerLLVMC::Initialize() { PluginManager::RegisterPlugin (GetPluginNameStatic(), - "Disassembler that uses LLVM MC to disassemble i386, x86_64 and ARM.", + "Disassembler that uses LLVM MC to disassemble i386, x86_64, ARM, and ARM64.", CreateInstance); - + llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmParsers(); @@ -810,7 +811,7 @@ const char *DisassemblerLLVMC::SymbolLookup (uint64_t value, if (*type_ptr) { if (m_exe_ctx && m_inst) - { + { //std::string remove_this_prior_to_checkin; Target *target = m_exe_ctx ? m_exe_ctx->GetTargetPtr() : NULL; Address value_so_addr; @@ -824,16 +825,16 @@ const char *DisassemblerLLVMC::SymbolLookup (uint64_t value, { target->GetSectionLoadList().ResolveLoadAddress(value, value_so_addr); } - + if (value_so_addr.IsValid() && value_so_addr.GetSection()) { StreamString ss; - + value_so_addr.Dump (&ss, target, Address::DumpStyleResolvedDescriptionNoModule, Address::DumpStyleSectionNameOffset); - + if (!ss.GetString().empty()) { m_inst->AppendComment(ss.GetString()); @@ -861,4 +862,3 @@ DisassemblerLLVMC::GetPluginVersion() { return 1; } - diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h index c567791866d5..6ab9e9ae2625 100644 --- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h +++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h @@ -42,9 +42,9 @@ class DisassemblerLLVMC : public lldb_private::Disassembler { public: LLVMCDisassembler (const char *triple, unsigned flavor, DisassemblerLLVMC &owner); - + ~LLVMCDisassembler(); - + uint64_t GetMCInst (const uint8_t *opcode_data, size_t opcode_data_len, lldb::addr_t pc, llvm::MCInst &mc_inst); uint64_t PrintMCInst (llvm::MCInst &mc_inst, char *output_buffer, size_t out_buffer_len); void SetStyle (bool use_hex_immed, HexImmediateStyle hex_style); @@ -53,7 +53,7 @@ class DisassemblerLLVMC : public lldb_private::Disassembler { return m_is_valid; } - + private: bool m_is_valid; std::unique_ptr<llvm::MCContext> m_context_ap; @@ -71,21 +71,21 @@ public: //------------------------------------------------------------------ static void Initialize(); - + static void Terminate(); - + static lldb_private::ConstString GetPluginNameStatic(); - + static lldb_private::Disassembler * CreateInstance(const lldb_private::ArchSpec &arch, const char *flavor); - + DisassemblerLLVMC(const lldb_private::ArchSpec &arch, const char *flavor /* = NULL */); - + virtual ~DisassemblerLLVMC(); - + virtual size_t DecodeInstructions (const lldb_private::Address &base_addr, const lldb_private::DataExtractor& data, @@ -93,72 +93,72 @@ public: size_t num_instructions, bool append, bool data_from_file); - + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ virtual lldb_private::ConstString GetPluginName(); - + virtual uint32_t GetPluginVersion(); - + protected: friend class InstructionLLVMC; - + virtual bool FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, const char *flavor); - + bool IsValid() { return (m_disasm_ap.get() != NULL && m_disasm_ap->IsValid()); } - + int OpInfo(uint64_t PC, uint64_t Offset, uint64_t Size, int TagType, void *TagBug); - + const char *SymbolLookup (uint64_t ReferenceValue, uint64_t *ReferenceType, uint64_t ReferencePC, const char **ReferenceName); - + static int OpInfoCallback (void *DisInfo, uint64_t PC, uint64_t Offset, uint64_t Size, int TagType, void *TagBug); - + static const char *SymbolLookupCallback(void *DisInfo, uint64_t ReferenceValue, uint64_t *ReferenceType, uint64_t ReferencePC, const char **ReferenceName); - - void Lock(InstructionLLVMC *inst, + + void Lock(InstructionLLVMC *inst, const lldb_private::ExecutionContext *exe_ctx) { m_mutex.Lock(); m_inst = inst; m_exe_ctx = exe_ctx; } - + void Unlock() { m_inst = NULL; m_exe_ctx = NULL; m_mutex.Unlock(); } - + const lldb_private::ExecutionContext *m_exe_ctx; InstructionLLVMC *m_inst; lldb_private::Mutex m_mutex; bool m_data_from_file; - + std::unique_ptr<LLVMCDisassembler> m_disasm_ap; std::unique_ptr<LLVMCDisassembler> m_alternate_disasm_ap; }; diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp new file mode 100644 index 000000000000..c79d96abafa2 --- /dev/null +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp @@ -0,0 +1,727 @@ +//===-- DynamicLoaderHexagon.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/Section.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlanRunToAddress.h" +#include "lldb/Breakpoint/BreakpointLocation.h" + +#include "DynamicLoaderHexagonDYLD.h" + +using namespace lldb; +using namespace lldb_private; + +// Aidan 21/05/2014 +// +// Notes about hexagon dynamic loading: +// +// When we connect to a target we find the dyld breakpoint address. We put a +// breakpoint there with a callback 'RendezvousBreakpointHit()'. +// +// It is possible to find the dyld structure address from the ELF symbol table, +// but in the case of the simulator it has not been initialized before the +// target calls dlinit(). +// +// We can only safely parse the dyld structure after we hit the dyld breakpoint +// since at that time we know dlinit() must have been called. +// + +// Find the load address of a symbol +static lldb::addr_t findSymbolAddress( Process *proc, ConstString findName ) +{ + assert( proc != nullptr ); + + ModuleSP module = proc->GetTarget().GetExecutableModule(); + assert( module.get() != nullptr ); + + ObjectFile *exe = module->GetObjectFile(); + assert( exe != nullptr ); + + lldb_private::Symtab *symtab = exe->GetSymtab( ); + assert( symtab != nullptr ); + + for ( size_t i = 0; i < symtab->GetNumSymbols( ); i++ ) + { + const Symbol* sym = symtab->SymbolAtIndex( i ); + assert( sym != nullptr ); + const ConstString &symName = sym->GetName( ); + + if ( ConstString::Compare( findName, symName ) == 0 ) + { + Address addr = sym->GetAddress( ); + return addr.GetLoadAddress( & proc->GetTarget() ); + } + } + return LLDB_INVALID_ADDRESS; +} + +void +DynamicLoaderHexagonDYLD::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +DynamicLoaderHexagonDYLD::Terminate() +{ +} + +lldb_private::ConstString +DynamicLoaderHexagonDYLD::GetPluginName() +{ + return GetPluginNameStatic(); +} + +lldb_private::ConstString +DynamicLoaderHexagonDYLD::GetPluginNameStatic() +{ + static ConstString g_name("hexagon-dyld"); + return g_name; +} + +const char * +DynamicLoaderHexagonDYLD::GetPluginDescriptionStatic() +{ + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in Hexagon processes."; +} + +void +DynamicLoaderHexagonDYLD::GetPluginCommandHelp(const char *command, Stream *strm) +{ +} + +uint32_t +DynamicLoaderHexagonDYLD::GetPluginVersion() +{ + return 1; +} + +DynamicLoader * +DynamicLoaderHexagonDYLD::CreateInstance(Process *process, bool force) +{ + bool create = force; + if (!create) + { + const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); + if (triple_ref.getArch() == llvm::Triple::hexagon) + create = true; + } + + if (create) + return new DynamicLoaderHexagonDYLD(process); + return NULL; +} + +DynamicLoaderHexagonDYLD::DynamicLoaderHexagonDYLD(Process *process) + : DynamicLoader(process) + , m_rendezvous (process) + , m_load_offset(LLDB_INVALID_ADDRESS) + , m_entry_point(LLDB_INVALID_ADDRESS) + , m_dyld_bid (LLDB_INVALID_BREAK_ID) +{ +} + +DynamicLoaderHexagonDYLD::~DynamicLoaderHexagonDYLD() +{ + if (m_dyld_bid != LLDB_INVALID_BREAK_ID) + { + m_process->GetTarget().RemoveBreakpointByID (m_dyld_bid); + m_dyld_bid = LLDB_INVALID_BREAK_ID; + } +} + +void +DynamicLoaderHexagonDYLD::DidAttach() +{ + ModuleSP executable; + addr_t load_offset; + + executable = GetTargetExecutable(); + + // Find the difference between the desired load address in the elf file + // and the real load address in memory + load_offset = ComputeLoadOffset(); + + // Check that there is a valid executable + if ( executable.get( ) == nullptr ) + return; + + // Disable JIT for hexagon targets because its not supported + m_process->SetCanJIT(false); + + // Add the current executable to the module list + ModuleList module_list; + module_list.Append(executable); + + // Map the loaded sections of this executable + if ( load_offset != LLDB_INVALID_ADDRESS ) + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset); + + // AD: confirm this? + // Load into LLDB all of the currently loaded executables in the stub + LoadAllCurrentModules(); + + // AD: confirm this? + // Callback for the target to give it the loaded module list + m_process->GetTarget().ModulesDidLoad(module_list); + + // Try to set a breakpoint at the rendezvous breakpoint. + // DidLaunch uses ProbeEntry() instead. That sets a breakpoint, + // at the dyld breakpoint address, with a callback so that when hit, + // the dyld structure can be parsed. + if (! SetRendezvousBreakpoint() ) + { + // fail + } +} + +void +DynamicLoaderHexagonDYLD::DidLaunch() +{ +} + +/// Checks to see if the target module has changed, updates the target +/// accordingly and returns the target executable module. +ModuleSP +DynamicLoaderHexagonDYLD::GetTargetExecutable() +{ + Target &target = m_process->GetTarget(); + ModuleSP executable = target.GetExecutableModule(); + + // There is no executable + if (! executable.get()) + return executable; + + // The target executable file does not exits + if (! executable->GetFileSpec().Exists()) + return executable; + + // Prep module for loading + ModuleSpec module_spec(executable->GetFileSpec(), executable->GetArchitecture()); + ModuleSP module_sp (new Module (module_spec)); + + // Check if the executable has changed and set it to the target executable if they differ. + if (module_sp.get() && module_sp->GetUUID().IsValid() && executable->GetUUID().IsValid()) + { + // if the executable has changed ?? + if (module_sp->GetUUID() != executable->GetUUID()) + executable.reset(); + } + else if (executable->FileHasChanged()) + executable.reset(); + + if ( executable.get( ) ) + return executable; + + // TODO: What case is this code used? + executable = target.GetSharedModule(module_spec); + if (executable.get() != target.GetExecutableModulePointer()) + { + // Don't load dependent images since we are in dyld where we will know + // and find out about all images that are loaded + const bool get_dependent_images = false; + target.SetExecutableModule(executable, get_dependent_images); + } + + return executable; +} + +Error +DynamicLoaderHexagonDYLD::ExecutePluginCommand(Args &command, Stream *strm) +{ + return Error(); +} + +Log * +DynamicLoaderHexagonDYLD::EnablePluginLogging(Stream *strm, Args &command) +{ + return NULL; +} + +//AD: Needs to be updated? +Error +DynamicLoaderHexagonDYLD::CanLoadImage() +{ + return Error(); +} + +void +DynamicLoaderHexagonDYLD::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, addr_t base_addr) +{ + Target &target = m_process->GetTarget(); + const SectionList *sections = GetSectionListFromModule(module); + + assert(sections && "SectionList missing from loaded module."); + + m_loaded_modules[module] = link_map_addr; + + const size_t num_sections = sections->GetSize(); + + for (unsigned i = 0; i < num_sections; ++i) + { + SectionSP section_sp (sections->GetSectionAtIndex(i)); + lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr; + + // AD: 02/05/14 + // since our memory map starts from address 0, we must not ignore + // sections that load to address 0. This violates the reference + // ELF spec, however is used for Hexagon. + + // If the file address of the section is zero then this is not an + // allocatable/loadable section (property of ELF sh_addr). Skip it. +// if (new_load_addr == base_addr) +// continue; + + target.SetSectionLoadAddress(section_sp, new_load_addr); + } +} + +/// Removes the loaded sections from the target in @p module. +/// +/// @param module The module to traverse. +void +DynamicLoaderHexagonDYLD::UnloadSections(const ModuleSP module) +{ + Target &target = m_process->GetTarget(); + const SectionList *sections = GetSectionListFromModule(module); + + assert(sections && "SectionList missing from unloaded module."); + + m_loaded_modules.erase(module); + + const size_t num_sections = sections->GetSize(); + for (size_t i = 0; i < num_sections; ++i) + { + SectionSP section_sp (sections->GetSectionAtIndex(i)); + target.SetSectionUnloaded(section_sp); + } +} + +// Place a breakpoint on <_rtld_debug_state> +bool +DynamicLoaderHexagonDYLD::SetRendezvousBreakpoint() +{ + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + // This is the original code, which want to look in the rendezvous structure + // to find the breakpoint address. Its backwards for us, since we can easily + // find the breakpoint address, since it is exported in our executable. + // We however know that we cant read the Rendezvous structure until we have hit + // the breakpoint once. + const ConstString dyldBpName( "_rtld_debug_state" ); + addr_t break_addr = findSymbolAddress( m_process, dyldBpName ); + + Target &target = m_process->GetTarget(); + + // Do not try to set the breakpoint if we don't know where to put it + if ( break_addr == LLDB_INVALID_ADDRESS ) + { + if ( log ) + log->Printf( "Unable to locate _rtld_debug_state breakpoint address" ); + + return false; + } + + // Save the address of the rendezvous structure + m_rendezvous.SetBreakAddress( break_addr ); + + // If we haven't set the breakpoint before then set it + if (m_dyld_bid == LLDB_INVALID_BREAK_ID) + { + 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(); + + // Make sure our breakpoint is at the right address. + assert + ( + target.GetBreakpointByID(m_dyld_bid)-> + FindLocationByAddress(break_addr)-> + GetBreakpoint().GetID() + == m_dyld_bid + ); + + if ( log && dyld_break == nullptr ) + log->Printf( "Failed to create _rtld_debug_state breakpoint" ); + + // check we have successfully set bp + return (dyld_break != nullptr); + } + else + // rendezvous already set + return true; +} + +// We have just hit our breakpoint at <_rtld_debug_state> +bool +DynamicLoaderHexagonDYLD::RendezvousBreakpointHit(void *baton, + StoppointCallbackContext *context, + user_id_t break_id, + user_id_t break_loc_id) +{ + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + if ( log ) + log->Printf( "Rendezvous breakpoint hit!" ); + + DynamicLoaderHexagonDYLD* dyld_instance = nullptr; + dyld_instance = static_cast<DynamicLoaderHexagonDYLD*>(baton); + + // if the dyld_instance is still not valid then + // try to locate it on the symbol table + if ( !dyld_instance->m_rendezvous.IsValid( ) ) + { + Process *proc = dyld_instance->m_process; + + const ConstString dyldStructName( "_rtld_debug" ); + addr_t structAddr = findSymbolAddress( proc, dyldStructName ); + + if ( structAddr != LLDB_INVALID_ADDRESS ) + { + dyld_instance->m_rendezvous.SetRendezvousAddress( structAddr ); + + if ( log ) + log->Printf( "Found _rtld_debug structure @ 0x%08lx", structAddr ); + } + else + { + if ( log ) + log->Printf( "Unable to resolve the _rtld_debug structure" ); + } + } + + dyld_instance->RefreshModules(); + + // Return true to stop the target, false to just let the target run. + return dyld_instance->GetStopWhenImagesChange(); +} + +/// Helper method for RendezvousBreakpointHit. Updates LLDB's current set +/// of loaded modules. +void +DynamicLoaderHexagonDYLD::RefreshModules() +{ + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + if (!m_rendezvous.Resolve()) + return; + + HexagonDYLDRendezvous::iterator I; + HexagonDYLDRendezvous::iterator E; + + ModuleList &loaded_modules = m_process->GetTarget().GetImages(); + + if (m_rendezvous.ModulesDidLoad()) + { + ModuleList new_modules; + + E = m_rendezvous.loaded_end(); + for (I = m_rendezvous.loaded_begin(); I != E; ++I) + { + FileSpec file(I->path.c_str(), true); + ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr); + if (module_sp.get()) + { + loaded_modules.AppendIfNeeded( module_sp ); + new_modules.Append(module_sp); + } + + if (log) + { + log->Printf( "Target is loading '%s'", I->path.c_str() ); + if (! module_sp.get() ) + log->Printf( "LLDB failed to load '%s'", I->path.c_str() ); + else + log->Printf( "LLDB successfully loaded '%s'", I->path.c_str() ); + } + + } + m_process->GetTarget().ModulesDidLoad(new_modules); + } + + if (m_rendezvous.ModulesDidUnload()) + { + ModuleList old_modules; + + E = m_rendezvous.unloaded_end(); + for (I = m_rendezvous.unloaded_begin(); I != E; ++I) + { + FileSpec file(I->path.c_str(), true); + ModuleSpec module_spec(file); + ModuleSP module_sp = loaded_modules.FindFirstModule (module_spec); + + if (module_sp.get()) + { + old_modules.Append(module_sp); + UnloadSections(module_sp); + } + + if (log) + log->Printf( "Target is unloading '%s'", I->path.c_str() ); + + } + loaded_modules.Remove(old_modules); + m_process->GetTarget().ModulesDidUnload(old_modules, false); + } +} + +//AD: This is very different to the Static Loader code. +// It may be wise to look over this and its relation to stack +// unwinding. +ThreadPlanSP +DynamicLoaderHexagonDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop) +{ + ThreadPlanSP thread_plan_sp; + + StackFrame *frame = thread.GetStackFrameAtIndex(0).get(); + const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol); + Symbol *sym = context.symbol; + + if (sym == NULL || !sym->IsTrampoline()) + return thread_plan_sp; + + const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled); + if (!sym_name) + return thread_plan_sp; + + SymbolContextList target_symbols; + Target &target = thread.GetProcess()->GetTarget(); + const ModuleList &images = target.GetImages(); + + images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols); + size_t num_targets = target_symbols.GetSize(); + if (!num_targets) + return thread_plan_sp; + + typedef std::vector<lldb::addr_t> AddressVector; + AddressVector addrs; + for (size_t i = 0; i < num_targets; ++i) + { + SymbolContext context; + AddressRange range; + if (target_symbols.GetContextAtIndex(i, context)) + { + context.GetAddressRange(eSymbolContextEverything, 0, false, range); + lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target); + if (addr != LLDB_INVALID_ADDRESS) + addrs.push_back(addr); + } + } + + if (addrs.size() > 0) + { + AddressVector::iterator start = addrs.begin(); + AddressVector::iterator end = addrs.end(); + + std::sort(start, end); + addrs.erase(std::unique(start, end), end); + thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop)); + } + + return thread_plan_sp; +} + +/// Helper for the entry breakpoint callback. Resolves the load addresses +/// of all dependent modules. +void +DynamicLoaderHexagonDYLD::LoadAllCurrentModules() +{ + HexagonDYLDRendezvous::iterator I; + HexagonDYLDRendezvous::iterator E; + ModuleList module_list; + + if (!m_rendezvous.Resolve()) + { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderHexagonDYLD::%s unable to resolve rendezvous address", __FUNCTION__); + return; + } + + // The rendezvous class doesn't enumerate the main module, so track + // that ourselves here. + ModuleSP executable = GetTargetExecutable(); + m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); + + + for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) + { + const char *module_path = I->path.c_str(); + FileSpec file(module_path, false); + ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr); + if (module_sp.get()) + { + module_list.Append(module_sp); + } + else + { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderHexagonDYLD::%s failed loading module %s at 0x%" PRIx64, + __FUNCTION__, module_path, I->base_addr); + } + } + + m_process->GetTarget().ModulesDidLoad(module_list); +} + +/// Helper for the entry breakpoint callback. Resolves the load addresses +/// of all dependent modules. +ModuleSP +DynamicLoaderHexagonDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, addr_t base_addr) +{ + Target &target = m_process->GetTarget(); + ModuleList &modules = target.GetImages(); + ModuleSP module_sp; + + ModuleSpec module_spec (file, target.GetArchitecture()); + + // check if module is currently loaded + if ((module_sp = modules.FindFirstModule (module_spec))) + { + UpdateLoadedSections(module_sp, link_map_addr, base_addr); + } + // try to load this module from disk + else if ((module_sp = target.GetSharedModule(module_spec))) + { + UpdateLoadedSections(module_sp, link_map_addr, base_addr); + } + + return module_sp; +} + +/// Computes a value for m_load_offset returning the computed address on +/// success and LLDB_INVALID_ADDRESS on failure. +addr_t +DynamicLoaderHexagonDYLD::ComputeLoadOffset() +{ + // Here we could send a GDB packet to know the load offset + // + // send: $qOffsets#4b + // get: Text=0;Data=0;Bss=0 + // + // Currently qOffsets is not supported by pluginProcessGDBRemote + // + return 0; +} + +// Here we must try to read the entry point directly from +// the elf header. This is possible if the process is not +// relocatable or dynamically linked. +// +// an alternative is to look at the PC if we can be sure +// that we have connected when the process is at the entry point. +// I dont think that is reliable for us. +addr_t +DynamicLoaderHexagonDYLD::GetEntryPoint() +{ + if (m_entry_point != LLDB_INVALID_ADDRESS) + return m_entry_point; + // check we have a valid process + if ( m_process == nullptr ) + return LLDB_INVALID_ADDRESS; + // Get the current executable module + Module & module = *( m_process->GetTarget( ).GetExecutableModule( ).get( ) ); + // Get the object file (elf file) for this module + lldb_private::ObjectFile &object = *( module.GetObjectFile( ) ); + // Check if the file is executable (ie, not shared object or relocatable) + if ( object.IsExecutable() ) + { + // Get the entry point address for this object + lldb_private::Address entry = object.GetEntryPointAddress( ); + // Return the entry point address + return entry.GetFileAddress( ); + } + // No idea so back out + return LLDB_INVALID_ADDRESS; +} + +const SectionList * +DynamicLoaderHexagonDYLD::GetSectionListFromModule(const ModuleSP module) const +{ + SectionList *sections = nullptr; + if (module.get()) + { + ObjectFile *obj_file = module->GetObjectFile(); + if (obj_file) + { + sections = obj_file->GetSectionList(); + } + } + return sections; +} + +static int ReadInt(Process *process, addr_t addr) +{ + Error error; + int value = (int)process->ReadUnsignedIntegerFromMemory(addr, sizeof(uint32_t), 0, error); + if (error.Fail()) + return -1; + else + return value; +} + +lldb::addr_t +DynamicLoaderHexagonDYLD::GetThreadLocalData (const lldb::ModuleSP module, const lldb::ThreadSP thread) +{ + auto it = m_loaded_modules.find (module); + if (it == m_loaded_modules.end()) + return LLDB_INVALID_ADDRESS; + + addr_t link_map = it->second; + if (link_map == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + const HexagonDYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo(); + if (!metadata.valid) + return LLDB_INVALID_ADDRESS; + + // Get the thread pointer. + addr_t tp = thread->GetThreadPointer (); + if (tp == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + // Find the module's modid. + int modid = ReadInt (m_process, link_map + metadata.modid_offset); + if (modid == -1) + return LLDB_INVALID_ADDRESS; + + // Lookup the DTV stucture for this thread. + addr_t dtv_ptr = tp + metadata.dtv_offset; + addr_t dtv = ReadPointer (dtv_ptr); + if (dtv == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + // Find the TLS block for this module. + addr_t dtv_slot = dtv + metadata.dtv_slot_size*modid; + addr_t tls_block = ReadPointer (dtv_slot + metadata.tls_offset); + + Module *mod = module.get(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderHexagonDYLD::Performed TLS lookup: " + "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 ", modid=%i, tls_block=0x%" PRIx64, + mod->GetObjectName().AsCString(""), link_map, tp, modid, tls_block); + + return tls_block; +} diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h new file mode 100644 index 000000000000..aafa385c0fca --- /dev/null +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h @@ -0,0 +1,182 @@ +//===-- DynamicLoaderHexagon.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_DynamicLoaderHexagon_H_ +#define liblldb_DynamicLoaderHexagon_H_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Target/DynamicLoader.h" + +#include "HexagonDYLDRendezvous.h" + +class DynamicLoaderHexagonDYLD : public lldb_private::DynamicLoader +{ +public: + + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb_private::DynamicLoader * + CreateInstance(lldb_private::Process *process, bool force); + + DynamicLoaderHexagonDYLD(lldb_private::Process *process); + + virtual + ~DynamicLoaderHexagonDYLD(); + + //------------------------------------------------------------------ + // DynamicLoader protocol + //------------------------------------------------------------------ + + virtual void + DidAttach(); + + virtual void + DidLaunch(); + + virtual lldb::ThreadPlanSP + GetStepThroughTrampolinePlan(lldb_private::Thread &thread, + bool stop_others); + + virtual lldb_private::Error + CanLoadImage(); + + virtual lldb::addr_t + GetThreadLocalData (const lldb::ModuleSP module, const lldb::ThreadSP thread); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + + virtual void + GetPluginCommandHelp(const char *command, lldb_private::Stream *strm); + + virtual lldb_private::Error + ExecutePluginCommand(lldb_private::Args &command, lldb_private::Stream *strm); + + virtual lldb_private::Log * + EnablePluginLogging(lldb_private::Stream *strm, lldb_private::Args &command); + +protected: + /// Runtime linker rendezvous structure. + HexagonDYLDRendezvous m_rendezvous; + + /// Virtual load address of the inferior process. + lldb::addr_t m_load_offset; + + /// Virtual entry address of the inferior process. + lldb::addr_t m_entry_point; + + /// Rendezvous breakpoint. + lldb::break_id_t m_dyld_bid; + + /// Loaded module list. (link map for each module) + std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>> m_loaded_modules; + + /// Enables a breakpoint on a function called by the runtime + /// linker each time a module is loaded or unloaded. + bool + SetRendezvousBreakpoint(); + + /// Callback routine which updates the current list of loaded modules based + /// on the information supplied by the runtime linker. + static bool + RendezvousBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set + /// of loaded modules. + void + RefreshModules(); + + /// Updates the load address of every allocatable section in @p module. + /// + /// @param module The module to traverse. + /// + /// @param link_map_addr The virtual address of the link map for the @p module. + /// + /// @param base_addr The virtual base address @p module is loaded at. + void + UpdateLoadedSections(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr); + + /// Removes the loaded sections from the target in @p module. + /// + /// @param module The module to traverse. + void + UnloadSections(const lldb::ModuleSP module); + + /// Locates or creates a module given by @p file and updates/loads the + /// resulting module at the virtual base address @p base_addr. + lldb::ModuleSP + LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t link_map_addr, lldb::addr_t base_addr); + + /// Callback routine invoked when we hit the breakpoint on process entry. + /// + /// This routine is responsible for resolving the load addresses of all + /// dependent modules required by the inferior and setting up the rendezvous + /// breakpoint. + static bool + EntryBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + /// Helper for the entry breakpoint callback. Resolves the load addresses + /// of all dependent modules. + void + LoadAllCurrentModules(); + + /// Computes a value for m_load_offset returning the computed address on + /// success and LLDB_INVALID_ADDRESS on failure. + lldb::addr_t + ComputeLoadOffset(); + + /// Computes a value for m_entry_point returning the computed address on + /// success and LLDB_INVALID_ADDRESS on failure. + lldb::addr_t + GetEntryPoint(); + + /// Checks to see if the target module has changed, updates the target + /// accordingly and returns the target executable module. + lldb::ModuleSP + GetTargetExecutable(); + + /// return the address of the Rendezvous breakpoint + lldb::addr_t + FindRendezvousBreakpointAddress( ); + +private: + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderHexagonDYLD); + + const lldb_private::SectionList * + GetSectionListFromModule(const lldb::ModuleSP module) const; +}; + +#endif // liblldb_DynamicLoaderHexagonDYLD_H_ diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp new file mode 100644 index 000000000000..5035e9d8bb17 --- /dev/null +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp @@ -0,0 +1,403 @@ +//===-- HexagonDYLDRendezvous.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "HexagonDYLDRendezvous.h" + +using namespace lldb; +using namespace lldb_private; + +/// Locates the address of the rendezvous structure. Returns the address on +/// success and LLDB_INVALID_ADDRESS on failure. +static addr_t +ResolveRendezvousAddress(Process *process) +{ + addr_t info_location; + addr_t info_addr; + Error error; + + info_location = process->GetImageInfoAddress(); + + if (info_location == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + info_addr = process->ReadPointerFromMemory(info_location, error); + if (error.Fail()) + return LLDB_INVALID_ADDRESS; + + if (info_addr == 0) + return LLDB_INVALID_ADDRESS; + + return info_addr; +} + +HexagonDYLDRendezvous::HexagonDYLDRendezvous(Process *process) + : m_process(process), + m_rendezvous_addr(LLDB_INVALID_ADDRESS), + m_current(), + m_previous(), + m_soentries(), + m_added_soentries(), + m_removed_soentries() +{ + m_thread_info.valid = false; + + // Cache a copy of the executable path + if (m_process) + { + Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer(); + if (exe_mod) + exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX); + } +} + +bool +HexagonDYLDRendezvous::Resolve() +{ + const size_t word_size = 4; + Rendezvous info; + size_t address_size; + size_t padding; + addr_t info_addr; + addr_t cursor; + + address_size = m_process->GetAddressByteSize(); + padding = address_size - word_size; + + if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) + cursor = info_addr = ResolveRendezvousAddress(m_process); + else + cursor = info_addr = m_rendezvous_addr; + + if (cursor == LLDB_INVALID_ADDRESS) + return false; + + if (!(cursor = ReadWord(cursor, &info.version, word_size))) + return false; + + if (!(cursor = ReadPointer(cursor + padding, &info.map_addr))) + return false; + + if (!(cursor = ReadPointer(cursor, &info.brk))) + return false; + + if (!(cursor = ReadWord(cursor, &info.state, word_size))) + return false; + + if (!(cursor = ReadPointer(cursor + padding, &info.ldbase))) + return false; + + // The rendezvous was successfully read. Update our internal state. + m_rendezvous_addr = info_addr; + m_previous = m_current; + m_current = info; + + return UpdateSOEntries(); +} + +void +HexagonDYLDRendezvous::SetRendezvousAddress( lldb::addr_t addr ) +{ + m_rendezvous_addr = addr; +} + +bool +HexagonDYLDRendezvous::IsValid() +{ + return m_rendezvous_addr != LLDB_INVALID_ADDRESS; +} + +bool +HexagonDYLDRendezvous::UpdateSOEntries() +{ + SOEntry entry; + + if (m_current.map_addr == 0) + return false; + + // When the previous and current states are consistent this is the first + // time we have been asked to update. Just take a snapshot of the currently + // loaded modules. + if (m_previous.state == eConsistent && m_current.state == eConsistent) + return TakeSnapshot(m_soentries); + + // If we are about to add or remove a shared object clear out the current + // state and take a snapshot of the currently loaded images. + if (m_current.state == eAdd || m_current.state == eDelete) + { + // this is a fudge so that we can clear the assert below. + m_previous.state = eConsistent; + // We hit this assert on the 2nd run of this function after running the calc example + assert(m_previous.state == eConsistent); + m_soentries.clear(); + m_added_soentries.clear(); + m_removed_soentries.clear(); + return TakeSnapshot(m_soentries); + } + assert(m_current.state == eConsistent); + + // Otherwise check the previous state to determine what to expect and update + // accordingly. + if (m_previous.state == eAdd) + return UpdateSOEntriesForAddition(); + else if (m_previous.state == eDelete) + return UpdateSOEntriesForDeletion(); + + return false; +} + +bool +HexagonDYLDRendezvous::UpdateSOEntriesForAddition() +{ + SOEntry entry; + iterator pos; + + assert(m_previous.state == eAdd); + + if (m_current.map_addr == 0) + return false; + + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) + { + if (!ReadSOEntryFromMemory(cursor, entry)) + return false; + + // Only add shared libraries and not the executable. + // On Linux this is indicated by an empty path in the entry. + // On FreeBSD it is the name of the executable. + if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0) + continue; + + pos = std::find(m_soentries.begin(), m_soentries.end(), entry); + if (pos == m_soentries.end()) + { + m_soentries.push_back(entry); + m_added_soentries.push_back(entry); + } + } + + return true; +} + +bool +HexagonDYLDRendezvous::UpdateSOEntriesForDeletion() +{ + SOEntryList entry_list; + iterator pos; + + assert(m_previous.state == eDelete); + + if (!TakeSnapshot(entry_list)) + return false; + + for (iterator I = begin(); I != end(); ++I) + { + pos = std::find(entry_list.begin(), entry_list.end(), *I); + if (pos == entry_list.end()) + m_removed_soentries.push_back(*I); + } + + m_soentries = entry_list; + return true; +} + +bool +HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) +{ + SOEntry entry; + + if (m_current.map_addr == 0) + return false; + + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) + { + if (!ReadSOEntryFromMemory(cursor, entry)) + return false; + + // Only add shared libraries and not the executable. + // On Linux this is indicated by an empty path in the entry. + // On FreeBSD it is the name of the executable. + if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0) + continue; + + entry_list.push_back(entry); + } + + return true; +} + +addr_t +HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) +{ + Error error; + + *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error); + if (error.Fail()) + return 0; + + return addr + size; +} + +addr_t +HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) +{ + Error error; + + *dst = m_process->ReadPointerFromMemory(addr, error); + if (error.Fail()) + return 0; + + return addr + m_process->GetAddressByteSize(); +} + +std::string +HexagonDYLDRendezvous::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++; + } + } + + return str; +} + +bool +HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) +{ + entry.clear(); + entry.link_addr = addr; + + if (!(addr = ReadPointer(addr, &entry.base_addr))) + return false; + + if (!(addr = ReadPointer(addr, &entry.path_addr))) + return false; + + if (!(addr = ReadPointer(addr, &entry.dyn_addr))) + return false; + + if (!(addr = ReadPointer(addr, &entry.next))) + return false; + + if (!(addr = ReadPointer(addr, &entry.prev))) + return false; + + entry.path = ReadStringFromMemory(entry.path_addr); + + return true; +} + +bool +HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field, uint32_t& value) +{ + Target& target = m_process->GetTarget(); + + SymbolContextList list; + if (!target.GetImages().FindSymbolsWithNameAndType (ConstString(name), eSymbolTypeAny, list)) + return false; + + Address address = list[0].symbol->GetAddress(); + addr_t addr = address.GetLoadAddress (&target); + if (addr == LLDB_INVALID_ADDRESS) + return false; + + Error error; + value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(addr + field*sizeof(uint32_t), sizeof(uint32_t), 0, error); + if (error.Fail()) + return false; + + if (field == eSize) + value /= 8; // convert bits to bytes + + return true; +} + +const HexagonDYLDRendezvous::ThreadInfo& +HexagonDYLDRendezvous::GetThreadInfo() +{ + if (!m_thread_info.valid) + { + bool ok = true; + + ok &= FindMetadata ("_thread_db_pthread_dtvp", eOffset, m_thread_info.dtv_offset); + ok &= FindMetadata ("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size); + ok &= FindMetadata ("_thread_db_link_map_l_tls_modid", eOffset, m_thread_info.modid_offset); + ok &= FindMetadata ("_thread_db_dtv_t_pointer_val", eOffset, m_thread_info.tls_offset); + + if (ok) + m_thread_info.valid = true; + } + + return m_thread_info; +} + +void +HexagonDYLDRendezvous::DumpToLog(Log *log) const +{ + int state = GetState(); + + if (!log) + return; + + log->PutCString("HexagonDYLDRendezvous:"); + log->Printf(" Address: %" PRIx64, GetRendezvousAddress()); + log->Printf(" Version: %" PRIu64, GetVersion()); + log->Printf(" Link : %" PRIx64, GetLinkMapAddress()); + log->Printf(" Break : %" PRIx64, GetBreakAddress()); + log->Printf(" LDBase : %" PRIx64, GetLDBase()); + log->Printf(" State : %s", + (state == eConsistent) ? "consistent" : + (state == eAdd) ? "add" : + (state == eDelete) ? "delete" : "unknown"); + + iterator I = begin(); + iterator E = end(); + + if (I != E) + log->PutCString("HexagonDYLDRendezvous SOEntries:"); + + for (int i = 1; I != E; ++I, ++i) + { + log->Printf("\n SOEntry [%d] %s", i, I->path.c_str()); + log->Printf(" Base : %" PRIx64, I->base_addr); + log->Printf(" Path : %" PRIx64, I->path_addr); + log->Printf(" Dyn : %" PRIx64, I->dyn_addr); + log->Printf(" Next : %" PRIx64, I->next); + log->Printf(" Prev : %" PRIx64, I->prev); + } +} diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h new file mode 100644 index 000000000000..cd5121330457 --- /dev/null +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h @@ -0,0 +1,279 @@ +//===-- HexagonDYLDRendezvous.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_HexagonDYLDRendezvous_H_ +#define liblldb_HexagonDYLDRendezvous_H_ + +// C Includes +// C++ Includes +#include <list> +#include <string> + +// Other libraries and framework includes +#include "lldb/lldb-defines.h" +#include "lldb/lldb-types.h" + +namespace lldb_private +{ + class Process; +} + +/// @class HexagonDYLDRendezvous +/// @brief Interface to the runtime linker. +/// +/// A structure is present in a processes memory space which is updated by the +/// runtime liker each time a module is loaded or unloaded. This class provides +/// an interface to this structure and maintains a consistent snapshot of the +/// currently loaded modules. +class HexagonDYLDRendezvous +{ + + // This structure is used to hold the contents of the debug rendezvous + // information (struct r_debug) as found in the inferiors memory. Note that + // the layout of this struct is not binary compatible, it is simply large + // enough to hold the information on both 32 and 64 bit platforms. + struct Rendezvous { + uint64_t version; + lldb::addr_t map_addr; + lldb::addr_t brk; + uint64_t state; + lldb::addr_t ldbase; + + Rendezvous() + : version (0) + , map_addr(LLDB_INVALID_ADDRESS) + , brk (LLDB_INVALID_ADDRESS) + , state (0) + , ldbase (0) + { } + + }; + +public: + // Various metadata supplied by the inferior's threading library to describe + // the per-thread state. + struct ThreadInfo { + bool valid; // whether we read valid metadata + uint32_t dtv_offset; // offset of DTV pointer within pthread + uint32_t dtv_slot_size; // size of one DTV slot + uint32_t modid_offset; // offset of module ID within link_map + uint32_t tls_offset; // offset of TLS pointer within DTV slot + }; + + HexagonDYLDRendezvous(lldb_private::Process *process); + + /// Update the internal snapshot of runtime linker rendezvous and recompute + /// the currently loaded modules. + /// + /// This method should be called once one start up, then once each time the + /// runtime linker enters the function given by GetBreakAddress(). + /// + /// @returns true on success and false on failure. + /// + /// @see GetBreakAddress(). + bool + Resolve(); + + /// @returns true if this rendezvous has been located in the inferiors + /// address space and false otherwise. + bool + IsValid(); + + /// @returns the address of the rendezvous structure in the inferiors + /// address space. + lldb::addr_t + GetRendezvousAddress() const { return m_rendezvous_addr; } + + /// Provide the dyld structure address + void + SetRendezvousAddress( lldb::addr_t ); + + /// @returns the version of the rendezvous protocol being used. + uint64_t + GetVersion() const { return m_current.version; } + + /// @returns address in the inferiors address space containing the linked + /// list of shared object descriptors. + lldb::addr_t + GetLinkMapAddress() const { return m_current.map_addr; } + + /// A breakpoint should be set at this address and Resolve called on each + /// hit. + /// + /// @returns the address of a function called by the runtime linker each + /// time a module is loaded/unloaded, or about to be loaded/unloaded. + /// + /// @see Resolve() + lldb::addr_t + GetBreakAddress() const { return m_current.brk; } + + /// In hexagon it is possible that we can know the dyld breakpoint without + /// having to find it from the rendezvous structure + /// + void + SetBreakAddress( lldb::addr_t addr ) { m_current.brk = addr; } + + /// Returns the current state of the rendezvous structure. + uint64_t + GetState() const { return m_current.state; } + + /// @returns the base address of the runtime linker in the inferiors address + /// space. + lldb::addr_t + GetLDBase() const { return m_current.ldbase; } + + /// @returns the thread layout metadata from the inferiors thread library. + const ThreadInfo& + GetThreadInfo(); + + /// @returns true if modules have been loaded into the inferior since the + /// last call to Resolve(). + bool + ModulesDidLoad() const { return !m_added_soentries.empty(); } + + /// @returns true if modules have been unloaded from the inferior since the + /// last call to Resolve(). + bool + ModulesDidUnload() const { return !m_removed_soentries.empty(); } + + void + DumpToLog(lldb_private::Log *log) const; + + /// @brief Constants describing the state of the rendezvous. + /// + /// @see GetState(). + enum RendezvousState + { + eConsistent = 0, + eAdd , + eDelete , + }; + + /// @brief Structure representing the shared objects currently loaded into + /// the inferior process. + /// + /// This object is a rough analogue to the struct link_map object which + /// actually lives in the inferiors memory. + struct SOEntry { + lldb::addr_t link_addr; ///< Address of this link_map. + lldb::addr_t base_addr; ///< Base address of the loaded object. + lldb::addr_t path_addr; ///< String naming the shared object. + lldb::addr_t dyn_addr; ///< Dynamic section of shared object. + lldb::addr_t next; ///< Address of next so_entry. + lldb::addr_t prev; ///< Address of previous so_entry. + std::string path; ///< File name of shared object. + + SOEntry() { clear(); } + + bool operator ==(const SOEntry &entry) { + return this->path == entry.path; + } + + void clear() { + link_addr = 0; + base_addr = 0; + path_addr = 0; + dyn_addr = 0; + next = 0; + prev = 0; + path.clear(); + } + }; + +protected: + typedef std::list<SOEntry> SOEntryList; + +public: + typedef SOEntryList::const_iterator iterator; + + /// Iterators over all currently loaded modules. + iterator begin() const { return m_soentries.begin(); } + iterator end() const { return m_soentries.end(); } + + /// Iterators over all modules loaded into the inferior since the last call + /// to Resolve(). + iterator loaded_begin() const { return m_added_soentries.begin(); } + iterator loaded_end() const { return m_added_soentries.end(); } + + /// Iterators over all modules unloaded from the inferior since the last + /// call to Resolve(). + iterator unloaded_begin() const { return m_removed_soentries.begin(); } + iterator unloaded_end() const { return m_removed_soentries.end(); } + +protected: + lldb_private::Process *m_process; + + // Cached copy of executable pathname + char m_exe_path[PATH_MAX]; + + /// Location of the r_debug structure in the inferiors address space. + lldb::addr_t m_rendezvous_addr; + + /// Current and previous snapshots of the rendezvous structure. + Rendezvous m_current; + Rendezvous m_previous; + + /// List of SOEntry objects corresponding to the current link map state. + SOEntryList m_soentries; + + /// List of SOEntry's added to the link map since the last call to Resolve(). + SOEntryList m_added_soentries; + + /// List of SOEntry's removed from the link map since the last call to + /// Resolve(). + SOEntryList m_removed_soentries; + + /// Threading metadata read from the inferior. + ThreadInfo m_thread_info; + + /// Reads an unsigned integer of @p size bytes from the inferior's address + /// space starting at @p addr. + /// + /// @returns addr + size if the read was successful and false otherwise. + lldb::addr_t + ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size); + + /// Reads an address from the inferior's address space starting at @p addr. + /// + /// @returns addr + target address size if the read was successful and + /// 0 otherwise. + lldb::addr_t + ReadPointer(lldb::addr_t addr, lldb::addr_t *dst); + + /// Reads a null-terminated C string from the memory location starting at @p + /// addr. + std::string + ReadStringFromMemory(lldb::addr_t addr); + + /// Reads an SOEntry starting at @p addr. + bool + ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry); + + /// Updates the current set of SOEntries, the set of added entries, and the + /// set of removed entries. + bool + UpdateSOEntries(); + + bool + UpdateSOEntriesForAddition(); + + bool + UpdateSOEntriesForDeletion(); + + /// Reads the current list of shared objects according to the link map + /// supplied by the runtime linker. + bool + TakeSnapshot(SOEntryList &entry_list); + + enum PThreadField { eSize, eNElem, eOffset }; + + bool FindMetadata(const char *name, PThreadField field, uint32_t& value); +}; + +#endif // liblldb_HexagonDYLDRendezvous_H_ diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp index c079d0fc381f..04a6792fbf01 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp @@ -57,11 +57,10 @@ ParseAuxvEntry(DataExtractor &data, DataBufferSP AuxVector::GetAuxvData() { -#if defined(__linux__) || defined(__FreeBSD__) - if (m_process->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) - return static_cast<ProcessElfCore *>(m_process)->GetAuxvData(); -#endif - return lldb_private::Host::GetAuxvData(m_process); + if (m_process) + return m_process->GetAuxvData (); + else + return DataBufferSP (); } void diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp index 3c5dcc5222af..0e203fe43a79 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -14,6 +14,7 @@ #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" +#include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -28,21 +29,61 @@ using namespace lldb_private; static addr_t ResolveRendezvousAddress(Process *process) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); addr_t info_location; addr_t info_addr; Error error; + // 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(); + if (log) + log->Printf ("%s info_location = 0x%" PRIx64, __FUNCTION__, info_location); + // 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; + if (target) + { + ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); + Address addr = obj_file->GetImageInfoAddress(target); + + if (addr.IsValid()) + { + info_location = addr.GetLoadAddress(target); + if (log) + log->Printf ("%s resolved via direct object file approach to 0x%" PRIx64, __FUNCTION__, info_location); + } + else + { + if (log) + log->Printf ("%s FAILED - direct object file approach did not yield a valid address", __FUNCTION__); + } + } + } + + if (info_location == LLDB_INVALID_ADDRESS) + { + if (log) + log->Printf ("%s FAILED - invalid info address", __FUNCTION__); return LLDB_INVALID_ADDRESS; + } info_addr = process->ReadPointerFromMemory(info_location, error); if (error.Fail()) + { + if (log) + log->Printf ("%s FAILED - could not read from the info location: %s", __FUNCTION__, error.AsCString ()); return LLDB_INVALID_ADDRESS; + } if (info_addr == 0) + { + if (log) + log->Printf ("%s FAILED - the rendezvous address contained at 0x%" PRIx64 " returned a null value", __FUNCTION__, info_location); return LLDB_INVALID_ADDRESS; + } return info_addr; } @@ -56,6 +97,8 @@ DYLDRendezvous::DYLDRendezvous(Process *process) m_added_soentries(), m_removed_soentries() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + m_thread_info.valid = false; // Cache a copy of the executable path @@ -63,13 +106,24 @@ DYLDRendezvous::DYLDRendezvous(Process *process) { Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer(); if (exe_mod) + { exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX); + if (log) + log->Printf ("DYLDRendezvous::%s exe module executable path set: '%s'", __FUNCTION__, m_exe_path); + } + else + { + if (log) + log->Printf ("DYLDRendezvous::%s cannot cache exe module path: null executable module pointer", __FUNCTION__); + } } } bool DYLDRendezvous::Resolve() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + const size_t word_size = 4; Rendezvous info; size_t address_size; @@ -79,12 +133,16 @@ DYLDRendezvous::Resolve() address_size = m_process->GetAddressByteSize(); padding = address_size - word_size; + if (log) + log->Printf ("DYLDRendezvous::%s address size: %zu, padding %zu", __FUNCTION__, address_size, padding); if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) cursor = info_addr = ResolveRendezvousAddress(m_process); else cursor = info_addr = m_rendezvous_addr; - + if (log) + log->Printf ("DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__, cursor); + if (cursor == LLDB_INVALID_ADDRESS) return false; diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 286b1ef62d9a..549e5f9b5345 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -468,7 +468,7 @@ DynamicLoaderPOSIXDYLD::GetThreadLocalData (const lldb::ModuleSP module, const l if (modid == -1) return LLDB_INVALID_ADDRESS; - // Lookup the DTV stucture for this thread. + // Lookup the DTV structure for this thread. addr_t dtv_ptr = tp + metadata.dtv_offset; addr_t dtv = ReadPointer (dtv_ptr); if (dtv == LLDB_INVALID_ADDRESS) diff --git a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h index a99435fa32ad..ea33164cf823 100644 --- a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h +++ b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h @@ -17,7 +17,6 @@ #include <string> // Other libraries and framework includes -#include "llvm/Support/MachO.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Host/FileSpec.h" diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index f1cb41d5a913..fa8681ed69fe 100644 --- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -24,6 +24,7 @@ #include "Plugins/Process/Utility/ARMUtils.h" #include "Utility/ARM_DWARF_Registers.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/MathExtras.h" // for SignExtend32 template function // and countTrailingZeros function @@ -266,7 +267,7 @@ EmulateInstructionARM::WriteBits32Unknown (int n) } bool -EmulateInstructionARM::GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo ®_info) +EmulateInstructionARM::GetRegisterInfo (lldb::RegisterKind reg_kind, uint32_t reg_num, RegisterInfo ®_info) { if (reg_kind == eRegisterKindGeneric) { @@ -2169,7 +2170,7 @@ EmulateInstructionARM::EmulateVPOP (const uint32_t opcode, const ARMEncoding enc addr_t sp_offset = imm32; addr_t addr = sp; uint32_t i; - uint64_t data; // uint64_t to accomodate 64-bit registers. + uint64_t data; // uint64_t to accommodate 64-bit registers. EmulateInstruction::Context context; if (conditional) @@ -3626,7 +3627,7 @@ EmulateInstructionARM::EmulateLDMDA (const uint32_t opcode, const ARMEncoding en } // LDMDB loads multiple registers from consecutive memory locations using an address from a base register. The -// consecutive memory lcoations end just below this address, and the address of the lowest of those locations can +// consecutive memory locations end just below this address, and the address of the lowest of those locations can // be optionally written back to the base register. bool EmulateInstructionARM::EmulateLDMDB (const uint32_t opcode, const ARMEncoding encoding) @@ -4033,7 +4034,7 @@ EmulateInstructionARM::EmulateLDRRtRnImm (const uint32_t opcode, const ARMEncodi } // STM (Store Multiple Increment After) stores multiple registers to consecutive memory locations using an address -// from a base register. The consecutive memory locations start at this address, and teh address just above the last +// from a base register. The consecutive memory locations start at this address, and the address just above the last // of those locations can optionally be written back to the base register. bool EmulateInstructionARM::EmulateSTM (const uint32_t opcode, const ARMEncoding encoding) @@ -4588,7 +4589,7 @@ EmulateInstructionARM::EmulateSTMIB (const uint32_t opcode, const ARMEncoding en return true; } -// STR (store immediate) calcualtes an address from a base register value and an immediate offset, and stores a word +// STR (store immediate) calculates an address from a base register value and an immediate offset, and stores a word // from a register to memory. It can use offset, post-indexed, or pre-indexed addressing. bool EmulateInstructionARM::EmulateSTRThumb (const uint32_t opcode, const ARMEncoding encoding) @@ -5076,7 +5077,7 @@ EmulateInstructionARM::EmulateSTRBThumb (const uint32_t opcode, const ARMEncodin } // STRH (register) calculates an address from a base register value and an offset register value, and stores a -// halfword from a register to memory. The offset register alue can be shifted left by 0, 1, 2, or 3 bits. +// halfword from a register to memory. The offset register value can be shifted left by 0, 1, 2, or 3 bits. bool EmulateInstructionARM::EmulateSTRHRegister (const uint32_t opcode, const ARMEncoding encoding) { @@ -5941,7 +5942,7 @@ EmulateInstructionARM::EmulateLDRImmediateARM (const uint32_t opcode, const ARME } // LDR (register) calculates an address from a base register value and an offset register value, loads a word -// from memory, and writes it to a resgister. The offset register value can optionally be shifted. +// from memory, and writes it to a register. The offset register value can optionally be shifted. bool EmulateInstructionARM::EmulateLDRRegister (const uint32_t opcode, const ARMEncoding encoding) { @@ -11033,7 +11034,7 @@ EmulateInstructionARM::EmulateVSTM (const uint32_t opcode, const ARMEncoding enc } // A8.6.320 -// This instruciton loads a single extension register fronm memory, using an address from an ARM core register, with +// This instruction loads a single extension register from memory, using an address from an ARM core register, with // an optional offset. bool EmulateInstructionARM::EmulateVLDR (const uint32_t opcode, ARMEncoding encoding) @@ -11638,7 +11639,7 @@ EmulateInstructionARM::EmulateVLD1Single (const uint32_t opcode, const ARMEncodi } // A8.6.391 VST1 (multiple single elements) -// Vector Store (multiple single elements) stores elements to memory from one, two, three, or four regsiters, without +// Vector Store (multiple single elements) stores elements to memory from one, two, three, or four registers, without // interleaving. Every element of each register is stored. bool EmulateInstructionARM::EmulateVST1Multiple (const uint32_t opcode, ARMEncoding encoding) @@ -12506,7 +12507,7 @@ EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode, uint32 { 0xfe500000, 0xf8100000, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRFE, "rfe{<amode>} <Rn>{!}" } }; - static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode); + static const size_t k_num_arm_opcodes = llvm::array_lengthof(g_arm_opcodes); for (size_t i=0; i<k_num_arm_opcodes; ++i) { @@ -12832,7 +12833,7 @@ EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode, uint { 0xfffff080, 0xfa1ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c>.w <Rd>,<Rm>{,<rotation>}" }, }; - const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode); + const size_t k_num_thumb_opcodes = llvm::array_lengthof(g_thumb_opcodes); for (size_t i=0; i<k_num_thumb_opcodes; ++i) { if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value && @@ -13019,7 +13020,7 @@ EmulateInstructionARM::ConditionPassed (const uint32_t opcode, bool *is_conditio break; case 7: // Always execute (cond == 0b1110, or the special 0b1111 which gives - // opcodes different meanings, but always means execution happpens. + // opcodes different meanings, but always means execution happens. if (is_conditional) *is_conditional = false; result = true; @@ -13307,7 +13308,8 @@ EmulateInstructionARM::AddWithCarry (uint32_t x, uint32_t y, uint8_t carry_in) uint32_t EmulateInstructionARM::ReadCoreReg(uint32_t num, bool *success) { - uint32_t reg_kind, reg_num; + lldb::RegisterKind reg_kind; + uint32_t reg_num; switch (num) { case SP_REG: @@ -13388,7 +13390,8 @@ EmulateInstructionARM::WriteCoreRegOptionalFlags (Context &context, } else { - uint32_t reg_kind, reg_num; + lldb::RegisterKind reg_kind; + uint32_t reg_num; switch (Rd) { case SP_REG: diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h index 81e78847a1f3..d107ca6bc702 100644 --- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h +++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h @@ -170,7 +170,7 @@ public: TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data); virtual bool - GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo ®_info); + GetRegisterInfo (lldb::RegisterKind reg_kind, uint32_t reg_num, RegisterInfo ®_info); virtual bool diff --git a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp new file mode 100644 index 000000000000..3900af9b00d0 --- /dev/null +++ b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp @@ -0,0 +1,719 @@ +//===-- EmulateInstructionARM64.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "EmulateInstructionARM64.h" + +#include <stdlib.h> + +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Stream.h" +#include "lldb/Symbol/UnwindPlan.h" + +#include "Plugins/Process/Utility/ARMDefines.h" +#include "Plugins/Process/Utility/ARMUtils.h" +#include "Utility/ARM64_DWARF_Registers.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/MathExtras.h" // for SignExtend32 template function + // and CountTrailingZeros_32 function + +#include "Plugins/Process/Utility/InstructionUtils.h" + +using namespace lldb; +using namespace lldb_private; + +#define No_VFP 0 +#define VFPv1 (1u << 1) +#define VFPv2 (1u << 2) +#define VFPv3 (1u << 3) +#define AdvancedSIMD (1u << 4) + +#define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD) +#define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD) +#define VFPv2v3 (VFPv2 | VFPv3) + +#define UInt(x) ((uint64_t)x) +#define SInt(x) ((int64_t)x) +#define bit bool +#define boolean bool +#define integer int64_t + +static inline bool +IsZero(uint64_t x) +{ + return x == 0; +} + +static inline uint64_t +NOT(uint64_t x) +{ + return ~x; +} + +#if 0 +// LSL_C() +// ======= +static inline uint64_t +LSL_C (uint64_t x, integer shift, bool &carry_out) +{ + assert (shift >= 0); + uint64_t result = x << shift; + carry_out = ((1ull << (64-1)) >> (shift - 1)) != 0; + return result; +} +#endif + +// LSL() +// ===== + +static inline uint64_t +LSL(uint64_t x, integer shift) +{ + if (shift == 0) + return x; + return x << shift; +} + +// AddWithCarry() +// =============== +static inline uint64_t +AddWithCarry (uint32_t N, uint64_t x, uint64_t y, bit carry_in, EmulateInstructionARM64::ProcState &proc_state) +{ + uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in); + int64_t signed_sum = SInt(x) + SInt(y) + UInt(carry_in); + uint64_t result = unsigned_sum; + if (N < 64) + result = Bits64 (result, N-1, 0); + proc_state.N = Bit64(result, N-1); + proc_state.Z = IsZero(result); + proc_state.C = UInt(result) == unsigned_sum; + proc_state.V = SInt(result) == signed_sum; + return result; +} + +// ConstrainUnpredictable() +// ======================== + +EmulateInstructionARM64::ConstraintType +ConstrainUnpredictable (EmulateInstructionARM64::Unpredictable which) +{ + EmulateInstructionARM64::ConstraintType result = EmulateInstructionARM64::Constraint_UNKNOWN; + switch (which) + { + case EmulateInstructionARM64::Unpredictable_WBOVERLAP: + case EmulateInstructionARM64::Unpredictable_LDPOVERLAP: + // TODO: don't know what to really do here? Pseudo code says: + // set result to one of above Constraint behaviours or UNDEFINED + break; + } + return result; +} + + + +//---------------------------------------------------------------------- +// +// EmulateInstructionARM implementation +// +//---------------------------------------------------------------------- + +void +EmulateInstructionARM64::Initialize () +{ + PluginManager::RegisterPlugin (GetPluginNameStatic (), + GetPluginDescriptionStatic (), + CreateInstance); +} + +void +EmulateInstructionARM64::Terminate () +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +ConstString +EmulateInstructionARM64::GetPluginNameStatic () +{ + ConstString g_plugin_name ("lldb.emulate-instruction.arm64"); + return g_plugin_name; +} + +lldb_private::ConstString +EmulateInstructionARM64::GetPluginName() +{ + static ConstString g_plugin_name ("EmulateInstructionARM64"); + return g_plugin_name; +} + +const char * +EmulateInstructionARM64::GetPluginDescriptionStatic () +{ + return "Emulate instructions for the ARM64 architecture."; +} + +EmulateInstruction * +EmulateInstructionARM64::CreateInstance (const ArchSpec &arch, InstructionType inst_type) +{ + if (EmulateInstructionARM64::SupportsEmulatingInstructionsOfTypeStatic(inst_type)) + { + if (arch.GetTriple().getArch() == llvm::Triple::aarch64) + { + std::auto_ptr<EmulateInstructionARM64> emulate_insn_ap (new EmulateInstructionARM64 (arch)); + if (emulate_insn_ap.get()) + return emulate_insn_ap.release(); + } + } + + return NULL; +} + +bool +EmulateInstructionARM64::SetTargetTriple (const ArchSpec &arch) +{ + if (arch.GetTriple().getArch () == llvm::Triple::arm) + return true; + else if (arch.GetTriple().getArch () == llvm::Triple::thumb) + return true; + + return false; +} + +bool +EmulateInstructionARM64::GetRegisterInfo (RegisterKind reg_kind, uint32_t reg_num, RegisterInfo ®_info) +{ + if (reg_kind == eRegisterKindGeneric) + { + switch (reg_num) + { + case LLDB_REGNUM_GENERIC_PC: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::pc; break; + case LLDB_REGNUM_GENERIC_SP: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::sp; break; + case LLDB_REGNUM_GENERIC_FP: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::fp; break; + case LLDB_REGNUM_GENERIC_RA: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::lr; break; + case LLDB_REGNUM_GENERIC_FLAGS: + // There is no DWARF register number for the CPSR right now... + reg_info.name = "cpsr"; + reg_info.alt_name = NULL; + reg_info.byte_size = 4; + reg_info.byte_offset = 0; + reg_info.encoding = eEncodingUint; + reg_info.format = eFormatHex; + for (uint32_t i=0; i<lldb::kNumRegisterKinds; ++i) + reg_info.kinds[reg_kind] = LLDB_INVALID_REGNUM; + reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; + return true; + + default: return false; + } + } + + if (reg_kind == eRegisterKindDWARF) + return arm64_dwarf::GetRegisterInfo(reg_num, reg_info); + return false; +} + +EmulateInstructionARM64::Opcode* +EmulateInstructionARM64::GetOpcodeForInstruction (const uint32_t opcode) +{ + static EmulateInstructionARM64::Opcode + g_opcodes[] = + { + //---------------------------------------------------------------------- + // Prologue instructions + //---------------------------------------------------------------------- + + // push register(s) + { 0xff000000, 0xd1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUB <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}" }, + { 0xff000000, 0xf1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUBS <Xd>, <Xn|SP>, #<imm> {, <shift>}" }, + { 0xff000000, 0x91000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}" }, + { 0xff000000, 0xb1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS <Xd>, <Xn|SP>, #<imm> {, <shift>}" }, + + + { 0xff000000, 0x51000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUB <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}" }, + { 0xff000000, 0x71000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}" }, + { 0xff000000, 0x11000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}" }, + { 0xff000000, 0x31000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS <Wd>, <Wn|WSP>, #<imm> {, <shift>}" }, + + { 0xffc00000, 0x29000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]" }, + { 0xffc00000, 0xa9000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]" }, + { 0xffc00000, 0x2d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <St>, <St2>, [<Xn|SP>{, #<imm>}]" }, + { 0xffc00000, 0x6d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]" }, + { 0xffc00000, 0xad000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]" }, + + { 0xffc00000, 0xad800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" }, + { 0xffc00000, 0x2d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <St>, <St2>, [<Xn|SP>, #<imm>]!" }, + { 0xffc00000, 0x29800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" }, + { 0xffc00000, 0x6d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" }, + { 0xffc00000, 0xa9800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" }, + + }; + static const size_t k_num_arm_opcodes = llvm::array_lengthof(g_opcodes); + + for (size_t i=0; i<k_num_arm_opcodes; ++i) + { + if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value) + return &g_opcodes[i]; + } + return NULL; +} + +bool +EmulateInstructionARM64::ReadInstruction () +{ + bool success = false; + m_addr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success); + if (success) + { + Context read_inst_context; + read_inst_context.type = eContextReadOpcode; + read_inst_context.SetNoArgs (); + m_opcode.SetOpcode32 (ReadMemoryUnsigned (read_inst_context, m_addr, 4, 0, &success), GetByteOrder()); + } + if (!success) + m_addr = LLDB_INVALID_ADDRESS; + return success; +} + + +bool +EmulateInstructionARM64::EvaluateInstruction (uint32_t evaluate_options) +{ + const uint32_t opcode = m_opcode.GetOpcode32(); + Opcode *opcode_data = GetOpcodeForInstruction(opcode); + if (opcode_data == NULL) + return false; + + //printf ("opcode template for 0x%8.8x: %s\n", opcode, opcode_data->name); + const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC; + m_ignore_conditions = evaluate_options & eEmulateInstructionOptionIgnoreConditions; + + bool success = false; +// if (m_opcode_cpsr == 0 || m_ignore_conditions == false) +// { +// m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, // use eRegisterKindDWARF is we ever get a cpsr DWARF register number +// LLDB_REGNUM_GENERIC_FLAGS, // use arm64_dwarf::cpsr if we ever get one +// 0, +// &success); +// } + + // Only return false if we are unable to read the CPSR if we care about conditions + if (success == false && m_ignore_conditions == false) + return false; + + uint32_t orig_pc_value = 0; + if (auto_advance_pc) + { + orig_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::pc, 0, &success); + if (!success) + return false; + } + + // Call the Emulate... function. + success = (this->*opcode_data->callback) (opcode); + if (!success) + return false; + + if (auto_advance_pc) + { + uint32_t new_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::pc, 0, &success); + if (!success) + return false; + + if (auto_advance_pc && (new_pc_value == orig_pc_value)) + { + EmulateInstruction::Context context; + context.type = eContextAdvancePC; + context.SetNoArgs(); + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::pc, orig_pc_value + 4)) + return false; + } + } + return true; +} + +bool +EmulateInstructionARM64::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + UnwindPlan::RowSP row(new UnwindPlan::Row); + const bool can_replace = false; + + // Our previous Call Frame Address is the stack pointer + row->SetCFARegister (arm64_dwarf::sp); + + // Our previous PC is in the LR + row->SetRegisterLocationToRegister(arm64_dwarf::pc, arm64_dwarf::lr, can_replace); + + unwind_plan.AppendRow (row); + + // All other registers are the same. + + unwind_plan.SetSourceName ("EmulateInstructionARM64"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes); + return true; +} + + + +bool +EmulateInstructionARM64::Emulate_addsub_imm (const uint32_t opcode) +{ + // integer d = UInt(Rd); + // integer n = UInt(Rn); + // integer datasize = if sf == 1 then 64 else 32; + // boolean sub_op = (op == 1); + // boolean setflags = (S == 1); + // bits(datasize) imm; + // + // case shift of + // when '00' imm = ZeroExtend(imm12, datasize); + // when '01' imm = ZeroExtend(imm12 : Zeros(12), datasize); + // when '1x' UNDEFINED; + // + // + // bits(datasize) result; + // bits(datasize) operand1 = if n == 31 then SP[] else X[n]; + // bits(datasize) operand2 = imm; + // bits(4) nzcv; + // bit carry_in; + // + // if sub_op then + // operand2 = NOT(operand2); + // carry_in = 1; + // else + // carry_in = 0; + // + // (result, nzcv) = AddWithCarry(operand1, operand2, carry_in); + // + // if setflags then + // PSTATE.NZCV = nzcv; + // + // if d == 31 && !setflags then + // SP[] = result; + // else + // X[d] = result; + + const uint32_t sf = Bit32(opcode, 31); + const uint32_t op = Bit32(opcode, 30); + const uint32_t S = Bit32(opcode, 29); + const uint32_t shift = Bits32(opcode, 23, 22); + const uint32_t imm12 = Bits32(opcode, 21, 10); + const uint32_t Rn = Bits32(opcode, 9, 5); + const uint32_t Rd = Bits32(opcode, 4, 0); + + bool success = false; + + const uint32_t d = UInt(Rd); + const uint32_t n = UInt(Rn); + const uint32_t datasize = (sf == 1) ? 64 : 32; + boolean sub_op = op == 1; + boolean setflags = S == 1; + uint64_t imm; + + switch (shift) + { + case 0: imm = imm12; break; + case 1: imm = imm12 << 12; break; + default: return false; // UNDEFINED; + } + uint64_t result; + uint64_t operand1 = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::x0 + n, 0, &success); + uint64_t operand2 = imm; + bit carry_in; + + if (sub_op) + { + operand2 = NOT(operand2); + carry_in = 1; + imm = -imm; // For the Register plug offset context below + } + else + { + carry_in = 0; + } + + ProcState proc_state; + + result = AddWithCarry (datasize, operand1, operand2, carry_in, proc_state); + + if (setflags) + { + m_emulated_pstate.N = proc_state.N; + m_emulated_pstate.Z = proc_state.Z; + m_emulated_pstate.C = proc_state.C; + m_emulated_pstate.V = proc_state.V; + } + + Context context; + RegisterInfo reg_info_Rn; + if (arm64_dwarf::GetRegisterInfo (n, reg_info_Rn)) + context.SetRegisterPlusOffset (reg_info_Rn, imm); + + if ((n == arm64_dwarf::sp || n == arm64_dwarf::fp) && + d == arm64_dwarf::sp && + !setflags) + { + context.type = EmulateInstruction::eContextAdjustStackPointer; + } + else if (d == arm64_dwarf::fp && + n == arm64_dwarf::sp && + !setflags) + { + context.type = EmulateInstruction::eContextSetFramePointer; + } + else + { + context.type = EmulateInstruction::eContextImmediate; + } + WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::x0 + d, result); + + return false; +} + +bool +EmulateInstructionARM64::Emulate_ldstpair_off (const uint32_t opcode) +{ + return Emulate_ldstpair (opcode, AddrMode_OFF); +} + + +bool +EmulateInstructionARM64::Emulate_ldstpair_pre (const uint32_t opcode) +{ + return Emulate_ldstpair (opcode, AddrMode_PRE); +} + +bool +EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mode) +{ + uint32_t opc = Bits32(opcode, 31, 30); + uint32_t V = Bit32(opcode, 26); + uint32_t L = Bit32(opcode, 22); + uint32_t imm7 = Bits32(opcode, 21, 15); + uint32_t Rt2 = Bits32(opcode, 14, 10); + uint32_t Rn = Bits32(opcode, 9, 5); + uint32_t Rt = Bits32(opcode, 4, 0); + + integer n = UInt(Rn); + integer t = UInt(Rt); + integer t2 = UInt(Rt2); + uint64_t idx; + + MemOp memop = L == 1 ? MemOp_LOAD : MemOp_STORE; + boolean vector = (V == 1); + //AccType acctype = AccType_NORMAL; + boolean is_signed = false; + boolean wback = a_mode != AddrMode_OFF; + boolean wb_unknown = false; + boolean rt_unknown = false; + integer scale; + integer size; + + if (opc == 3) + return false; // UNDEFINED + + if (vector) + { + scale = 2 + UInt(opc); + } + else + { + scale = (opc & 2) ? 3 : 2; + is_signed = (opc & 1) != 0; + if (is_signed && memop == MemOp_STORE) + return false; // UNDEFINED + } + + if (!vector && wback && ((t == n) || (t2 == n))) + { + switch (ConstrainUnpredictable(Unpredictable_WBOVERLAP)) + { + case Constraint_UNKNOWN: + wb_unknown = true; // writeback is UNKNOWN + break; + + case Constraint_SUPPRESSWB: + wback = false; // writeback is suppressed + break; + + case Constraint_NOP: + memop = MemOp_NOP; // do nothing + wback = false; + break; + + case Constraint_NONE: + break; + } + } + + if (memop == MemOp_LOAD && t == t2) + { + switch (ConstrainUnpredictable(Unpredictable_LDPOVERLAP)) + { + case Constraint_UNKNOWN: + rt_unknown = true; // result is UNKNOWN + break; + + case Constraint_NOP: + memop = MemOp_NOP; // do nothing + wback = false; + break; + + default: + break; + } + } + + idx = LSL(llvm::SignExtend64<7>(imm7), scale); + size = (integer)1 << scale; + uint64_t datasize = size * 8; + uint64_t address; + uint64_t wb_address; + + RegisterValue data_Rt; + RegisterValue data_Rt2; + + // if (vector) + // CheckFPEnabled(false); + + RegisterInfo reg_info_base; + RegisterInfo reg_info_Rt; + RegisterInfo reg_info_Rt2; + if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + n, reg_info_base)) + return false; + + if (vector) + { + if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::v0 + n, reg_info_Rt)) + return false; + if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::v0 + n, reg_info_Rt2)) + return false; + } + else + { + if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + t, reg_info_Rt)) + return false; + if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + t2, reg_info_Rt2)) + return false; + } + + bool success = false; + if (n == 31) + { + //CheckSPAlignment(); + address = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::sp, 0, &success); + } + else + address = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::x0 + n, 0, &success); + + wb_address = address + idx; + if (a_mode != AddrMode_POST) + address = wb_address; + + Context context_t; + Context context_t2; + + if (n == 31 || n == 29) // if this store is based off of the sp or fp register + { + context_t.type = eContextPushRegisterOnStack; + context_t2.type = eContextPushRegisterOnStack; + } + else + { + context_t.type = eContextRegisterPlusOffset; + context_t2.type = eContextRegisterPlusOffset; + } + context_t.SetRegisterToRegisterPlusOffset (reg_info_Rt, reg_info_base, 0); + context_t2.SetRegisterToRegisterPlusOffset (reg_info_Rt2, reg_info_base, size); + uint8_t buffer [RegisterValue::kMaxRegisterByteSize]; + Error error; + + switch (memop) + { + case MemOp_STORE: + { + if (!ReadRegister (®_info_Rt, data_Rt)) + return false; + + if (data_Rt.GetAsMemoryData(®_info_Rt, buffer, reg_info_Rt.byte_size, eByteOrderLittle, error) == 0) + return false; + + if (!WriteMemory(context_t, address + 0, buffer, reg_info_Rt.byte_size)) + return false; + + if (!ReadRegister (®_info_Rt2, data_Rt2)) + return false; + + if (data_Rt2.GetAsMemoryData(®_info_Rt2, buffer, reg_info_Rt2.byte_size, eByteOrderLittle, error) == 0) + return false; + + if (!WriteMemory(context_t2, address + size, buffer, reg_info_Rt2.byte_size)) + return false; + } + break; + + case MemOp_LOAD: + { + if (rt_unknown) + memset (buffer, 'U', reg_info_Rt.byte_size); + else + { + if (!ReadMemory (context_t, address, buffer, reg_info_Rt.byte_size)) + return false; + } + + if (data_Rt.SetFromMemoryData(®_info_Rt, buffer, reg_info_Rt.byte_size, eByteOrderLittle, error) == 0) + return false; + + if (!vector && is_signed && !data_Rt.SignExtend (datasize)) + return false; + + if (!WriteRegister (context_t, ®_info_Rt, data_Rt)) + return false; + + if (!rt_unknown) + { + if (!ReadMemory (context_t2, address + size, buffer, reg_info_Rt2.byte_size)) + return false; + } + + if (data_Rt2.SetFromMemoryData(®_info_Rt2, buffer, reg_info_Rt2.byte_size, eByteOrderLittle, error) == 0) + return false; + + if (!vector && is_signed && !data_Rt2.SignExtend (datasize)) + return false; + + if (!WriteRegister (context_t2, ®_info_Rt2, data_Rt2)) + return false; + } + break; + + default: + break; + } + + if (wback) + { + if (wb_unknown) + wb_address = LLDB_INVALID_ADDRESS; + Context context; + context.SetImmediateSigned (idx); + if (n == 31) + context.type = eContextAdjustStackPointer; + else + context.type = eContextAdjustBaseRegister; + WriteRegisterUnsigned (context, ®_info_base, wb_address); + } + return true; +} diff --git a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h new file mode 100644 index 000000000000..7e18d09a0ee2 --- /dev/null +++ b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h @@ -0,0 +1,297 @@ +//===-- EmulateInstructionARM64.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef EmulateInstructionARM64_h_ +#define EmulateInstructionARM64_h_ + +#include "lldb/Core/EmulateInstruction.h" +#include "lldb/Core/Error.h" +#include "lldb/Interpreter/OptionValue.h" +#include "Plugins/Process/Utility/ARMDefines.h" + +class EmulateInstructionARM64 : public lldb_private::EmulateInstruction +{ +public: + static void + Initialize (); + + static void + Terminate (); + + static lldb_private::ConstString + GetPluginNameStatic (); + + static const char * + GetPluginDescriptionStatic (); + + static lldb_private::EmulateInstruction * + CreateInstance (const lldb_private::ArchSpec &arch, + lldb_private::InstructionType inst_type); + + static bool + SupportsEmulatingInstructionsOfTypeStatic (lldb_private::InstructionType inst_type) + { + switch (inst_type) + { + case lldb_private::eInstructionTypeAny: + case lldb_private::eInstructionTypePrologueEpilogue: + return true; + + case lldb_private::eInstructionTypePCModifying: + case lldb_private::eInstructionTypeAll: + return false; + } + return false; + } + + virtual lldb_private::ConstString + GetPluginName(); + + virtual lldb_private::ConstString + GetShortPluginName() + { + return GetPluginNameStatic(); + } + + virtual uint32_t + GetPluginVersion() + { + return 1; + } + + bool + SetTargetTriple (const lldb_private::ArchSpec &arch); + + EmulateInstructionARM64 (const lldb_private::ArchSpec &arch) : + EmulateInstruction (arch), + m_opcode_pstate (), + m_emulated_pstate (), + m_ignore_conditions (false) + { + } + + virtual bool + SupportsEmulatingInstructionsOfType (lldb_private::InstructionType inst_type) + { + return SupportsEmulatingInstructionsOfTypeStatic (inst_type); + } + + virtual bool + ReadInstruction (); + + virtual bool + EvaluateInstruction (uint32_t evaluate_options); + + virtual bool + TestEmulation (lldb_private::Stream *out_stream, + lldb_private::ArchSpec &arch, + lldb_private::OptionValueDictionary *test_data) + { + return false; + } + + virtual bool + GetRegisterInfo (lldb::RegisterKind reg_kind, + uint32_t reg_num, + lldb_private::RegisterInfo ®_info); + + virtual bool + CreateFunctionEntryUnwind (lldb_private::UnwindPlan &unwind_plan); + + + typedef enum + { + AddrMode_OFF, + AddrMode_PRE, + AddrMode_POST + } AddrMode; + + typedef enum + { + BranchType_CALL, + BranchType_ERET, + BranchType_DRET, + BranchType_RET, + BranchType_JMP + } BranchType; + + typedef enum + { + CountOp_CLZ, + CountOp_CLS, + CountOp_CNT + } CountOp; + + typedef enum + { + RevOp_RBIT, + RevOp_REV16, + RevOp_REV32, + RevOp_REV64 + } RevOp; + + typedef enum + { + BitwiseOp_NOT, + BitwiseOp_RBIT + } BitwiseOp; + + + typedef enum + { + EL0 = 0, + EL1 = 1, + EL2 = 2, + EL3 = 3 + } ExceptionLevel; + + typedef enum + { + ExtendType_SXTB, + ExtendType_SXTH, + ExtendType_SXTW, + ExtendType_SXTX, + ExtendType_UXTB, + ExtendType_UXTH, + ExtendType_UXTW, + ExtendType_UXTX + } ExtendType; + + typedef enum + { + ExtractType_LEFT, + ExtractType_RIGHT + } ExtractType; + + typedef enum + { + LogicalOp_AND, + LogicalOp_EOR, + LogicalOp_ORR + } LogicalOp; + + typedef enum + { + MemOp_LOAD, + MemOp_STORE, + MemOp_PREFETCH, + MemOp_NOP + } MemOp; + + typedef enum + { + MoveWideOp_N, + MoveWideOp_Z, + MoveWideOp_K + } MoveWideOp; + + typedef enum { + ShiftType_LSL, + ShiftType_LSR, + ShiftType_ASR, + ShiftType_ROR + } ShiftType; + + typedef enum + { + SP0 = 0, + SPx = 1 + } StackPointerSelection; + + typedef enum + { + Unpredictable_WBOVERLAP, + Unpredictable_LDPOVERLAP + } Unpredictable; + + typedef enum + { + Constraint_NONE, + Constraint_UNKNOWN, + Constraint_SUPPRESSWB, + Constraint_NOP + } ConstraintType; + + typedef enum + { + AccType_NORMAL, + AccType_UNPRIV, + AccType_STREAM, + AccType_ALIGNED, + AccType_ORDERED + } AccType; + + typedef struct + { + uint32_t + N:1, + V:1, + C:1, + Z:1, // condition code flags – can also be accessed as PSTATE.[N,Z,C,V] + Q:1, // AArch32 only – CSPR.Q bit + IT:8, // AArch32 only – CPSR.IT bits + J:1, // AArch32 only – CSPR.J bit + T:1, // AArch32 only – CPSR.T bit + SS:1, // Single step process state bit + IL:1, // Illegal state bit + D:1, + A:1, + I:1, + F:1, // Interrupt masks – can also be accessed as PSTATE.[D,A,I,F] + E:1, // AArch32 only – CSPR.E bit + M:5, // AArch32 only – mode encodings + RW:1, // Current register width – 0 is AArch64, 1 is AArch32 + EL:2, // Current exception level (see ExceptionLevel enum) + SP:1; // AArch64 only - Stack Pointer selection (see StackPointerSelection enum) + } ProcState; + +protected: + + typedef struct + { + uint32_t mask; + uint32_t value; + uint32_t vfp_variants; + bool (EmulateInstructionARM64::*callback) (const uint32_t opcode); + const char *name; + } Opcode; + + static Opcode* + GetOpcodeForInstruction (const uint32_t opcode); + + bool + Emulate_addsub_imm (const uint32_t opcode); + +// bool +// Emulate_STP_Q_ldstpair_off (const uint32_t opcode); +// +// bool +// Emulate_STP_S_ldstpair_off (const uint32_t opcode); +// +// bool +// Emulate_STP_32_ldstpair_off (const uint32_t opcode); +// +// bool +// Emulate_STP_D_ldstpair_off (const uint32_t opcode); +// + bool + Emulate_ldstpair_off (const uint32_t opcode); + + bool + Emulate_ldstpair_pre (const uint32_t opcode); + + bool + Emulate_ldstpair (const uint32_t opcode, AddrMode a_mode); + + ProcState m_opcode_pstate; + ProcState m_emulated_pstate; // This can get updated by the opcode. + bool m_ignore_conditions; +}; + +#endif // EmulateInstructionARM64_h_ diff --git a/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp new file mode 100644 index 000000000000..905984d33410 --- /dev/null +++ b/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -0,0 +1,430 @@ +//===-- JITLoaderGDB.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes + +#include "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Target.h" +#include "lldb/Symbol/SymbolVendor.h" + +#include "JITLoaderGDB.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------ +// Debug Interface Structures +//------------------------------------------------------------------ +typedef enum +{ + JIT_NOACTION = 0, + JIT_REGISTER_FN, + JIT_UNREGISTER_FN +} jit_actions_t; + +struct jit_code_entry +{ + struct jit_code_entry *next_entry; + struct jit_code_entry *prev_entry; + const char *symfile_addr; + uint64_t symfile_size; +}; + +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; +}; + +JITLoaderGDB::JITLoaderGDB (lldb_private::Process *process) : + JITLoader(process), + m_jit_objects(), + m_jit_break_id(LLDB_INVALID_BREAK_ID), + m_jit_descriptor_addr(LLDB_INVALID_ADDRESS) +{ +} + +JITLoaderGDB::~JITLoaderGDB () +{ + if (LLDB_BREAK_ID_IS_VALID(m_jit_break_id)) + m_process->GetTarget().RemoveBreakpointByID (m_jit_break_id); +} + +void JITLoaderGDB::DidAttach() +{ + Target &target = m_process->GetTarget(); + ModuleList &module_list = target.GetImages(); + SetJITBreakpoint(module_list); +} + +void JITLoaderGDB::DidLaunch() +{ + Target &target = m_process->GetTarget(); + ModuleList &module_list = target.GetImages(); + SetJITBreakpoint(module_list); +} + +void +JITLoaderGDB::ModulesDidLoad(ModuleList &module_list) +{ + if (!DidSetJITBreakpoint() && m_process->IsAlive()) + SetJITBreakpoint(module_list); +} + +//------------------------------------------------------------------ +// Setup the JIT Breakpoint +//------------------------------------------------------------------ +void +JITLoaderGDB::SetJITBreakpoint(lldb_private::ModuleList &module_list) +{ + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER)); + + if ( DidSetJITBreakpoint() ) + return; + + if (log) + log->Printf("JITLoaderGDB::%s looking for JIT register hook", + __FUNCTION__); + + addr_t jit_addr = GetSymbolAddress(module_list, + ConstString("__jit_debug_register_code"), + eSymbolTypeAny); + if (jit_addr == LLDB_INVALID_ADDRESS) + return; + + m_jit_descriptor_addr = GetSymbolAddress(module_list, + ConstString("__jit_debug_descriptor"), + eSymbolTypeData); + if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS) + { + if (log) + log->Printf( + "JITLoaderGDB::%s failed to find JIT descriptor address", + __FUNCTION__); + return; + } + + if (log) + log->Printf("JITLoaderGDB::%s setting JIT breakpoint", + __FUNCTION__); + + Breakpoint *bp = + m_process->GetTarget().CreateBreakpoint(jit_addr, true, false).get(); + bp->SetCallback(JITDebugBreakpointHit, this, true); + bp->SetBreakpointKind("jit-debug-register"); + m_jit_break_id = bp->GetID(); + + ReadJITDescriptor(true); +} + +bool +JITLoaderGDB::JITDebugBreakpointHit(void *baton, + StoppointCallbackContext *context, + user_id_t break_id, user_id_t break_loc_id) +{ + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER)); + if (log) + log->Printf("JITLoaderGDB::%s hit JIT breakpoint", + __FUNCTION__); + JITLoaderGDB *instance = static_cast<JITLoaderGDB *>(baton); + return instance->ReadJITDescriptor(false); +} + +static void updateSectionLoadAddress(const SectionList §ion_list, + Target &target, + uint64_t symbolfile_addr, + uint64_t symbolfile_size, + uint64_t &vmaddrheuristic, + uint64_t &min_addr, + uint64_t &max_addr) +{ + const uint32_t num_sections = section_list.GetSize(); + for (uint32_t i = 0; i<num_sections; ++i) + { + SectionSP section_sp(section_list.GetSectionAtIndex(i)); + if (section_sp) + { + if(section_sp->IsFake()) { + uint64_t lower = (uint64_t)-1; + uint64_t upper = 0; + updateSectionLoadAddress(section_sp->GetChildren(), target, symbolfile_addr, symbolfile_size, vmaddrheuristic, + lower, upper); + if (lower < min_addr) + min_addr = lower; + if (upper > max_addr) + max_addr = upper; + const lldb::addr_t slide_amount = lower - section_sp->GetFileAddress(); + section_sp->Slide(slide_amount, false); + section_sp->GetChildren().Slide(-slide_amount, false); + section_sp->SetByteSize (upper - lower); + } else { + vmaddrheuristic += 2<<section_sp->GetLog2Align(); + uint64_t lower; + if (section_sp->GetFileAddress() > vmaddrheuristic) + lower = section_sp->GetFileAddress(); + else { + lower = symbolfile_addr+section_sp->GetFileOffset(); + section_sp->SetFileAddress(symbolfile_addr+section_sp->GetFileOffset()); + } + target.SetSectionLoadAddress(section_sp, lower, true); + uint64_t upper = lower + section_sp->GetByteSize(); + if (lower < min_addr) + min_addr = lower; + if (upper > max_addr) + max_addr = upper; + // This is an upper bound, but a good enough heuristic + vmaddrheuristic += section_sp->GetByteSize(); + } + } + } +} + +bool +JITLoaderGDB::ReadJITDescriptor(bool all_entries) +{ + if (m_jit_descriptor_addr == LLDB_INVALID_ADDRESS) + return false; + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER)); + Target &target = m_process->GetTarget(); + ModuleList &module_list = target.GetImages(); + + jit_descriptor jit_desc; + const size_t jit_desc_size = sizeof(jit_desc); + Error error; + size_t bytes_read = m_process->DoReadMemory( + m_jit_descriptor_addr, &jit_desc, jit_desc_size, error); + if (bytes_read != jit_desc_size || !error.Success()) + { + if (log) + log->Printf("JITLoaderGDB::%s failed to read JIT descriptor", + __FUNCTION__); + return false; + } + + jit_actions_t jit_action = (jit_actions_t)jit_desc.action_flag; + addr_t jit_relevant_entry = (addr_t)jit_desc.relevant_entry; + if (all_entries) + { + jit_action = JIT_REGISTER_FN; + jit_relevant_entry = (addr_t)jit_desc.first_entry; + } + + while (jit_relevant_entry != 0) + { + jit_code_entry 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()) + { + if (log) + log->Printf( + "JITLoaderGDB::%s failed to read JIT entry at 0x%" PRIx64, + __FUNCTION__, jit_relevant_entry); + return false; + } + + const addr_t &symbolfile_addr = (addr_t)jit_entry.symfile_addr; + const size_t &symbolfile_size = (size_t)jit_entry.symfile_size; + ModuleSP module_sp; + + if (jit_action == JIT_REGISTER_FN) + { + if (log) + log->Printf( + "JITLoaderGDB::%s registering JIT entry at 0x%" PRIx64 + " (%" PRIu64 " bytes)", + __FUNCTION__, symbolfile_addr, (uint64_t) symbolfile_size); + + char jit_name[64]; + snprintf(jit_name, 64, "JIT(0x%" PRIx64 ")", symbolfile_addr); + module_sp = m_process->ReadModuleFromMemory( + FileSpec(jit_name, false), symbolfile_addr, symbolfile_size); + + if (module_sp && module_sp->GetObjectFile()) + { + bool changed; + m_jit_objects.insert(std::make_pair(symbolfile_addr, module_sp)); + if (module_sp->GetObjectFile()->GetPluginName() == ConstString("mach-o")) + { + ObjectFile *image_object_file = module_sp->GetObjectFile(); + if (image_object_file) + { + const SectionList *section_list = image_object_file->GetSectionList (); + if (section_list) + { + uint64_t vmaddrheuristic = 0; + uint64_t lower = (uint64_t)-1; + uint64_t upper = 0; + updateSectionLoadAddress(*section_list, target, symbolfile_addr, symbolfile_size, + vmaddrheuristic, lower, upper); + } + } + } + else + { + module_sp->SetLoadAddress(target, 0, true, changed); + } + + // load the symbol table right away + module_sp->GetObjectFile()->GetSymtab(); + + module_list.AppendIfNeeded(module_sp); + + ModuleList module_list; + module_list.Append(module_sp); + target.ModulesDidLoad(module_list); + } + else + { + if (log) + log->Printf("JITLoaderGDB::%s failed to load module for " + "JIT entry at 0x%" PRIx64, + __FUNCTION__, symbolfile_addr); + } + } + else if (jit_action == JIT_UNREGISTER_FN) + { + if (log) + log->Printf( + "JITLoaderGDB::%s unregistering JIT entry at 0x%" PRIx64, + __FUNCTION__, symbolfile_addr); + + JITObjectMap::iterator it = m_jit_objects.find(symbolfile_addr); + if (it != m_jit_objects.end()) + { + module_sp = it->second; + ObjectFile *image_object_file = module_sp->GetObjectFile(); + if (image_object_file) + { + const SectionList *section_list = image_object_file->GetSectionList (); + if (section_list) + { + const uint32_t num_sections = section_list->GetSize(); + for (uint32_t i = 0; i<num_sections; ++i) + { + SectionSP section_sp(section_list->GetSectionAtIndex(i)); + if (section_sp) + { + target.GetSectionLoadList().SetSectionUnloaded (section_sp); + } + } + } + } + module_list.Remove(module_sp); + m_jit_objects.erase(it); + } + } + else if (jit_action == JIT_NOACTION) + { + // Nothing to do + } + else + { + assert(false && "Unknown jit action"); + } + + if (all_entries) + jit_relevant_entry = (addr_t)jit_entry.next_entry; + else + jit_relevant_entry = 0; + } + + return false; // Continue Running. +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +JITLoaderGDB::GetPluginNameStatic() +{ + static ConstString g_name("gdb"); + return g_name; +} + +JITLoaderSP +JITLoaderGDB::CreateInstance(Process *process, bool force) +{ + JITLoaderSP jit_loader_sp; + ArchSpec arch (process->GetTarget().GetArchitecture()); + if (arch.GetTriple().getVendor() != llvm::Triple::Apple) + jit_loader_sp.reset(new JITLoaderGDB(process)); + return jit_loader_sp; +} + +const char * +JITLoaderGDB::GetPluginDescriptionStatic() +{ + return "JIT loader plug-in that watches for JIT events using the GDB interface."; +} + +lldb_private::ConstString +JITLoaderGDB::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +JITLoaderGDB::GetPluginVersion() +{ + return 1; +} + +void +JITLoaderGDB::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +JITLoaderGDB::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +bool +JITLoaderGDB::DidSetJITBreakpoint() const +{ + return LLDB_BREAK_ID_IS_VALID(m_jit_break_id); +} + +addr_t +JITLoaderGDB::GetSymbolAddress(ModuleList &module_list, const ConstString &name, + SymbolType symbol_type) const +{ + SymbolContextList target_symbols; + Target &target = m_process->GetTarget(); + + if (!module_list.FindSymbolsWithNameAndType(name, symbol_type, + target_symbols)) + return LLDB_INVALID_ADDRESS; + + SymbolContext sym_ctx; + target_symbols.GetContextAtIndex(0, sym_ctx); + + const Address *jit_descriptor_addr = &sym_ctx.symbol->GetAddress(); + if (!jit_descriptor_addr || !jit_descriptor_addr->IsValid()) + return LLDB_INVALID_ADDRESS; + + const addr_t jit_addr = jit_descriptor_addr->GetLoadAddress(&target); + return jit_addr; +} diff --git a/source/Plugins/JITLoader/GDB/JITLoaderGDB.h b/source/Plugins/JITLoader/GDB/JITLoaderGDB.h new file mode 100644 index 000000000000..5fa66b874972 --- /dev/null +++ b/source/Plugins/JITLoader/GDB/JITLoaderGDB.h @@ -0,0 +1,104 @@ +//===-- JITLoaderGDB.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_JITLoaderGDB_h_ +#define liblldb_JITLoaderGDB_h_ + +// C Includes +// C++ Includes +#include <map> +#include <vector> +#include <string> + +#include "lldb/Target/JITLoader.h" +#include "lldb/Target/Process.h" + +class JITLoaderGDB : public lldb_private::JITLoader +{ +public: + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb::JITLoaderSP + CreateInstance (lldb_private::Process *process, bool force); + + JITLoaderGDB (lldb_private::Process *process); + + virtual + ~JITLoaderGDB (); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + + //------------------------------------------------------------------ + // JITLoader interface + //------------------------------------------------------------------ + virtual void + DidAttach (); + + virtual void + DidLaunch (); + + virtual void + ModulesDidLoad (lldb_private::ModuleList &module_list); + +private: + lldb::addr_t + GetSymbolAddress(lldb_private::ModuleList &module_list, + const lldb_private::ConstString &name, + lldb::SymbolType symbol_type) const; + + void + SetJITBreakpoint(lldb_private::ModuleList &module_list); + + bool + DidSetJITBreakpoint() const; + + bool + ReadJITDescriptor(bool all_entries); + + static bool + JITDebugBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + static void + ProcessStateChangedCallback(void *baton, + lldb_private::Process *process, + lldb::StateType state); + + // A collection of in-memory jitted object addresses and their corresponding modules + typedef std::map<lldb::addr_t, const lldb::ModuleSP> JITObjectMap; + JITObjectMap m_jit_objects; + + lldb::user_id_t m_jit_break_id; + lldb::addr_t m_jit_descriptor_addr; + +}; + +#endif diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 9781dcb093ac..a6c74f3f1fc4 100644 --- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -107,7 +107,7 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value, if (symbol != NULL) { const char *name = symbol->GetMangled().GetDemangledName().AsCString(); - if (strstr(name, vtable_demangled_prefix) == name) + if (name && strstr(name, vtable_demangled_prefix) == name) { Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) @@ -289,7 +289,9 @@ ItaniumABILanguageRuntime::CreateInstance (Process *process, lldb::LanguageType { // FIXME: We have to check the process and make sure we actually know that this process supports // the Itanium ABI. - if (language == eLanguageTypeC_plus_plus) + if (language == eLanguageTypeC_plus_plus || + language == eLanguageTypeC_plus_plus_03 || + language == eLanguageTypeC_plus_plus_11) return new ItaniumABILanguageRuntime (process); else return NULL; diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 32574e3ef2f0..0263c23ce307 100644 --- a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -74,6 +74,25 @@ ObjectContainerBSDArchive::Object::Extract (const DataExtractor& data, lldb::off size_t ar_name_len = 0; std::string str; char *err; + + + // File header + // + // The common format is as follows. + // + // Offset Length Name Format + // 0 16 File name ASCII right padded with spaces (no spaces allowed in file name) + // 16 12 File mod Decimal as cstring right padded with spaces + // 28 6 Owner ID Decimal as cstring right padded with spaces + // 34 6 Group ID Decimal as cstring right padded with spaces + // 40 8 File mode Octal as cstring right padded with spaces + // 48 10 File byte size Decimal as cstring right padded with spaces + // 58 2 File magic 0x60 0x0A + + // Make sure there is enough data for the file header and bail if not + if (!data.ValidOffsetForDataOfSize(offset, 60)) + return LLDB_INVALID_OFFSET; + str.assign ((const char *)data.GetData(&offset, 16), 16); if (str.find("#1/") == 0) { @@ -110,7 +129,11 @@ ObjectContainerBSDArchive::Object::Extract (const DataExtractor& data, lldb::off { if (ar_name_len > 0) { - str.assign ((const char *)data.GetData(&offset, ar_name_len), ar_name_len); + const void *ar_name_ptr = data.GetData(&offset, ar_name_len); + // Make sure there was enough data for the string value and bail if not + if (ar_name_ptr == NULL) + return LLDB_INVALID_OFFSET; + str.assign ((const char *)ar_name_ptr, ar_name_len); ar_name.SetCString (str.c_str()); } ar_file_offset = offset; @@ -224,7 +247,7 @@ ObjectContainerBSDArchive::Archive::FindCachedArchive (const FileSpec &file, con // whose modification time doesn't match. It doesn't make sense // for us to continue to use this BSD archive since we cache only // the object info which consists of file time info and also the - // file offset and file size of any contianed objects. Since + // file offset and file size of any contained objects. Since // this information is now out of date, we won't get the correct // information if we go and extract the file data, so we should // remove the old and outdated entry. @@ -335,7 +358,9 @@ ObjectContainerBSDArchive::CreateInstance Timer scoped_timer (__PRETTY_FUNCTION__, "ObjectContainerBSDArchive::CreateInstance (module = %s, file = %p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")", module_sp->GetFileSpec().GetPath().c_str(), - file, (uint64_t) file_offset, (uint64_t) length); + static_cast<const void*>(file), + static_cast<uint64_t>(file_offset), + static_cast<uint64_t>(length)); // Map the entire .a file to be sure that we don't lose any data if the file // gets updated by a new build while this .a file is being used for debugging @@ -457,11 +482,11 @@ ObjectContainerBSDArchive::ParseHeader () void ObjectContainerBSDArchive::Dump (Stream *s) const { - s->Printf("%p: ", this); + s->Printf("%p: ", static_cast<const void*>(this)); s->Indent(); const size_t num_archs = GetNumArchitectures(); const size_t num_objects = GetNumObjects(); - s->Printf("ObjectContainerBSDArchive, num_archs = %zu, num_objects = %zu", num_archs, num_objects); + s->Printf("ObjectContainerBSDArchive, num_archs = %" PRIu64 ", num_objects = %" PRIu64 "", (uint64_t)num_archs, (uint64_t)num_objects); uint32_t i; ArchSpec arch; s->IndentMore(); diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index a63a01d7ed7a..f027294b7c57 100644 --- a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -183,6 +183,12 @@ ELFHeader::GetRelocationJumpSlotType() const case EM_ARM: slot = R_ARM_JUMP_SLOT; break; + case EM_HEXAGON: + slot = R_HEX_JMP_SLOT; + break; + case EM_AARCH64: + slot = R_AARCH64_JUMP_SLOT; + break; } return slot; diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.h b/source/Plugins/ObjectFile/ELF/ELFHeader.h index aa2c16b6168c..4ea22b51baf7 100644 --- a/source/Plugins/ObjectFile/ELF/ELFHeader.h +++ b/source/Plugins/ObjectFile/ELF/ELFHeader.h @@ -353,7 +353,7 @@ struct ELFRel } /// Returns the symbol index when the given entry represents a 32-bit - /// reloction. + /// relocation. static unsigned RelocSymbol32(const ELFRel &rel) { @@ -361,7 +361,7 @@ struct ELFRel } /// Returns the symbol index when the given entry represents a 64-bit - /// reloction. + /// relocation. static unsigned RelocSymbol64(const ELFRel &rel) { @@ -412,7 +412,7 @@ struct ELFRela } /// Returns the symbol index when the given entry represents a 32-bit - /// reloction. + /// relocation. static unsigned RelocSymbol32(const ELFRela &rela) { @@ -420,7 +420,7 @@ struct ELFRela } /// Returns the symbol index when the given entry represents a 64-bit - /// reloction. + /// relocation. static unsigned RelocSymbol64(const ELFRela &rela) { diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 335090cc0c36..d86aee78947f 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -22,13 +22,16 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/Timer.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" -#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MathExtras.h" #define CASE_AND_STREAM(s, def, width) \ case def: s->Printf("%-*s", width, #def); break; @@ -39,6 +42,30 @@ using namespace elf; using namespace llvm::ELF; namespace { + +// ELF note owner definitions +const char *const LLDB_NT_OWNER_FREEBSD = "FreeBSD"; +const char *const LLDB_NT_OWNER_GNU = "GNU"; +const char *const LLDB_NT_OWNER_NETBSD = "NetBSD"; +const char *const LLDB_NT_OWNER_CSR = "csr"; + +// ELF note type definitions +const elf_word LLDB_NT_FREEBSD_ABI_TAG = 0x01; +const elf_word LLDB_NT_FREEBSD_ABI_SIZE = 4; + +const elf_word LLDB_NT_GNU_ABI_TAG = 0x01; +const elf_word LLDB_NT_GNU_ABI_SIZE = 16; + +const elf_word LLDB_NT_GNU_BUILD_ID_TAG = 0x03; + +const elf_word LLDB_NT_NETBSD_ABI_TAG = 0x01; +const elf_word LLDB_NT_NETBSD_ABI_SIZE = 4; + +// GNU ABI note OS constants +const elf_word LLDB_NT_GNU_ABI_OS_LINUX = 0x00; +const elf_word LLDB_NT_GNU_ABI_OS_HURD = 0x01; +const elf_word LLDB_NT_GNU_ABI_OS_SOLARIS = 0x02; + //===----------------------------------------------------------------------===// /// @class ELFRelocation /// @brief Generic wrapper for ELFRel and ELFRela. @@ -72,6 +99,18 @@ public: static unsigned RelocSymbol64(const ELFRelocation &rel); + static unsigned + RelocOffset32(const ELFRelocation &rel); + + static unsigned + RelocOffset64(const ELFRelocation &rel); + + static unsigned + RelocAddend32(const ELFRelocation &rel); + + static unsigned + RelocAddend64(const ELFRelocation &rel); + private: typedef llvm::PointerUnion<ELFRel*, ELFRela*> RelocUnion; @@ -80,9 +119,9 @@ private: ELFRelocation::ELFRelocation(unsigned type) { - if (type == DT_REL) + if (type == DT_REL || type == SHT_REL) reloc = new ELFRel(); - else if (type == DT_RELA) + else if (type == DT_RELA || type == SHT_RELA) reloc = new ELFRela(); else { assert(false && "unexpected relocation type"); @@ -143,6 +182,42 @@ ELFRelocation::RelocSymbol64(const ELFRelocation &rel) return ELFRela::RelocSymbol64(*rel.reloc.get<ELFRela*>()); } +unsigned +ELFRelocation::RelocOffset32(const ELFRelocation &rel) +{ + if (rel.reloc.is<ELFRel*>()) + return rel.reloc.get<ELFRel*>()->r_offset; + else + return rel.reloc.get<ELFRela*>()->r_offset; +} + +unsigned +ELFRelocation::RelocOffset64(const ELFRelocation &rel) +{ + if (rel.reloc.is<ELFRel*>()) + return rel.reloc.get<ELFRel*>()->r_offset; + else + return rel.reloc.get<ELFRela*>()->r_offset; +} + +unsigned +ELFRelocation::RelocAddend32(const ELFRelocation &rel) +{ + if (rel.reloc.is<ELFRel*>()) + return 0; + else + return rel.reloc.get<ELFRela*>()->r_addend; +} + +unsigned +ELFRelocation::RelocAddend64(const ELFRelocation &rel) +{ + if (rel.reloc.is<ELFRel*>()) + return 0; + else + return rel.reloc.get<ELFRela*>()->r_addend; +} + } // end anonymous namespace bool @@ -183,6 +258,39 @@ ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) return true; } +static uint32_t +kalimbaVariantFromElfFlags(const elf::elf_word e_flags) +{ + const uint32_t dsp_rev = e_flags & 0xFF; + uint32_t kal_arch_variant = LLDB_INVALID_CPUTYPE; + switch(dsp_rev) + { + // TODO(mg11) Support more variants + case 10: + kal_arch_variant = 3; + break; + case 14: + kal_arch_variant = 4; + break; + default: + break; + } + return kal_arch_variant; +} + +static uint32_t +subTypeFromElfHeader(const elf::ELFHeader& header) +{ + return + llvm::ELF::EM_CSR_KALIMBA == header.e_machine ? + kalimbaVariantFromElfFlags(header.e_flags) : + LLDB_INVALID_CPUTYPE; +} + +// Arbitrary constant used as UUID prefix for core files. +const uint32_t +ObjectFileELF::g_core_uuid_magic(0xE210C); + //------------------------------------------------------------------ // Static methods. //------------------------------------------------------------------ @@ -261,6 +369,22 @@ ObjectFileELF::CreateMemoryInstance (const lldb::ModuleSP &module_sp, const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT)) + { + const uint8_t *magic = data_sp->GetBytes(); + if (ELFHeader::MagicBytesMatch(magic)) + { + unsigned address_size = ELFHeader::AddressSizeInBytes(magic); + if (address_size == 4 || address_size == 8) + { + std::auto_ptr<ObjectFileELF> objfile_ap(new ObjectFileELF(module_sp, data_sp, process_sp, header_addr)); + ArchSpec spec; + if (objfile_ap->GetArchitecture(spec) && + objfile_ap->SetModulesArchitecture(spec)) + return objfile_ap.release(); + } + } + } return NULL; } @@ -284,7 +408,7 @@ ObjectFileELF::MagicBytesMatch (DataBufferSP& data_sp, * code or tables extracted from it, as desired without restriction. */ static uint32_t -calc_gnu_debuglink_crc32(const void *buf, size_t size) +calc_crc32(uint32_t crc, const void *buf, size_t size) { static const uint32_t g_crc32_tab[] = { @@ -333,14 +457,100 @@ calc_gnu_debuglink_crc32(const void *buf, size_t size) 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; const uint8_t *p = (const uint8_t *)buf; - uint32_t crc; - crc = ~0U; + crc = crc ^ ~0U; while (size--) crc = g_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); return crc ^ ~0U; } +static uint32_t +calc_gnu_debuglink_crc32(const void *buf, size_t size) +{ + return calc_crc32(0U, buf, size); +} + +uint32_t +ObjectFileELF::CalculateELFNotesSegmentsCRC32 (const ProgramHeaderColl& program_headers, + DataExtractor& object_data) +{ + typedef ProgramHeaderCollConstIter Iter; + + uint32_t core_notes_crc = 0; + + for (Iter I = program_headers.begin(); I != program_headers.end(); ++I) + { + if (I->p_type == llvm::ELF::PT_NOTE) + { + const elf_off ph_offset = I->p_offset; + const size_t ph_size = I->p_filesz; + + DataExtractor segment_data; + if (segment_data.SetData(object_data, ph_offset, ph_size) != ph_size) + { + // The ELF program header contained incorrect data, + // probably corefile is incomplete or corrupted. + break; + } + + core_notes_crc = calc_crc32(core_notes_crc, + segment_data.GetDataStart(), + segment_data.GetByteSize()); + } + } + + return core_notes_crc; +} + +static const char* +OSABIAsCString (unsigned char osabi_byte) +{ +#define _MAKE_OSABI_CASE(x) case x: return #x + switch (osabi_byte) + { + _MAKE_OSABI_CASE(ELFOSABI_NONE); + _MAKE_OSABI_CASE(ELFOSABI_HPUX); + _MAKE_OSABI_CASE(ELFOSABI_NETBSD); + _MAKE_OSABI_CASE(ELFOSABI_GNU); + _MAKE_OSABI_CASE(ELFOSABI_HURD); + _MAKE_OSABI_CASE(ELFOSABI_SOLARIS); + _MAKE_OSABI_CASE(ELFOSABI_AIX); + _MAKE_OSABI_CASE(ELFOSABI_IRIX); + _MAKE_OSABI_CASE(ELFOSABI_FREEBSD); + _MAKE_OSABI_CASE(ELFOSABI_TRU64); + _MAKE_OSABI_CASE(ELFOSABI_MODESTO); + _MAKE_OSABI_CASE(ELFOSABI_OPENBSD); + _MAKE_OSABI_CASE(ELFOSABI_OPENVMS); + _MAKE_OSABI_CASE(ELFOSABI_NSK); + _MAKE_OSABI_CASE(ELFOSABI_AROS); + _MAKE_OSABI_CASE(ELFOSABI_FENIXOS); + _MAKE_OSABI_CASE(ELFOSABI_C6000_ELFABI); + _MAKE_OSABI_CASE(ELFOSABI_C6000_LINUX); + _MAKE_OSABI_CASE(ELFOSABI_ARM); + _MAKE_OSABI_CASE(ELFOSABI_STANDALONE); + default: + return "<unknown-osabi>"; + } +#undef _MAKE_OSABI_CASE +} + +static bool +GetOsFromOSABI (unsigned char osabi_byte, llvm::Triple::OSType &ostype) +{ + switch (osabi_byte) + { + case ELFOSABI_AIX: ostype = llvm::Triple::OSType::AIX; break; + case ELFOSABI_FREEBSD: ostype = llvm::Triple::OSType::FreeBSD; break; + case ELFOSABI_GNU: ostype = llvm::Triple::OSType::Linux; break; + case ELFOSABI_NETBSD: ostype = llvm::Triple::OSType::NetBSD; break; + case ELFOSABI_OPENBSD: ostype = llvm::Triple::OSType::OpenBSD; break; + case ELFOSABI_SOLARIS: ostype = llvm::Triple::OSType::Solaris; break; + default: + ostype = llvm::Triple::OSType::UnknownOS; + } + return ostype != llvm::Triple::OSType::UnknownOS; +} + size_t ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file, lldb::DataBufferSP& data_sp, @@ -349,6 +559,8 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file, lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES)); + const size_t initial_count = specs.GetSize(); if (ObjectFileELF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) @@ -362,18 +574,30 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file, { ModuleSpec spec; spec.GetFileSpec() = file; + + const uint32_t sub_type = subTypeFromElfHeader(header); spec.GetArchitecture().SetArchitecture(eArchTypeELF, header.e_machine, - LLDB_INVALID_CPUTYPE); + sub_type); + if (spec.GetArchitecture().IsValid()) { - // We could parse the ABI tag information (in .note, .notes, or .note.ABI-tag) to get the - // machine information. However, this info isn't guaranteed to exist or be correct. Details: - // http://refspecs.linuxfoundation.org/LSB_1.2.0/gLSB/noteabitag.html - // Instead of passing potentially incorrect information down the pipeline, grab - // the host information and use it. - spec.GetArchitecture().GetTriple().setOSName (Host::GetOSString().GetCString()); - spec.GetArchitecture().GetTriple().setVendorName(Host::GetVendorString().GetCString()); + llvm::Triple::OSType ostype; + // First try to determine the OS type from the OSABI field in the elf header. + + if (log) + log->Printf ("ObjectFileELF::%s file '%s' module OSABI: %s", __FUNCTION__, file.GetPath ().c_str (), OSABIAsCString (header.e_ident[EI_OSABI])); + if (GetOsFromOSABI (header.e_ident[EI_OSABI], ostype) && ostype != llvm::Triple::OSType::UnknownOS) + { + spec.GetArchitecture ().GetTriple ().setOS (ostype); + + // Also clear the vendor so we don't end up with situations like + // x86_64-apple-FreeBSD. + spec.GetArchitecture ().GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor); + + if (log) + log->Printf ("ObjectFileELF::%s file '%s' set ELF module OS type from ELF header OSABI.", __FUNCTION__, file.GetPath ().c_str ()); + } // Try to get the UUID from the section list. Usually that's at the end, so // map the file in if we don't have it already. @@ -388,16 +612,68 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file, std::string gnu_debuglink_file; SectionHeaderColl section_headers; lldb_private::UUID &uuid = spec.GetUUID(); - GetSectionHeaderInfo(section_headers, data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc); + + GetSectionHeaderInfo(section_headers, data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc, spec.GetArchitecture ()); + + // If the module vendor is not set and the module OS matches this host OS, set the module vendor to the host vendor. + llvm::Triple &spec_triple = spec.GetArchitecture ().GetTriple (); + if (spec_triple.getVendor () == llvm::Triple::VendorType::UnknownVendor) + { + const llvm::Triple &host_triple = HostInfo::GetArchitecture().GetTriple(); + if (spec_triple.getOS () == host_triple.getOS ()) + spec_triple.setVendor (host_triple.getVendor ()); + } + + if (log) + log->Printf ("ObjectFileELF::%s file '%s' module set to triple: %s (architecture %s)", __FUNCTION__, file.GetPath ().c_str (), spec_triple.getTriple ().c_str (), spec.GetArchitecture ().GetArchitectureName ()); if (!uuid.IsValid()) { + uint32_t core_notes_crc = 0; + if (!gnu_debuglink_crc) { - // Need to map entire file into memory to calculate the crc. - data_sp = file.MemoryMapFileContents (file_offset, SIZE_MAX); - data.SetData(data_sp); - gnu_debuglink_crc = calc_gnu_debuglink_crc32 (data.GetDataStart(), data.GetByteSize()); + lldb_private::Timer scoped_timer (__PRETTY_FUNCTION__, + "Calculating module crc32 %s with size %" PRIu64 " KiB", + file.GetLastPathComponent().AsCString(), + (file.GetByteSize()-file_offset)/1024); + + // For core files - which usually don't happen to have a gnu_debuglink, + // and are pretty bulky - calculating whole contents crc32 would be too much of luxury. + // Thus we will need to fallback to something simpler. + if (header.e_type == llvm::ELF::ET_CORE) + { + size_t program_headers_end = header.e_phoff + header.e_phnum * header.e_phentsize; + if (program_headers_end > data_sp->GetByteSize()) + { + data_sp = file.MemoryMapFileContents(file_offset, program_headers_end); + data.SetData(data_sp); + } + ProgramHeaderColl program_headers; + GetProgramHeaderInfo(program_headers, data, header); + + size_t segment_data_end = 0; + for (ProgramHeaderCollConstIter I = program_headers.begin(); + I != program_headers.end(); ++I) + { + segment_data_end = std::max<unsigned long long> (I->p_offset + I->p_filesz, segment_data_end); + } + + if (segment_data_end > data_sp->GetByteSize()) + { + data_sp = file.MemoryMapFileContents(file_offset, segment_data_end); + data.SetData(data_sp); + } + + core_notes_crc = CalculateELFNotesSegmentsCRC32 (program_headers, data); + } + else + { + // Need to map entire file into memory to calculate the crc. + data_sp = file.MemoryMapFileContents (file_offset, SIZE_MAX); + data.SetData(data_sp); + gnu_debuglink_crc = calc_gnu_debuglink_crc32 (data.GetDataStart(), data.GetByteSize()); + } } if (gnu_debuglink_crc) { @@ -405,6 +681,13 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file, uint32_t uuidt[4] = { gnu_debuglink_crc, 0, 0, 0 }; uuid.SetBytes (uuidt, sizeof(uuidt)); } + else if (core_notes_crc) + { + // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it look different form + // .gnu_debuglink crc followed by 4 bytes of note segments crc. + uint32_t uuidt[4] = { g_core_uuid_magic, core_notes_crc, 0, 0 }; + uuid.SetBytes (uuidt, sizeof(uuidt)); + } } specs.Append(spec); @@ -442,15 +725,38 @@ ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp, lldb::offset_t length) : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), m_header(), + m_uuid(), + m_gnu_debuglink_file(), + m_gnu_debuglink_crc(0), m_program_headers(), m_section_headers(), - m_filespec_ap() + m_dynamic_symbols(), + m_filespec_ap(), + m_entry_point_address(), + m_arch_spec() { if (file) m_file = *file; ::memset(&m_header, 0, sizeof(m_header)); - m_gnu_debuglink_crc = 0; - m_gnu_debuglink_file.clear(); +} + +ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp, + DataBufferSP& data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) : + ObjectFile(module_sp, process_sp, LLDB_INVALID_ADDRESS, data_sp), + m_header(), + m_uuid(), + m_gnu_debuglink_file(), + m_gnu_debuglink_crc(0), + m_program_headers(), + m_section_headers(), + m_dynamic_symbols(), + m_filespec_ap(), + m_entry_point_address(), + m_arch_spec() +{ + ::memset(&m_header, 0, sizeof(m_header)); } ObjectFileELF::~ObjectFileELF() @@ -460,7 +766,7 @@ ObjectFileELF::~ObjectFileELF() bool ObjectFileELF::IsExecutable() const { - return m_header.e_entry != 0; + return ((m_header.e_type & ET_EXEC) != 0) || (m_header.e_entry != 0); } bool @@ -543,7 +849,7 @@ bool ObjectFileELF::GetUUID(lldb_private::UUID* uuid) { // Need to parse the section list to get the UUIDs, so make sure that's been done. - if (!ParseSectionHeaders()) + if (!ParseSectionHeaders() && GetType() != ObjectFile::eTypeCoreFile) return false; if (m_uuid.IsValid()) @@ -552,7 +858,25 @@ ObjectFileELF::GetUUID(lldb_private::UUID* uuid) *uuid = m_uuid; return true; } - else + else if (GetType() == ObjectFile::eTypeCoreFile) + { + uint32_t core_notes_crc = 0; + + if (!ParseProgramHeaders()) + return false; + + core_notes_crc = CalculateELFNotesSegmentsCRC32(m_program_headers, m_data); + + if (core_notes_crc) + { + // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it + // look different form .gnu_debuglink crc - followed by 4 bytes of note + // segments crc. + uint32_t uuidt[4] = { g_core_uuid_magic, core_notes_crc, 0, 0 }; + m_uuid.SetBytes (uuidt, sizeof(uuidt)); + } + } + else { if (!m_gnu_debuglink_crc) m_gnu_debuglink_crc = calc_gnu_debuglink_crc32 (m_data.GetDataStart(), m_data.GetByteSize()); @@ -560,11 +884,16 @@ ObjectFileELF::GetUUID(lldb_private::UUID* uuid) { // Use 4 bytes of crc from the .gnu_debuglink section. uint32_t uuidt[4] = { m_gnu_debuglink_crc, 0, 0, 0 }; - uuid->SetBytes (uuidt, sizeof(uuidt)); - return true; + m_uuid.SetBytes (uuidt, sizeof(uuidt)); } } + if (m_uuid.IsValid()) + { + *uuid = m_uuid; + return true; + } + return false; } @@ -724,72 +1053,235 @@ ObjectFileELF::ParseDependentModules() } //---------------------------------------------------------------------- -// ParseProgramHeaders +// GetProgramHeaderInfo //---------------------------------------------------------------------- size_t -ObjectFileELF::ParseProgramHeaders() +ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, + DataExtractor &object_data, + const ELFHeader &header) { // We have already parsed the program headers - if (!m_program_headers.empty()) - return m_program_headers.size(); + if (!program_headers.empty()) + return program_headers.size(); // If there are no program headers to read we are done. - if (m_header.e_phnum == 0) + if (header.e_phnum == 0) return 0; - m_program_headers.resize(m_header.e_phnum); - if (m_program_headers.size() != m_header.e_phnum) + program_headers.resize(header.e_phnum); + if (program_headers.size() != header.e_phnum) return 0; - const size_t ph_size = m_header.e_phnum * m_header.e_phentsize; - const elf_off ph_offset = m_header.e_phoff; + const size_t ph_size = header.e_phnum * header.e_phentsize; + const elf_off ph_offset = header.e_phoff; DataExtractor data; - if (GetData (ph_offset, ph_size, data) != ph_size) + if (data.SetData(object_data, ph_offset, ph_size) != ph_size) return 0; uint32_t idx; lldb::offset_t offset; - for (idx = 0, offset = 0; idx < m_header.e_phnum; ++idx) + for (idx = 0, offset = 0; idx < header.e_phnum; ++idx) { - if (m_program_headers[idx].Parse(data, &offset) == false) + if (program_headers[idx].Parse(data, &offset) == false) break; } - if (idx < m_program_headers.size()) - m_program_headers.resize(idx); + if (idx < program_headers.size()) + program_headers.resize(idx); + + return program_headers.size(); - return m_program_headers.size(); } -static bool -ParseNoteGNUBuildID(DataExtractor &data, lldb_private::UUID &uuid) +//---------------------------------------------------------------------- +// ParseProgramHeaders +//---------------------------------------------------------------------- +size_t +ObjectFileELF::ParseProgramHeaders() +{ + return GetProgramHeaderInfo(m_program_headers, m_data, m_header); +} + +lldb_private::Error +ObjectFileELF::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch_spec, lldb_private::UUID &uuid) { - // Try to parse the note section (ie .note.gnu.build-id|.notes|.note|...) and get the build id. - // BuildID documentation: https://fedoraproject.org/wiki/Releases/FeatureBuildId + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES)); + Error error; + lldb::offset_t offset = 0; - static const uint32_t g_gnu_build_id = 3; // NT_GNU_BUILD_ID from elf.h while (true) { + // Parse the note header. If this fails, bail out. ELFNote note = ELFNote(); if (!note.Parse(data, &offset)) - return false; + { + // We're done. + return error; + } + + // If a tag processor handles the tag, it should set processed to true, and + // the loop will assume the tag processing has moved entirely past the note's payload. + // Otherwise, leave it false and the end of the loop will handle the offset properly. + bool processed = false; - // 16 bytes is UUID|MD5, 20 bytes is SHA1 - if (note.n_name == "GNU" && (note.n_type == g_gnu_build_id) && - (note.n_descsz == 16 || note.n_descsz == 20)) + if (log) + log->Printf ("ObjectFileELF::%s parsing note name='%s', type=%" PRIu32, __FUNCTION__, note.n_name.c_str (), note.n_type); + + // Process FreeBSD ELF notes. + if ((note.n_name == LLDB_NT_OWNER_FREEBSD) && + (note.n_type == LLDB_NT_FREEBSD_ABI_TAG) && + (note.n_descsz == LLDB_NT_FREEBSD_ABI_SIZE)) { - uint8_t uuidbuf[20]; - if (data.GetU8 (&offset, &uuidbuf, note.n_descsz) == NULL) - return false; - uuid.SetBytes (uuidbuf, note.n_descsz); - return true; + // We'll consume the payload below. + processed = true; + + // Pull out the min version info. + uint32_t version_info; + if (data.GetU32 (&offset, &version_info, 1) == nullptr) + { + error.SetErrorString ("failed to read FreeBSD ABI note payload"); + return error; + } + + // Convert the version info into a major/minor number. + const uint32_t version_major = version_info / 100000; + const uint32_t version_minor = (version_info / 1000) % 100; + + char os_name[32]; + snprintf (os_name, sizeof (os_name), "freebsd%" PRIu32 ".%" PRIu32, version_major, version_minor); + + // Set the elf OS version to FreeBSD. Also clear the vendor. + arch_spec.GetTriple ().setOSName (os_name); + arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor); + + if (log) + log->Printf ("ObjectFileELF::%s detected FreeBSD %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_major, version_minor, static_cast<uint32_t> (version_info % 1000)); + } + // Process GNU ELF notes. + else if (note.n_name == LLDB_NT_OWNER_GNU) + { + switch (note.n_type) + { + case LLDB_NT_GNU_ABI_TAG: + if (note.n_descsz == LLDB_NT_GNU_ABI_SIZE) + { + // We'll consume the payload below. + processed = true; + + // Pull out the min OS version supporting the ABI. + uint32_t version_info[4]; + if (data.GetU32 (&offset, &version_info[0], note.n_descsz / 4) == nullptr) + { + error.SetErrorString ("failed to read GNU ABI note payload"); + return error; + } + + // Set the OS per the OS field. + switch (version_info[0]) + { + case LLDB_NT_GNU_ABI_OS_LINUX: + arch_spec.GetTriple ().setOS (llvm::Triple::OSType::Linux); + arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor); + if (log) + log->Printf ("ObjectFileELF::%s detected Linux, min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]); + // FIXME we have the minimal version number, we could be propagating that. version_info[1] = OS Major, version_info[2] = OS Minor, version_info[3] = Revision. + break; + case LLDB_NT_GNU_ABI_OS_HURD: + arch_spec.GetTriple ().setOS (llvm::Triple::OSType::UnknownOS); + arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor); + if (log) + log->Printf ("ObjectFileELF::%s detected Hurd (unsupported), min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]); + break; + case LLDB_NT_GNU_ABI_OS_SOLARIS: + arch_spec.GetTriple ().setOS (llvm::Triple::OSType::Solaris); + arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor); + if (log) + log->Printf ("ObjectFileELF::%s detected Solaris, min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]); + break; + default: + if (log) + log->Printf ("ObjectFileELF::%s unrecognized OS in note, id %" PRIu32 ", min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[0], version_info[1], version_info[2], version_info[3]); + break; + } + } + break; + + case LLDB_NT_GNU_BUILD_ID_TAG: + // Only bother processing this if we don't already have the uuid set. + if (!uuid.IsValid()) + { + // We'll consume the payload below. + processed = true; + + // 16 bytes is UUID|MD5, 20 bytes is SHA1 + if ((note.n_descsz == 16 || note.n_descsz == 20)) + { + uint8_t uuidbuf[20]; + if (data.GetU8 (&offset, &uuidbuf, note.n_descsz) == nullptr) + { + error.SetErrorString ("failed to read GNU_BUILD_ID note payload"); + return error; + } + + // Save the build id as the UUID for the module. + uuid.SetBytes (uuidbuf, note.n_descsz); + } + } + break; + } } - offset += llvm::RoundUpToAlignment(note.n_descsz, 4); + // Process NetBSD ELF notes. + else if ((note.n_name == LLDB_NT_OWNER_NETBSD) && + (note.n_type == LLDB_NT_NETBSD_ABI_TAG) && + (note.n_descsz == LLDB_NT_NETBSD_ABI_SIZE)) + { + + // We'll consume the payload below. + processed = true; + + // Pull out the min version info. + uint32_t version_info; + if (data.GetU32 (&offset, &version_info, 1) == nullptr) + { + error.SetErrorString ("failed to read NetBSD ABI note payload"); + return error; + } + + // Set the elf OS version to NetBSD. Also clear the vendor. + arch_spec.GetTriple ().setOS (llvm::Triple::OSType::NetBSD); + arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor); + + if (log) + log->Printf ("ObjectFileELF::%s detected NetBSD, min version constant %" PRIu32, __FUNCTION__, version_info); + } + // Process CSR kalimba notes + else if ((note.n_type == LLDB_NT_GNU_ABI_TAG) && + (note.n_name == LLDB_NT_OWNER_CSR)) + { + // We'll consume the payload below. + processed = true; + arch_spec.GetTriple().setOS(llvm::Triple::OSType::UnknownOS); + arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::CSR); + + // TODO At some point the description string could be processed. + // It could provide a steer towards the kalimba variant which + // this ELF targets. + if(note.n_descsz) + { + const char *cstr = data.GetCStr(&offset, llvm::RoundUpToAlignment (note.n_descsz, 4)); + (void)cstr; + } + } + + if (!processed) + offset += llvm::RoundUpToAlignment(note.n_descsz, 4); } - return false; + + return error; } + //---------------------------------------------------------------------- // GetSectionHeaderInfo //---------------------------------------------------------------------- @@ -799,16 +1291,51 @@ ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, const elf::ELFHeader &header, lldb_private::UUID &uuid, std::string &gnu_debuglink_file, - uint32_t &gnu_debuglink_crc) + uint32_t &gnu_debuglink_crc, + ArchSpec &arch_spec) { - // We have already parsed the section headers + // Don't reparse the section headers if we already did that. if (!section_headers.empty()) return section_headers.size(); + // Only initialize the arch_spec to okay defaults if they're not already set. + // We'll refine this with note data as we parse the notes. + if (arch_spec.GetTriple ().getOS () == llvm::Triple::OSType::UnknownOS) + { + const uint32_t sub_type = subTypeFromElfHeader(header); + arch_spec.SetArchitecture (eArchTypeELF, header.e_machine, sub_type); + + switch (arch_spec.GetAddressByteSize()) + { + case 4: + { + const ArchSpec host_arch32 = HostInfo::GetArchitecture(HostInfo::eArchKind32); + if (host_arch32.GetCore() == arch_spec.GetCore()) + { + arch_spec.GetTriple().setOSName(HostInfo::GetOSString().data()); + arch_spec.GetTriple().setVendorName(HostInfo::GetVendorString().data()); + } + } + break; + case 8: + { + const ArchSpec host_arch64 = HostInfo::GetArchitecture(HostInfo::eArchKind64); + if (host_arch64.GetCore() == arch_spec.GetCore()) + { + arch_spec.GetTriple().setOSName(HostInfo::GetOSString().data()); + arch_spec.GetTriple().setVendorName(HostInfo::GetVendorString().data()); + } + } + break; + } + } + // If there are no section headers we are done. if (header.e_shnum == 0) return 0; + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES)); + section_headers.resize(header.e_shnum); if (section_headers.size() != header.e_shnum) return 0; @@ -861,12 +1388,19 @@ ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, } } - if (header.sh_type == SHT_NOTE && !uuid.IsValid()) + // Process ELF note section entries. + if (header.sh_type == SHT_NOTE) { + // Allow notes to refine module info. DataExtractor data; if (section_size && (data.SetData (object_data, header.sh_offset, section_size) == section_size)) { - ParseNoteGNUBuildID (data, uuid); + Error error = RefineModuleDetailsFromNote (data, arch_spec, uuid); + if (error.Fail ()) + { + if (log) + log->Printf ("ObjectFileELF::%s ELF note processing failed: %s", __FUNCTION__, error.AsCString ()); + } } } } @@ -912,7 +1446,7 @@ ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id) size_t ObjectFileELF::ParseSectionHeaders() { - return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc); + return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc, m_arch_spec); } const ObjectFileELF::ELFSectionHeaderInfo * @@ -1026,6 +1560,9 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list) break; } + elf::elf_xword log2align = (header.sh_addralign==0) + ? 0 + : llvm::Log2_64(header.sh_addralign); SectionSP section_sp (new Section(GetModule(), // Module to which this section belongs. this, // ObjectFile to which this section belongs and should read section data from. SectionIndex(I), // Section ID. @@ -1035,6 +1572,7 @@ ObjectFileELF::CreateSections(SectionList &unified_section_list) vm_size, // VM size in bytes of this section. 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. if (is_thread_specific) @@ -1117,8 +1655,9 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, const char *symbol_name = strtab_data.PeekCStr(symbol.st_name); - // No need to add symbols that have no names - if (symbol_name == NULL || symbol_name[0] == '\0') + // No need to add non-section symbols that have no names + if (symbol.getType() != STT_SECTION && + (symbol_name == NULL || symbol_name[0] == '\0')) continue; //symbol.Dump (&strm, i, &strtab_data, section_list); @@ -1228,7 +1767,7 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, } uint64_t symbol_value = symbol.st_value; - if (symbol_section_sp) + 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; @@ -1279,7 +1818,6 @@ ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, user_id_t start_id, lldb_p user_id_t strtab_id = symtab_hdr->sh_link + 1; Section *strtab = section_list->FindSectionByID(strtab_id).get(); - unsigned num_symbols = 0; if (symtab && strtab) { assert (symtab->GetObjectFile() == this); @@ -1292,13 +1830,12 @@ ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, user_id_t start_id, lldb_p { size_t num_symbols = symtab_data.GetByteSize() / symtab_hdr->sh_entsize; - num_symbols = ParseSymbols(symbol_table, start_id, - section_list, num_symbols, - symtab_data, strtab_data); + return ParseSymbols(symbol_table, start_id, section_list, + num_symbols, symtab_data, strtab_data); } } - return num_symbols; + return 0; } size_t @@ -1526,6 +2063,136 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, strtab_data); } +unsigned +ObjectFileELF::RelocateSection(Symtab* symtab, const ELFHeader *hdr, const ELFSectionHeader *rel_hdr, + const ELFSectionHeader *symtab_hdr, const ELFSectionHeader *debug_hdr, + DataExtractor &rel_data, DataExtractor &symtab_data, + DataExtractor &debug_data, Section* rel_section) +{ + ELFRelocation rel(rel_hdr->sh_type); + lldb::addr_t offset = 0; + const unsigned num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize; + typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel); + reloc_info_fn reloc_type; + reloc_info_fn reloc_symbol; + + if (hdr->Is32Bit()) + { + reloc_type = ELFRelocation::RelocType32; + reloc_symbol = ELFRelocation::RelocSymbol32; + } + else + { + reloc_type = ELFRelocation::RelocType64; + reloc_symbol = ELFRelocation::RelocSymbol64; + } + + for (unsigned i = 0; i < num_relocations; ++i) + { + if (rel.Parse(rel_data, &offset) == false) + break; + + Symbol* symbol = NULL; + + if (hdr->Is32Bit()) + { + switch (reloc_type(rel)) { + case R_386_32: + case R_386_PC32: + default: + assert(false && "unexpected relocation type"); + } + } else { + switch (reloc_type(rel)) { + case R_X86_64_64: + { + symbol = symtab->FindSymbolByID(reloc_symbol(rel)); + if (symbol) + { + addr_t value = symbol->GetAddress().GetFileAddress(); + DataBufferSP& data_buffer_sp = debug_data.GetSharedDataBuffer(); + uint64_t* dst = reinterpret_cast<uint64_t*>(data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset64(rel)); + *dst = value + ELFRelocation::RelocAddend64(rel); + } + break; + } + case R_X86_64_32: + case R_X86_64_32S: + { + symbol = symtab->FindSymbolByID(reloc_symbol(rel)); + if (symbol) + { + addr_t value = symbol->GetAddress().GetFileAddress(); + value += ELFRelocation::RelocAddend32(rel); + assert((reloc_type(rel) == R_X86_64_32 && (value <= UINT32_MAX)) || + (reloc_type(rel) == R_X86_64_32S && + ((int64_t)value <= INT32_MAX && (int64_t)value >= INT32_MIN))); + uint32_t truncated_addr = (value & 0xFFFFFFFF); + DataBufferSP& data_buffer_sp = debug_data.GetSharedDataBuffer(); + uint32_t* dst = reinterpret_cast<uint32_t*>(data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset32(rel)); + *dst = truncated_addr; + } + break; + } + case R_X86_64_PC32: + default: + assert(false && "unexpected relocation type"); + } + } + } + + return 0; +} + +unsigned +ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, user_id_t rel_id) +{ + assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL); + + // Parse in the section list if needed. + SectionList *section_list = GetSectionList(); + if (!section_list) + return 0; + + // Section ID's are ones based. + user_id_t symtab_id = rel_hdr->sh_link + 1; + user_id_t debug_id = rel_hdr->sh_info + 1; + + const ELFSectionHeader *symtab_hdr = GetSectionHeaderByIndex(symtab_id); + if (!symtab_hdr) + return 0; + + const ELFSectionHeader *debug_hdr = GetSectionHeaderByIndex(debug_id); + if (!debug_hdr) + return 0; + + Section *rel = section_list->FindSectionByID(rel_id).get(); + if (!rel) + return 0; + + Section *symtab = section_list->FindSectionByID(symtab_id).get(); + if (!symtab) + return 0; + + Section *debug = section_list->FindSectionByID(debug_id).get(); + if (!debug) + return 0; + + DataExtractor rel_data; + DataExtractor symtab_data; + DataExtractor debug_data; + + if (ReadSectionData(rel, rel_data) && + ReadSectionData(symtab, symtab_data) && + ReadSectionData(debug, debug_data)) + { + RelocateSection(m_symtab_ap.get(), &m_header, rel_hdr, symtab_hdr, debug_hdr, + rel_data, symtab_data, debug_data, debug); + } + + return 0; +} + Symtab * ObjectFileELF::GetSymtab() { @@ -1588,6 +2255,25 @@ ObjectFileELF::GetSymtab() } } } + + for (SectionHeaderCollIter I = m_section_headers.begin(); + I != m_section_headers.end(); ++I) + { + if (I->sh_type == SHT_RELA || I->sh_type == SHT_REL) + { + if (CalculateType() == eTypeObjectFile) + { + const char *section_name = I->section_name.AsCString(""); + if (strstr(section_name, ".rela.debug") || + strstr(section_name, ".rel.debug")) + { + const ELFSectionHeader &reloc_header = *I; + user_id_t reloc_id = SectionIndex(I); + RelocateDebugSections(&reloc_header, reloc_id); + } + } + } + } return m_symtab_ap.get(); } @@ -1958,9 +2644,13 @@ ObjectFileELF::GetArchitecture (ArchSpec &arch) if (!ParseHeader()) return false; - arch.SetArchitecture (eArchTypeELF, m_header.e_machine, LLDB_INVALID_CPUTYPE); - arch.GetTriple().setOSName (Host::GetOSString().GetCString()); - arch.GetTriple().setVendorName(Host::GetVendorString().GetCString()); + if (m_section_headers.empty()) + { + // Allow elf notes to be parsed which may affect the detected architecture. + ParseSectionHeaders(); + } + + arch = m_arch_spec; return true; } diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 9b7c073d902d..6b036af7aeff 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -17,6 +17,7 @@ #include "lldb/Host/FileSpec.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Core/UUID.h" +#include "lldb/Core/ArchSpec.h" #include "ELFHeader.h" @@ -191,6 +192,11 @@ private: lldb::offset_t offset, lldb::offset_t length); + ObjectFileELF (const lldb::ModuleSP &module_sp, + lldb::DataBufferSP& data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr); + typedef std::vector<elf::ELFProgramHeader> ProgramHeaderColl; typedef ProgramHeaderColl::iterator ProgramHeaderCollIter; typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter; @@ -209,6 +215,7 @@ private: /// Version of this reader common to all plugins based on this class. static const uint32_t m_plugin_version = 1; + static const uint32_t g_core_uuid_magic; /// ELF file header. elf::ELFHeader m_header; @@ -236,6 +243,9 @@ private: /// Cached value of the entry point for this module. lldb_private::Address m_entry_point_address; + /// The architecture detected from parsing elf file contents. + lldb_private::ArchSpec m_arch_spec; + /// Returns a 1 based index of the given section header. size_t SectionIndex(const SectionHeaderCollIter &I); @@ -244,6 +254,17 @@ private: size_t SectionIndex(const SectionHeaderCollConstIter &I) const; + // Parses the ELF program headers. + static size_t + GetProgramHeaderInfo(ProgramHeaderColl &program_headers, + lldb_private::DataExtractor &data, + const elf::ELFHeader &header); + + // Finds PT_NOTE segments and calculates their crc sum. + static uint32_t + CalculateELFNotesSegmentsCRC32(const ProgramHeaderColl& program_headers, + lldb_private::DataExtractor &data); + /// Parses all section headers present in this object file and populates /// m_program_headers. This method will compute the header list only once. /// Returns the number of headers parsed. @@ -256,14 +277,15 @@ private: size_t ParseSectionHeaders(); - /// Parses the elf section headers and returns the uuid, debug link name, crc. + /// Parses the elf section headers and returns the uuid, debug link name, crc, archspec. static size_t GetSectionHeaderInfo(SectionHeaderColl §ion_headers, lldb_private::DataExtractor &data, const elf::ELFHeader &header, lldb_private::UUID &uuid, std::string &gnu_debuglink_file, - uint32_t &gnu_debuglink_crc); + uint32_t &gnu_debuglink_crc, + lldb_private::ArchSpec &arch_spec); /// Scans the dynamic section and locates all dependent modules (shared /// libraries) populating m_filespec_ap. This method will compute the @@ -303,6 +325,32 @@ private: const ELFSectionHeaderInfo *rela_hdr, lldb::user_id_t section_id); + /// Relocates debug sections + unsigned + RelocateDebugSections(const elf::ELFSectionHeader *rel_hdr, lldb::user_id_t rel_id); + + unsigned + RelocateSection(lldb_private::Symtab* symtab, const elf::ELFHeader *hdr, const elf::ELFSectionHeader *rel_hdr, + const elf::ELFSectionHeader *symtab_hdr, const elf::ELFSectionHeader *debug_hdr, + lldb_private::DataExtractor &rel_data, lldb_private::DataExtractor &symtab_data, + lldb_private::DataExtractor &debug_data, lldb_private::Section* rel_section); + + /// Loads the section name string table into m_shstr_data. Returns the + /// number of bytes constituting the table. + size_t + GetSectionHeaderStringTable(); + + /// Utility method for looking up a section given its name. Returns the + /// index of the corresponding section or zero if no section with the given + /// name can be found (note that section indices are always 1 based, and so + /// section index 0 is never valid). + lldb::user_id_t + GetSectionIndexByName(const char *name); + + // Returns the ID of the first section that has the given type. + lldb::user_id_t + GetSectionIndexByType(unsigned type); + /// Returns the section header with the given id or NULL. const ELFSectionHeaderInfo * GetSectionHeaderByIndex(lldb::user_id_t id); @@ -364,6 +412,9 @@ private: unsigned PLTRelocationType(); + + static lldb_private::Error + RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch_spec, lldb_private::UUID &uuid); }; #endif // #ifndef liblldb_ObjectFileELF_h_ diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp new file mode 100644 index 000000000000..5498bed13ebc --- /dev/null +++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp @@ -0,0 +1,363 @@ +//===-- ObjectFileJIT.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" + +#include "ObjectFileJIT.h" + +#include "lldb/lldb-private-log.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/DataBuffer.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/FileSpecList.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RangeMap.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/Timer.h" +#include "lldb/Core/UUID.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Target.h" + +#ifndef __APPLE__ +#include "Utility/UuidCompatibility.h" +#endif + +using namespace lldb; +using namespace lldb_private; + + +void +ObjectFileJIT::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance, + CreateMemoryInstance, + GetModuleSpecifications); +} + +void +ObjectFileJIT::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + + +lldb_private::ConstString +ObjectFileJIT::GetPluginNameStatic() +{ + static ConstString g_name("jit"); + return g_name; +} + +const char * +ObjectFileJIT::GetPluginDescriptionStatic() +{ + return "JIT code object file"; +} + +ObjectFile * +ObjectFileJIT::CreateInstance (const lldb::ModuleSP &module_sp, + DataBufferSP& data_sp, + lldb::offset_t data_offset, + const FileSpec* file, + lldb::offset_t file_offset, + lldb::offset_t length) +{ + // JIT'ed object file is backed by the ObjectFileJITDelegate, never + // read from a file + return NULL; +} + +ObjectFile * +ObjectFileJIT::CreateMemoryInstance (const lldb::ModuleSP &module_sp, + DataBufferSP& data_sp, + const ProcessSP &process_sp, + lldb::addr_t header_addr) +{ + // JIT'ed object file is backed by the ObjectFileJITDelegate, never + // read from memory + return NULL; +} + +size_t +ObjectFileJIT::GetModuleSpecifications (const lldb_private::FileSpec& file, + lldb::DataBufferSP& data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs) +{ + // JIT'ed object file can't be read from a file on disk + return 0; +} + +ObjectFileJIT::ObjectFileJIT (const lldb::ModuleSP &module_sp, + const ObjectFileJITDelegateSP &delegate_sp) : + ObjectFile(module_sp, NULL, 0, 0, DataBufferSP(), 0), + m_delegate_wp () +{ + if (delegate_sp) + { + m_delegate_wp = delegate_sp; + m_data.SetByteOrder(delegate_sp->GetByteOrder()); + m_data.SetAddressByteSize(delegate_sp->GetAddressByteSize()); + } +} + +ObjectFileJIT::~ObjectFileJIT() +{ +} + + +bool +ObjectFileJIT::ParseHeader () +{ + // JIT code is never in a file, nor is it required to have any header + return false; +} + +ByteOrder +ObjectFileJIT::GetByteOrder () const +{ + return m_data.GetByteOrder(); +} + +bool +ObjectFileJIT::IsExecutable() const +{ + return false; +} + +uint32_t +ObjectFileJIT::GetAddressByteSize () const +{ + return m_data.GetAddressByteSize(); +} + + +Symtab * +ObjectFileJIT::GetSymtab() +{ + ModuleSP module_sp(GetModule()); + if (module_sp) + { + lldb_private::Mutex::Locker locker(module_sp->GetMutex()); + if (m_symtab_ap.get() == NULL) + { + m_symtab_ap.reset(new Symtab(this)); + Mutex::Locker symtab_locker (m_symtab_ap->GetMutex()); + ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock()); + if (delegate_sp) + delegate_sp->PopulateSymtab(this, *m_symtab_ap); + // TODO: get symbols from delegate + m_symtab_ap->Finalize (); + } + } + return m_symtab_ap.get(); +} + +bool +ObjectFileJIT::IsStripped () +{ + return false; // JIT code that is in a module is never stripped +} + +void +ObjectFileJIT::CreateSections (SectionList &unified_section_list) +{ + if (!m_sections_ap.get()) + { + m_sections_ap.reset(new SectionList()); + ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock()); + if (delegate_sp) + { + delegate_sp->PopulateSectionList(this, *m_sections_ap); + unified_section_list = *m_sections_ap; + } + } +} + +void +ObjectFileJIT::Dump (Stream *s) +{ + ModuleSP module_sp(GetModule()); + if (module_sp) + { + lldb_private::Mutex::Locker locker(module_sp->GetMutex()); + s->Printf("%p: ", static_cast<void*>(this)); + s->Indent(); + s->PutCString("ObjectFileJIT"); + + ArchSpec arch; + if (GetArchitecture(arch)) + *s << ", arch = " << arch.GetArchitectureName(); + + s->EOL(); + + SectionList *sections = GetSectionList(); + if (sections) + sections->Dump(s, NULL, true, UINT32_MAX); + + if (m_symtab_ap.get()) + m_symtab_ap->Dump(s, NULL, eSortOrderNone); + } +} + +bool +ObjectFileJIT::GetUUID (lldb_private::UUID* uuid) +{ + // TODO: maybe get from delegate, not needed for first pass + return false; +} + + +uint32_t +ObjectFileJIT::GetDependentModules (FileSpecList& files) +{ + // JIT modules don't have dependencies, but they could + // if external functions are called and we know where they are + files.Clear(); + return 0; +} + +lldb_private::Address +ObjectFileJIT::GetEntryPointAddress () +{ + return Address(); +} + +lldb_private::Address +ObjectFileJIT::GetHeaderAddress () +{ + return Address(); +} + + + +ObjectFile::Type +ObjectFileJIT::CalculateType() +{ + return eTypeJIT; +} + +ObjectFile::Strata +ObjectFileJIT::CalculateStrata() +{ + return eStrataJIT; +} + + +bool +ObjectFileJIT::GetArchitecture (ArchSpec &arch) +{ + ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock()); + if (delegate_sp) + return delegate_sp->GetArchitecture(arch); + return false; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +ObjectFileJIT::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +ObjectFileJIT::GetPluginVersion() +{ + return 1; +} + + +bool +ObjectFileJIT::SetLoadAddress (Target &target, + lldb::addr_t value, + bool value_is_offset) +{ + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList (); + if (section_list) + { + const size_t num_sections = section_list->GetSize(); + // "value" is an offset to apply to each top level segment + for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) + { + // Iterate through the object file sections to find all + // of the sections that size on disk (to avoid __PAGEZERO) + // and load them + SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx)); + if (section_sp && + section_sp->GetFileSize() > 0 && + section_sp->IsThreadSpecific() == false) + { + if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } + return num_loaded_sections > 0; +} + + +size_t +ObjectFileJIT::ReadSectionData (const lldb_private::Section *section, + lldb::offset_t section_offset, + void *dst, + size_t dst_len) const +{ + lldb::offset_t file_size = section->GetFileSize(); + if (section_offset < file_size) + { + size_t src_len = file_size - section_offset; + if (src_len > dst_len) + src_len = dst_len; + const uint8_t *src = ((uint8_t *)(uintptr_t)section->GetFileOffset()) + section_offset; + + memcpy (dst, src, src_len); + return src_len; + } + return 0; +} + +size_t +ObjectFileJIT::ReadSectionData (const lldb_private::Section *section, + lldb_private::DataExtractor& section_data) const +{ + if (section->GetFileSize()) + { + const void *src = (void *)(uintptr_t)section->GetFileOffset(); + + DataBufferSP data_sp (new lldb_private::DataBufferHeap(src, section->GetFileSize())); + if (data_sp) + { + section_data.SetData (data_sp, 0, data_sp->GetByteSize()); + section_data.SetByteOrder (GetByteOrder()); + section_data.SetAddressByteSize (GetAddressByteSize()); + return section_data.GetByteSize(); + } + } + section_data.Clear(); + return 0; +} + diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h new file mode 100644 index 000000000000..47140f5bcaff --- /dev/null +++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h @@ -0,0 +1,142 @@ +//===-- ObjectFileJIT.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_ObjectFileJIT_h_ +#define liblldb_ObjectFileJIT_h_ + +#include "lldb/Core/Address.h" +#include "lldb/Symbol/ObjectFile.h" + + +//---------------------------------------------------------------------- +// This class needs to be hidden as eventually belongs in a plugin that +// will export the ObjectFile protocol +//---------------------------------------------------------------------- +class ObjectFileJIT : + public lldb_private::ObjectFile +{ +public: + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb_private::ObjectFile * + CreateInstance (const lldb::ModuleSP &module_sp, + lldb::DataBufferSP& data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec* file, + lldb::offset_t file_offset, + lldb::offset_t length); + + static lldb_private::ObjectFile * + CreateMemoryInstance (const lldb::ModuleSP &module_sp, + lldb::DataBufferSP& data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr); + + static size_t + GetModuleSpecifications (const lldb_private::FileSpec& file, + lldb::DataBufferSP& data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + //------------------------------------------------------------------ + // Member Functions + //------------------------------------------------------------------ + ObjectFileJIT (const lldb::ModuleSP &module_sp, + const lldb::ObjectFileJITDelegateSP &delegate_sp); + + virtual + ~ObjectFileJIT(); + + virtual bool + ParseHeader (); + + virtual bool + SetLoadAddress(lldb_private::Target &target, + lldb::addr_t value, + bool value_is_offset); + + virtual lldb::ByteOrder + GetByteOrder () const; + + virtual bool + IsExecutable () const; + + virtual uint32_t + GetAddressByteSize () const; + + virtual lldb_private::Symtab * + GetSymtab(); + + virtual bool + IsStripped (); + + virtual void + CreateSections (lldb_private::SectionList &unified_section_list); + + virtual void + Dump (lldb_private::Stream *s); + + virtual bool + GetArchitecture (lldb_private::ArchSpec &arch); + + virtual bool + GetUUID (lldb_private::UUID* uuid); + + virtual uint32_t + GetDependentModules (lldb_private::FileSpecList& files); + + virtual size_t + ReadSectionData (const lldb_private::Section *section, + lldb::offset_t section_offset, + void *dst, + size_t dst_len) const; + virtual size_t + ReadSectionData (const lldb_private::Section *section, + lldb_private::DataExtractor& section_data) const; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + + virtual lldb_private::Address + GetEntryPointAddress (); + + virtual lldb_private::Address + GetHeaderAddress (); + + virtual ObjectFile::Type + CalculateType(); + + virtual ObjectFile::Strata + CalculateStrata(); +protected: + lldb::ObjectFileJITDelegateWP m_delegate_wp; +}; + +#endif // liblldb_ObjectFileJIT_h_ diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index 7eca67ac7f57..7aa940a530b4 100644 --- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -1,4 +1,4 @@ -//===-- PlatformFreeBSD.cpp ---------------------------------------*- C++ -*-===// +//===-- PlatformFreeBSD.cpp -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -27,6 +27,7 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" using namespace lldb; using namespace lldb_private; @@ -47,10 +48,10 @@ PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch) case llvm::Triple::PC: create = true; break; - + #if defined(__FreeBSD__) || defined(__OpenBSD__) // Only accept "unknown" for the vendor if the host is BSD and - // it "unknown" wasn't specified (it was just returned becasue it + // it "unknown" wasn't specified (it was just returned because it // was NOT specified) case llvm::Triple::UnknownArch: create = !arch->TripleVendorWasSpecified(); @@ -59,7 +60,7 @@ PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch) default: break; } - + if (create) { switch (triple.getOS()) @@ -67,10 +68,10 @@ PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch) case llvm::Triple::FreeBSD: case llvm::Triple::KFreeBSD: break; - + #if defined(__FreeBSD__) || defined(__OpenBSD__) // Only accept "unknown" for the OS if the host is BSD and - // it "unknown" wasn't specified (it was just returned becasue it + // it "unknown" wasn't specified (it was just returned because it // was NOT specified) case llvm::Triple::UnknownOS: create = arch->TripleOSWasSpecified(); @@ -122,7 +123,7 @@ PlatformFreeBSD::Initialize () #if defined (__FreeBSD__) // Force a host flag to true for the default platform object. PlatformSP default_platform_sp (new PlatformFreeBSD(true)); - default_platform_sp->SetSystemArchitecture (Host::GetArchitecture()); + default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); Platform::SetDefaultPlatform (default_platform_sp); #endif PluginManager::RegisterPlugin(PlatformFreeBSD::GetPluginNameStatic(false), @@ -186,10 +187,10 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file, { Error error; // Nothing special to do here, just use the actual file and architecture - + char exe_path[PATH_MAX]; FileSpec resolved_exe_file (exe_file); - + if (IsHost()) { // If we have "ls" as the exe_file, resolve the executable location based on @@ -199,10 +200,10 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file, exe_file.GetPath(exe_path, sizeof(exe_path)); resolved_exe_file.SetFile(exe_path, true); } - + if (!resolved_exe_file.Exists()) resolved_exe_file.ResolveExecutableLocation (); - + if (resolved_exe_file.Exists()) error.Clear(); else @@ -223,10 +224,10 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file, else { // 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); - + if (resolved_exe_file.Exists()) { error.Clear(); } @@ -248,7 +249,7 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file, module_search_paths_ptr, NULL, NULL); - + if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL) { exe_module_sp.reset(); @@ -279,18 +280,25 @@ PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file, else error.SetErrorToGenericError(); } - + if (idx > 0) arch_names.PutCString (", "); arch_names.PutCString (platform_arch.GetArchitectureName()); } - + if (error.Fail() || !exe_module_sp) { - error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s", - exe_file.GetPath().c_str(), - GetPluginName().GetCString(), - arch_names.GetString().c_str()); + if (exe_file.Readable()) + { + error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s", + exe_file.GetPath().c_str(), + GetPluginName().GetCString(), + arch_names.GetString().c_str()); + } + else + { + error.SetErrorStringWithFormat("'%s' is not readable", exe_file.GetPath().c_str()); + } } } } @@ -305,15 +313,13 @@ PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite const uint8_t *trap_opcode = NULL; size_t trap_opcode_size = 0; - switch (arch.GetCore()) + switch (arch.GetMachine()) { default: assert(false && "Unhandled architecture in PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode()"); break; - - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_64_x86_64: - case ArchSpec::eCore_x86_64_x86_64h: + case llvm::Triple::x86: + case llvm::Triple::x86_64: { static const uint8_t g_i386_opcode[] = { 0xCC }; trap_opcode = g_i386_opcode; @@ -451,7 +457,7 @@ PlatformFreeBSD::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_i { success = Platform::GetProcessInfo (pid, process_info); } - else if (m_remote_platform_sp) + else if (m_remote_platform_sp) { success = m_remote_platform_sp->GetProcessInfo (pid, process_info); } @@ -633,19 +639,19 @@ PlatformFreeBSD::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) // From macosx;s plugin code. For FreeBSD we may want to support more archs. if (idx == 0) { - arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture); + arch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); return arch.IsValid(); } else if (idx == 1) { - ArchSpec platform_arch (Host::GetArchitecture (Host::eSystemDefaultArchitecture)); - ArchSpec platform_arch64 (Host::GetArchitecture (Host::eSystemDefaultArchitecture64)); + ArchSpec platform_arch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault)); + ArchSpec platform_arch64(HostInfo::GetArchitecture(HostInfo::eArchKind64)); if (platform_arch.IsExactMatch(platform_arch64)) { // This freebsd platform supports both 32 and 64 bit. Since we already // returned the 64 bit arch for idx == 0, return the 32 bit arch // for idx == 1 - arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture32); + arch = HostInfo::GetArchitecture(HostInfo::eArchKind32); return arch.IsValid(); } } diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h index 0682eacc5a43..62958a08a9e0 100644 --- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h +++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h @@ -1,4 +1,4 @@ -//===-- PlatformFreeBSD.h -----------------------------------------*- C++ -*-===// +//===-- PlatformFreeBSD.h ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index bb07d999c4c2..cc4c693e1b43 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -18,8 +18,11 @@ #include "lldb/Core/Log.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/File.h" +#include "lldb/Host/FileCache.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" +#include "lldb/Target/ProcessLaunchInfo.h" using namespace lldb; using namespace lldb_private; @@ -57,6 +60,16 @@ PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpret return m_options.get(); } +bool +PlatformPOSIX::IsConnected () const +{ + if (IsHost()) + return true; + else if (m_remote_platform_sp) + return m_remote_platform_sp->IsConnected(); + return false; +} + lldb_private::Error PlatformPOSIX::RunShellCommand (const char *command, // Shouldn't be NULL const char *working_dir, // Pass NULL to use the current working directory @@ -98,7 +111,7 @@ Error PlatformPOSIX::SetFilePermissions (const char *path, uint32_t file_permissions) { if (m_remote_platform_sp) - return m_remote_platform_sp->MakeDirectory(path, file_permissions); + return m_remote_platform_sp->SetFilePermissions(path, file_permissions); else return Platform::SetFilePermissions(path ,file_permissions); } @@ -110,7 +123,7 @@ PlatformPOSIX::OpenFile (const FileSpec& file_spec, Error &error) { if (IsHost()) - return Host::OpenFile(file_spec, flags, mode, error); + return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error); else if (m_remote_platform_sp) return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error); else @@ -121,7 +134,7 @@ bool PlatformPOSIX::CloseFile (lldb::user_id_t fd, Error &error) { if (IsHost()) - return Host::CloseFile(fd, error); + return FileCache::GetInstance().CloseFile(fd, error); else if (m_remote_platform_sp) return m_remote_platform_sp->CloseFile(fd, error); else @@ -136,7 +149,7 @@ PlatformPOSIX::ReadFile (lldb::user_id_t fd, Error &error) { if (IsHost()) - return Host::ReadFile(fd, offset, dst, dst_len, error); + return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error); else if (m_remote_platform_sp) return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error); else @@ -151,7 +164,7 @@ PlatformPOSIX::WriteFile (lldb::user_id_t fd, Error &error) { if (IsHost()) - return Host::WriteFile(fd, offset, src, src_len, error); + return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error); else if (m_remote_platform_sp) return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error); else @@ -339,7 +352,7 @@ lldb::user_id_t PlatformPOSIX::GetFileSize (const FileSpec& file_spec) { if (IsHost()) - return Host::GetFileSize(file_spec); + return FileSystem::GetFileSize(file_spec); else if (m_remote_platform_sp) return m_remote_platform_sp->GetFileSize(file_spec); else @@ -350,7 +363,7 @@ Error PlatformPOSIX::CreateSymlink(const char *src, const char *dst) { if (IsHost()) - return Host::Symlink(src, dst); + return FileSystem::Symlink(src, dst); else if (m_remote_platform_sp) return m_remote_platform_sp->CreateSymlink(src, dst); else @@ -372,7 +385,7 @@ Error PlatformPOSIX::Unlink (const char *path) { if (IsHost()) - return Host::Unlink (path); + return FileSystem::Unlink(path); else if (m_remote_platform_sp) return m_remote_platform_sp->Unlink(path); else @@ -469,10 +482,9 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path if (permissions == 0) permissions = lldb::eFilePermissionsFileDefault; - user_id_t fd_dst = Host::OpenFile(destination, - File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, - permissions, - error); + user_id_t fd_dst = FileCache::GetInstance().OpenFile( + destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, permissions, + error); if (fd_dst == UINT64_MAX) { @@ -496,15 +508,11 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path break; if (n_read == 0) break; - if (Host::WriteFile(fd_dst, - offset, - buffer_sp->GetBytes(), - n_read, - error) != n_read) + if (FileCache::GetInstance().WriteFile(fd_dst, offset, buffer_sp->GetBytes(), n_read, error) != n_read) { if (!error.Fail()) error.SetErrorString("unable to write to destination file"); - break; + break; } offset += n_read; } @@ -513,7 +521,7 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path if (fd_src != UINT64_MAX) CloseFile(fd_src, error); // And close the dst file descriptot. - if (fd_dst != UINT64_MAX && !Host::CloseFile(fd_dst, error)) + if (fd_dst != UINT64_MAX && !FileCache::GetInstance().CloseFile(fd_dst, error)) { if (!error.Fail()) error.SetErrorString("unable to close destination file"); @@ -589,6 +597,176 @@ PlatformPOSIX::SetRemoteWorkingDirectory(const lldb_private::ConstString &path) return Platform::SetRemoteWorkingDirectory(path); } +bool +PlatformPOSIX::GetRemoteOSVersion () +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetOSVersion (m_major_os_version, + m_minor_os_version, + m_update_os_version); + return false; +} + +bool +PlatformPOSIX::GetRemoteOSBuildString (std::string &s) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteOSBuildString (s); + s.clear(); + return false; +} + +bool +PlatformPOSIX::GetRemoteOSKernelDescription (std::string &s) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteOSKernelDescription (s); + s.clear(); + return false; +} + +// Remote Platform subclasses need to override this function +ArchSpec +PlatformPOSIX::GetRemoteSystemArchitecture () +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteSystemArchitecture (); + return ArchSpec(); +} + +const char * +PlatformPOSIX::GetHostname () +{ + if (IsHost()) + return Platform::GetHostname(); + + if (m_remote_platform_sp) + return m_remote_platform_sp->GetHostname (); + return NULL; +} + +const char * +PlatformPOSIX::GetUserName (uint32_t uid) +{ + // Check the cache in Platform in case we have already looked this uid up + const char *user_name = Platform::GetUserName(uid); + if (user_name) + return user_name; + + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetUserName(uid); + return NULL; +} + +const char * +PlatformPOSIX::GetGroupName (uint32_t gid) +{ + const char *group_name = Platform::GetGroupName(gid); + if (group_name) + return group_name; + + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetGroupName(gid); + return NULL; +} + +Error +PlatformPOSIX::ConnectRemote (Args& args) +{ + Error error; + if (IsHost()) + { + error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString()); + } + else + { + if (!m_remote_platform_sp) + m_remote_platform_sp = Platform::Create ("remote-gdb-server", error); + + if (m_remote_platform_sp && error.Success()) + error = m_remote_platform_sp->ConnectRemote (args); + else + error.SetErrorString ("failed to create a 'remote-gdb-server' platform"); + + if (error.Fail()) + m_remote_platform_sp.reset(); + } + + if (error.Success() && m_remote_platform_sp) + { + if (m_options.get()) + { + OptionGroupOptions* options = m_options.get(); + OptionGroupPlatformRSync* m_rsync_options = (OptionGroupPlatformRSync*)options->GetGroupWithOption('r'); + OptionGroupPlatformSSH* m_ssh_options = (OptionGroupPlatformSSH*)options->GetGroupWithOption('s'); + OptionGroupPlatformCaching* m_cache_options = (OptionGroupPlatformCaching*)options->GetGroupWithOption('c'); + + if (m_rsync_options->m_rsync) + { + SetSupportsRSync(true); + SetRSyncOpts(m_rsync_options->m_rsync_opts.c_str()); + SetRSyncPrefix(m_rsync_options->m_rsync_prefix.c_str()); + SetIgnoresRemoteHostname(m_rsync_options->m_ignores_remote_hostname); + } + if (m_ssh_options->m_ssh) + { + SetSupportsSSH(true); + SetSSHOpts(m_ssh_options->m_ssh_opts.c_str()); + } + SetLocalCacheDirectory(m_cache_options->m_cache_dir.c_str()); + } + } + + return error; +} + +Error +PlatformPOSIX::DisconnectRemote () +{ + Error error; + + if (IsHost()) + { + error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().GetCString()); + } + else + { + if (m_remote_platform_sp) + error = m_remote_platform_sp->DisconnectRemote (); + else + error.SetErrorString ("the platform is not currently connected"); + } + return error; +} + +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; + + if (IsHost()) + { + // We are going to hand this process off to debugserver which will be in charge of setting the exit status. + // 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); + } + else + { + if (m_remote_platform_sp) + process_sp = m_remote_platform_sp->DebugProcess (launch_info, debugger, target, listener, error); + else + error.SetErrorString ("the platform is not currently connected"); + } + return process_sp; + +} + void PlatformPOSIX::CalculateTrapHandlerSymbolNames () { diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 130c84bdface..374e36495d88 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -33,7 +33,16 @@ public: //------------------------------------------------------------ virtual lldb_private::OptionGroupOptions* GetConnectionOptions (lldb_private::CommandInterpreter& interpreter); - + + const char * + GetHostname () override; + + const char * + GetUserName (uint32_t uid) override; + + const char * + GetGroupName (uint32_t gid) override; + virtual lldb_private::Error PutFile (const lldb_private::FileSpec& source, const lldb_private::FileSpec& destination, @@ -79,7 +88,22 @@ public: virtual bool SetRemoteWorkingDirectory(const lldb_private::ConstString &path); - + + bool + GetRemoteOSVersion () override; + + bool + GetRemoteOSBuildString (std::string &s) override; + + bool + GetRemoteOSKernelDescription (std::string &s) override; + + lldb_private::ArchSpec + GetRemoteSystemArchitecture () override; + + bool + IsConnected () const override; + virtual lldb_private::Error RunShellCommand (const char *command, // Shouldn't be NULL const char *working_dir, // Pass NULL to use the current working directory @@ -103,6 +127,13 @@ public: virtual lldb_private::Error Unlink (const char *path); + 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(); @@ -114,6 +145,12 @@ public: virtual void CalculateTrapHandlerSymbolNames (); + lldb_private::Error + ConnectRemote (lldb_private::Args& args) override; + + lldb_private::Error + DisconnectRemote () override; + protected: std::unique_ptr<lldb_private::OptionGroupOptions> m_options; diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 3832265638db..05fbc5101278 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -12,11 +12,6 @@ #include "PlatformRemoteGDBServer.h" #include "lldb/Host/Config.h" -// C Includes -#ifndef LLDB_DISABLE_POSIX -#include <sys/sysctl.h> -#endif - // C++ Includes // Other libraries and framework includes // Project includes @@ -24,6 +19,7 @@ #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/PluginManager.h" @@ -346,13 +342,18 @@ PlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &p Error PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info) { + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); Error error; lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - + + if (log) + log->Printf ("PlatformRemoteGDBServer::%s() called", __FUNCTION__); + m_gdb_client.SetSTDIN ("/dev/null"); m_gdb_client.SetSTDOUT ("/dev/null"); m_gdb_client.SetSTDERR ("/dev/null"); m_gdb_client.SetDisableASLR (launch_info.GetFlags().Test (eLaunchFlagDisableASLR)); + m_gdb_client.SetDetachOnError (launch_info.GetFlags().Test (eLaunchFlagDetachOnError)); const char *working_dir = launch_info.GetWorkingDirectory(); if (working_dir && working_dir[0]) @@ -377,7 +378,9 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info) const char *arch_triple = arch_spec.GetTriple().str().c_str(); m_gdb_client.SendLaunchArchPacket(arch_triple); - + if (log) + log->Printf ("PlatformRemoteGDBServer::%s() set launch architecture triple to '%s'", __FUNCTION__, arch_triple ? arch_triple : "<NULL>"); + const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5); int arg_packet_err = m_gdb_client.SendArgumentsPacket (launch_info); m_gdb_client.SetPacketTimeout (old_packet_timeout); @@ -388,11 +391,23 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info) { pid = m_gdb_client.GetCurrentProcessID (); if (pid != LLDB_INVALID_PROCESS_ID) + { launch_info.SetProcessID (pid); + if (log) + log->Printf ("PlatformRemoteGDBServer::%s() pid %" PRIu64 " launched successfully", __FUNCTION__, pid); + } + else + { + if (log) + log->Printf ("PlatformRemoteGDBServer::%s() launch succeeded but we didn't get a valid process id back!", __FUNCTION__); + // FIXME isn't this an error condition? Do we need to set an error here? Check with Greg. + } } else { error.SetErrorString (error_str.c_str()); + if (log) + log->Printf ("PlatformRemoteGDBServer::%s() launch failed: %s", __FUNCTION__, error.AsCString ()); } } else @@ -423,7 +438,7 @@ PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_i // When remote debugging to iOS, we use a USB mux that always talks // to localhost, so we will need the remote debugserver to accept connections // only from localhost, no matter what our current hostname is - port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "localhost"); + port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "127.0.0.1"); } else { @@ -511,7 +526,7 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info, // When remote debugging to iOS, we use a USB mux that always talks // to localhost, so we will need the remote debugserver to accept connections // only from localhost, no matter what our current hostname is - port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "localhost"); + port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "127.0.0.1"); } else { diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index d13b9a485858..4b488444de1e 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -22,12 +22,23 @@ #include "ProcessFreeBSD.h" #include "ProcessPOSIXLog.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" +#include "Plugins/Process/Utility/FreeBSDSignals.h" #include "ProcessMonitor.h" #include "FreeBSDThread.h" using namespace lldb; using namespace lldb_private; +namespace +{ + UnixSignalsSP& + GetFreeBSDSignals () + { + static UnixSignalsSP s_freebsd_signals_sp (new FreeBSDSignals ()); + return s_freebsd_signals_sp; + } +} + //------------------------------------------------------------------------------ // Static functions. @@ -113,7 +124,8 @@ ProcessFreeBSD::EnablePluginLogging(Stream *strm, Args &command) // Constructors and destructors. ProcessFreeBSD::ProcessFreeBSD(Target& target, Listener &listener) - : ProcessPOSIX(target, listener) + : ProcessPOSIX(target, listener, GetFreeBSDSignals ()), + m_resume_signo(0) { } @@ -132,8 +144,6 @@ ProcessFreeBSD::DoDetach(bool keep_stopped) return error; } - DisableAllBreakpointSites(); - error = m_monitor->Detach(GetID()); if (error.Success()) @@ -147,9 +157,6 @@ ProcessFreeBSD::DoResume() { Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - // FreeBSD's ptrace() uses 0 to indicate "no signal is to be sent." - int resume_signal = 0; - SetPrivateState(eStateRunning); Mutex::Locker lock(m_thread_list.GetMutex()); @@ -172,11 +179,11 @@ ProcessFreeBSD::DoResume() } if (log) - log->Printf("process %lu resuming (%s)", GetID(), do_step ? "step" : "continue"); + log->Printf("process %" PRIu64 " resuming (%s)", GetID(), do_step ? "step" : "continue"); if (do_step) - m_monitor->SingleStep(GetID(), resume_signal); + m_monitor->SingleStep(GetID(), m_resume_signo); else - m_monitor->Resume(GetID(), resume_signal); + m_monitor->Resume(GetID(), m_resume_signo); return Error(); } @@ -228,6 +235,7 @@ ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_th Error ProcessFreeBSD::WillResume() { + m_resume_signo = 0; m_suspend_tids.clear(); m_run_tids.clear(); m_step_tids.clear(); @@ -274,4 +282,3 @@ ProcessFreeBSD::SendMessage(const ProcessMessage &message) m_message_queue.push(message); } - diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 3d793d0c1c20..63439b155111 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -702,7 +702,7 @@ EventMessageOperation::Execute(ProcessMonitor *monitor) //------------------------------------------------------------------------------ /// @class KillOperation -/// @brief Implements ProcessMonitor::BringProcessIntoLimbo. +/// @brief Implements ProcessMonitor::Kill. class KillOperation : public Operation { public: @@ -727,7 +727,7 @@ KillOperation::Execute(ProcessMonitor *monitor) //------------------------------------------------------------------------------ /// @class DetachOperation -/// @brief Implements ProcessMonitor::BringProcessIntoLimbo. +/// @brief Implements ProcessMonitor::Detach. class DetachOperation : public Operation { public: @@ -807,6 +807,7 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process, const char *stdout_path, const char *stderr_path, const char *working_dir, + const lldb_private::ProcessLaunchInfo & /* launch_info */, lldb_private::Error &error) : m_process(static_cast<ProcessFreeBSD *>(process)), m_operation_thread(LLDB_INVALID_HOST_THREAD), @@ -1628,9 +1629,13 @@ ProcessMonitor::Resume(lldb::tid_t unused, uint32_t signo) bool result; Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - if (log) - log->Printf ("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s", __FUNCTION__, GetPID(), - m_process->GetUnixSignals().GetSignalAsCString (signo)); + if (log) { + const char *signame = m_process->GetUnixSignals().GetSignalAsCString (signo); + if (signame == nullptr) + signame = "<none>"; + log->Printf("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s", + __FUNCTION__, GetPID(), signame); + } ResumeOperation op(signo, result); DoOperation(&op); if (log) @@ -1648,7 +1653,7 @@ ProcessMonitor::SingleStep(lldb::tid_t unused, uint32_t signo) } bool -ProcessMonitor::BringProcessIntoLimbo() +ProcessMonitor::Kill() { bool result; KillOperation op(result); diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 4c8198fb2e4c..314743b00754 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -55,6 +55,7 @@ public: const char *stdout_path, const char *stderr_path, const char *working_dir, + const lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Error &error); ProcessMonitor(ProcessPOSIX *process, @@ -194,11 +195,9 @@ public: bool SingleStep(lldb::tid_t unused, uint32_t signo); - /// Sends the inferior process a PTRACE_KILL signal. The inferior will - /// still exists and can be interrogated. Once resumed it will exit as - /// though it received a SIGKILL. + /// Terminate the traced process. bool - BringProcessIntoLimbo(); + Kill(); lldb_private::Error Detach(lldb::tid_t tid); diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/POSIX/POSIXThread.cpp index cc759eaad96d..d48f8f9dd307 100644 --- a/source/Plugins/Process/POSIX/POSIXThread.cpp +++ b/source/Plugins/Process/POSIX/POSIXThread.cpp @@ -20,6 +20,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/State.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Target/Process.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" @@ -29,8 +30,10 @@ #include "ProcessPOSIX.h" #include "ProcessPOSIXLog.h" #include "ProcessMonitor.h" +#include "RegisterContextPOSIXProcessMonitor_arm64.h" #include "RegisterContextPOSIXProcessMonitor_mips64.h" #include "RegisterContextPOSIXProcessMonitor_x86.h" +#include "RegisterContextLinux_arm64.h" #include "RegisterContextLinux_i386.h" #include "RegisterContextLinux_x86_64.h" #include "RegisterContextFreeBSD_i386.h" @@ -110,7 +113,7 @@ POSIXThread::RefreshStateAfterStop() GetRegisterContext()->InvalidateIfNeeded (force); } // FIXME: This should probably happen somewhere else. - SetResumeState(eStateRunning); + SetResumeState(eStateRunning, true); Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); if (log) log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to running", __FUNCTION__, GetID()); @@ -156,58 +159,82 @@ POSIXThread::GetRegisterContext() RegisterInfoInterface *reg_interface = NULL; const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture(); - switch (target_arch.GetCore()) + switch (target_arch.GetTriple().getOS()) { - case ArchSpec::eCore_mips64: - { - switch (target_arch.GetTriple().getOS()) + case llvm::Triple::FreeBSD: + switch (target_arch.GetMachine()) { - case llvm::Triple::FreeBSD: + case llvm::Triple::mips64: reg_interface = new RegisterContextFreeBSD_mips64(target_arch); break; + case llvm::Triple::x86: + reg_interface = new RegisterContextFreeBSD_i386(target_arch); + break; + case llvm::Triple::x86_64: + reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); + break; default: - assert(false && "OS not supported"); break; } - - if (reg_interface) - { - RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - } break; - } - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - case ArchSpec::eCore_x86_64_x86_64: - { - switch (target_arch.GetTriple().getOS()) + case llvm::Triple::Linux: + switch (target_arch.GetMachine()) { - case llvm::Triple::FreeBSD: - reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); + case llvm::Triple::aarch64: + assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); + reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm64(target_arch)); break; - case llvm::Triple::Linux: - reg_interface = new RegisterContextLinux_x86_64(target_arch); + case llvm::Triple::x86: + case llvm::Triple::x86_64: + if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) + { + // 32-bit hosts run with a RegisterContextLinux_i386 context. + reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_i386(target_arch)); + } + else + { + assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && + "Register setting path assumes this is a 64-bit host"); + // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context. + reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_x86_64(target_arch)); + } break; default: - assert(false && "OS not supported"); break; } - if (reg_interface) + default: + break; + } + + assert(reg_interface && "OS or CPU not supported!"); + + switch (target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + { + RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm64(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + case llvm::Triple::mips64: + { + RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*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: { RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, reg_interface); m_posix_thread = reg_ctx; m_reg_context_sp.reset(reg_ctx); + break; } - break; - } - default: - assert(false && "CPU type not supported!"); break; } } @@ -546,18 +573,14 @@ void POSIXThread::SignalNotify(const ProcessMessage &message) { int signo = message.GetSignal(); - SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo)); - SetResumeSignal(signo); } void POSIXThread::SignalDeliveredNotify(const ProcessMessage &message) { int signo = message.GetSignal(); - SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo)); - SetResumeSignal(signo); } void @@ -576,7 +599,6 @@ POSIXThread::CrashNotify(const ProcessMessage &message) SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo, message.GetCrashReason(), message.GetFaultAddress()))); - SetResumeSignal(signo); } void @@ -589,19 +611,18 @@ unsigned POSIXThread::GetRegisterIndexFromOffset(unsigned offset) { unsigned reg = LLDB_INVALID_REGNUM; - ArchSpec arch = Host::GetArchitecture(); + ArchSpec arch = HostInfo::GetArchitecture(); - switch (arch.GetCore()) + switch (arch.GetMachine()) { default: llvm_unreachable("CPU type not supported!"); break; - case ArchSpec::eCore_mips64: - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - case ArchSpec::eCore_x86_64_x86_64: + case llvm::Triple::aarch64: + case llvm::Triple::mips64: + case llvm::Triple::x86: + case llvm::Triple::x86_64: { POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); reg = reg_ctx->GetRegisterIndexFromOffset(offset); @@ -621,19 +642,18 @@ const char * POSIXThread::GetRegisterName(unsigned reg) { const char * name = nullptr; - ArchSpec arch = Host::GetArchitecture(); + ArchSpec arch = HostInfo::GetArchitecture(); - switch (arch.GetCore()) + switch (arch.GetMachine()) { default: assert(false && "CPU type not supported!"); break; - case ArchSpec::eCore_mips64: - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - case ArchSpec::eCore_x86_64_x86_64: + case llvm::Triple::aarch64: + case llvm::Triple::mips64: + case llvm::Triple::x86: + case llvm::Triple::x86_64: name = GetRegisterContext()->GetRegisterName(reg); break; } diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp index 62394623c59d..f340631c7d07 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -70,8 +70,8 @@ ProcessPOSIX::Initialize() //------------------------------------------------------------------------------ // Constructors and destructors. -ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener) - : Process(target, listener), +ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener, UnixSignalsSP &unix_signals_sp) + : Process(target, listener, unix_signals_sp), m_byte_order(lldb::endian::InlHostByteOrder()), m_monitor(NULL), m_module(NULL), @@ -176,23 +176,23 @@ ProcessPOSIX::WillLaunch(Module* module) } const char * -ProcessPOSIX::GetFilePath( - const lldb_private::ProcessLaunchInfo::FileAction *file_action, - const char *default_path) +ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const char *default_path) { const char *pts_name = "/dev/pts/"; const char *path = NULL; if (file_action) { - if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen) + if (file_action->GetAction() == FileAction::eFileActionOpen) + { path = file_action->GetPath(); // By default the stdio paths passed in will be pseudo-terminal // (/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 (::strncmp(path, pts_name, ::strlen(pts_name)) == 0) + if (!path || ::strncmp(path, pts_name, ::strlen(pts_name)) == 0) path = default_path; + } } return path; @@ -217,7 +217,7 @@ ProcessPOSIX::DoLaunch (Module *module, SetPrivateState(eStateLaunching); - const lldb_private::ProcessLaunchInfo::FileAction *file_action; + const lldb_private::FileAction *file_action; // Default of NULL will mean to use existing open file descriptors const char *stdin_path = NULL; @@ -241,6 +241,7 @@ ProcessPOSIX::DoLaunch (Module *module, stdout_path, stderr_path, working_dir, + launch_info, error); m_module = module; @@ -335,11 +336,9 @@ ProcessPOSIX::DoDestroy() if (!HasExited()) { - // Drive the exit event to completion (do not keep the inferior in - // limbo). + assert(m_monitor); m_exit_now = true; - - if ((m_monitor == NULL || kill(m_monitor->GetPID(), SIGKILL)) && error.Success()) + if (!m_monitor->Kill()) { error.SetErrorToErrno(); return error; @@ -379,6 +378,8 @@ ProcessPOSIX::DoDidExec() void ProcessPOSIX::SendMessage(const ProcessMessage &message) { + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + Mutex::Locker lock(m_message_mutex); Mutex::Locker thread_lock(m_thread_list.GetMutex()); @@ -420,8 +421,14 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) break; case ProcessMessage::eExitMessage: - assert(thread); - thread->SetState(eStateExited); + if (thread != nullptr) + thread->SetState(eStateExited); + else + { + if (log) + log->Warning ("ProcessPOSIX::%s eExitMessage for TID %" PRIu64 " failed to find a thread to mark as eStateExited, ignoring", __FUNCTION__, message.GetTID ()); + } + // FIXME: I'm not sure we need to do this. if (message.GetTID() == GetID()) { @@ -635,20 +642,26 @@ ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr) size_t ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) { + static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xD4 }; static const uint8_t g_i386_opcode[] = { 0xCC }; ArchSpec arch = GetTarget().GetArchitecture(); const uint8_t *opcode = NULL; size_t opcode_size = 0; - switch (arch.GetCore()) + switch (arch.GetMachine()) { default: assert(false && "CPU type not supported!"); break; - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_64_x86_64: + case llvm::Triple::aarch64: + opcode = g_aarch64_opcode; + opcode_size = sizeof(g_aarch64_opcode); + break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: opcode = g_i386_opcode; opcode_size = sizeof(g_i386_opcode); break; @@ -865,12 +878,6 @@ ProcessPOSIX::PutSTDIN(const char *buf, size_t len, Error &error) return status; } -UnixSignals & -ProcessPOSIX::GetUnixSignals() -{ - return m_signals; -} - //------------------------------------------------------------------------------ // Utility functions. @@ -926,3 +933,16 @@ ProcessPOSIX::IsAThreadRunning() } return is_running; } + +const DataBufferSP +ProcessPOSIX::GetAuxvData () +{ + // If we're the local platform, we can ask the host for auxv data. + PlatformSP platform_sp = m_target.GetPlatform (); + if (platform_sp && platform_sp->IsHost ()) + return lldb_private::Host::GetAuxvData(this); + + // Somewhat unexpected - the process is not running locally or we don't have a platform. + assert (false && "no platform or not the host - how did we get here with ProcessPOSIX?"); + return DataBufferSP (); +} diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h index 7f705d33fe68..033accf17f29 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h @@ -18,7 +18,6 @@ // Other libraries and framework includes #include "lldb/Target/Process.h" -#include "lldb/Target/UnixSignals.h" #include "ProcessMessage.h" class ProcessMonitor; @@ -33,7 +32,8 @@ public: // Constructors and destructors //------------------------------------------------------------------ ProcessPOSIX(lldb_private::Target& target, - lldb_private::Listener &listener); + lldb_private::Listener &listener, + lldb_private::UnixSignalsSP &unix_signals_sp); virtual ~ProcessPOSIX(); @@ -141,6 +141,9 @@ public: virtual size_t PutSTDIN(const char *buf, size_t len, lldb_private::Error &error); + const lldb::DataBufferSP + GetAuxvData () override; + //-------------------------------------------------------------------------- // ProcessPOSIX internal API. @@ -151,12 +154,7 @@ public: ProcessMonitor & GetMonitor() { assert(m_monitor); return *m_monitor; } - lldb_private::UnixSignals & - GetUnixSignals(); - - const char * - GetFilePath(const lldb_private::ProcessLaunchInfo::FileAction *file_action, - const char *default_path); + const char *GetFilePath(const lldb_private::FileAction *file_action, const char *default_path); /// Stops all threads in the process. /// The \p stop_tid parameter indicates the thread which initiated the stop. @@ -164,7 +162,7 @@ public: StopAllThreads(lldb::tid_t stop_tid); /// Adds the thread to the list of threads for which we have received the initial stopping signal. - /// The \p stop_tid paramter indicates the thread which the stop happened for. + /// The \p stop_tid parameter indicates the thread which the stop happened for. bool AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid); @@ -191,9 +189,6 @@ protected: /// Drive any exit events to completion. bool m_exit_now; - /// OS-specific signal set. - lldb_private::UnixSignals m_signals; - /// Returns true if the process has exited. bool HasExited(); diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp new file mode 100644 index 000000000000..9109cdb000ae --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp @@ -0,0 +1,318 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm64.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/Target/Thread.h" +#include "lldb/Core/RegisterValue.h" + +#include "RegisterContextPOSIX_arm64.h" +#include "ProcessPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_arm64.h" +#include "ProcessMonitor.h" + +#define REG_CONTEXT_SIZE (GetGPRSize()) + +RegisterContextPOSIXProcessMonitor_arm64::RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_arm64(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_arm64::GetMonitor() +{ + lldb::ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const unsigned reg, + lldb_private::RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const unsigned reg, + const lldb_private::RegisterValue &value) +{ + unsigned reg_to_write = reg; + lldb_private::RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + lldb_private::RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const lldb_private::RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + lldb_private::Error error; + lldb::ByteOrder byte_order = GetByteOrder(); + uint8_t dst[lldb_private::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[lldb_private::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(); + return monitor.WriteRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[lldb::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]; + } + return ReadRegister(full_reg, value); + } + + // Get pointer to m_fpr variable and set the data from it. + assert (reg_info->byte_offset < sizeof m_fpr); + uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 2: + value.SetUInt16(*(uint16_t *)src); + return true; + case 4: + value.SetUInt32(*(uint32_t *)src); + return true; + case 8: + value.SetUInt64(*(uint64_t *)src); + return true; + default: + assert(false && "Unhandled data size."); + return false; + } +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsGPR(reg)) + return WriteRegister(reg, value); + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new lldb_private::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_arm64, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy (dst, &m_fpr, sizeof m_fpr); + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues(const lldb::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_arm64, src, GetGPRSize()); + if (WriteGPR()) { + src += GetGPRSize(); + ::memcpy (&m_fpr, src, sizeof m_fpr); + success = WriteFPR(); + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint(lldb::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_arm64::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint() +{ + // PC points one byte past the int3 responsible for the breakpoint. + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + SetPC(pc - 1); + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < k_num_registers_arm64; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_arm64 && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits() +{ + return false; +} + +lldb::addr_t +RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress(uint32_t hw_index) +{ + return LLDB_INVALID_ADDRESS; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints() +{ + return 0; +} diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h new file mode 100644 index 000000000000..eb24d4852ab8 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm64.h --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" + +class RegisterContextPOSIXProcessMonitor_arm64: + public RegisterContextPOSIX_arm64, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_arm64(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_mips64.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp index f70d00e98a3e..9bfe236de139 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp @@ -22,7 +22,7 @@ using namespace lldb; RegisterContextPOSIXProcessMonitor_mips64::RegisterContextPOSIXProcessMonitor_mips64(Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info) + lldb_private::RegisterInfoInterface *register_info) : RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info) { } @@ -196,7 +196,6 @@ RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues(DataBufferSP &d if (success) { ::memcpy (dst, &m_gpr_mips64, GetGPRSize()); - dst += GetGPRSize(); } } return success; diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h index 8f545eef0d5e..79e4468b1adf 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h @@ -10,7 +10,7 @@ #ifndef liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ #define liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ -#include "Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" class RegisterContextPOSIXProcessMonitor_mips64: public RegisterContextPOSIX_mips64, @@ -19,7 +19,7 @@ class RegisterContextPOSIXProcessMonitor_mips64: public: RegisterContextPOSIXProcessMonitor_mips64(lldb_private::Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info); + lldb_private::RegisterInfoInterface *register_info); protected: bool diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp index c446bbfa7dce..e534f3b4f9d0 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -53,7 +53,7 @@ size_and_rw_bits(size_t size, bool read, bool write) RegisterContextPOSIXProcessMonitor_x86_64::RegisterContextPOSIXProcessMonitor_x86_64(Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info) + lldb_private::RegisterInfoInterface *register_info) : RegisterContextPOSIX_x86(thread, concrete_frame_idx, register_info) { } @@ -347,12 +347,12 @@ RegisterContextPOSIXProcessMonitor_x86_64::ReadAllRegisterValues(DataBufferSP &d if (success) { - ::memcpy (dst, &m_gpr_x86_64, GetGPRSize()); - dst += GetGPRSize(); + ::memcpy (dst, &m_gpr_x86_64, GetGPRSize()); + dst += GetGPRSize(); + if (GetFPRType() == eFXSAVE) + ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); } - if (GetFPRType() == eFXSAVE) - ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); - + if (GetFPRType() == eXSAVE) { ByteOrder byte_order = GetByteOrder(); diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h index 2b64fa8003a2..2afb195c4c36 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h @@ -10,7 +10,7 @@ #ifndef liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ #define liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ -#include "Plugins/Process/POSIX/RegisterContextPOSIX_x86.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h" class RegisterContextPOSIXProcessMonitor_x86_64: public RegisterContextPOSIX_x86, @@ -19,7 +19,7 @@ class RegisterContextPOSIXProcessMonitor_x86_64: public: RegisterContextPOSIXProcessMonitor_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info); + lldb_private::RegisterInfoInterface *register_info); protected: bool diff --git a/source/Plugins/Process/Utility/ARMDefines.h b/source/Plugins/Process/Utility/ARMDefines.h index 4b1f06a2f9cd..2c8ad3586af1 100644 --- a/source/Plugins/Process/Utility/ARMDefines.h +++ b/source/Plugins/Process/Utility/ARMDefines.h @@ -10,7 +10,7 @@ #ifndef lldb_ARMDefines_h_ #define lldb_ARMDefines_h_ -// Common defintions for the ARM/Thumb Instruction Set Architecture. +// Common definitions for the ARM/Thumb Instruction Set Architecture. namespace lldb_private { diff --git a/source/Plugins/Process/Utility/ARMUtils.h b/source/Plugins/Process/Utility/ARMUtils.h index 76d64e15a53e..b6ba3fea6928 100644 --- a/source/Plugins/Process/Utility/ARMUtils.h +++ b/source/Plugins/Process/Utility/ARMUtils.h @@ -316,7 +316,7 @@ static inline uint32_t ARMExpandImm(uint32_t opcode) // (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in) static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out) { - uint32_t imm32; // the expaned result + uint32_t imm32; // the expanded result const uint32_t i = bit(opcode, 26); const uint32_t imm3 = bits(opcode, 14, 12); const uint32_t abcdefgh = bits(opcode, 7, 0); diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp index dc90b7ae02c3..3507ccf92065 100644 --- a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -115,7 +115,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict RegisterInfo reg_info; std::vector<uint32_t> value_regs; std::vector<uint32_t> invalidate_regs; - bzero (®_info, sizeof(reg_info)); + memset(®_info, 0, sizeof(reg_info)); reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString(); if (reg_info.name == NULL) @@ -323,7 +323,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict reg_info.encoding = (Encoding)reg_info_dict.GetItemForKeyAsInteger (encoding_pystr, eEncodingUint); const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1); - if (set >= m_sets.size()) + if (static_cast<size_t>(set) >= m_sets.size()) { Clear(); return 0; @@ -379,7 +379,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict if (invalidate_reg_num) { const int64_t r = invalidate_reg_num.GetInteger(); - if (r != UINT64_MAX) + if (r != static_cast<int64_t>(UINT64_MAX)) m_invalidate_regs_map[i].push_back(r); else printf("error: 'invalidate-regs' list value wasn't a valid integer\n"); @@ -632,10 +632,11 @@ DynamicRegisterInfo::Dump () const { StreamFile s(stdout, false); const size_t num_regs = m_regs.size(); - s.Printf("%p: DynamicRegisterInfo contains %zu registers:\n", this, num_regs); + s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " registers:\n", + static_cast<const void*>(this), static_cast<uint64_t>(num_regs)); for (size_t i=0; i<num_regs; ++i) { - s.Printf("[%3zu] name = %-10s", i, m_regs[i].name); + s.Printf("[%3" PRIu64 "] name = %-10s", (uint64_t)i, m_regs[i].name); s.Printf(", size = %2u, offset = %4u, encoding = %u, format = %-10s", m_regs[i].byte_size, m_regs[i].byte_offset, @@ -671,12 +672,13 @@ DynamicRegisterInfo::Dump () const } s.EOL(); } - + const size_t num_sets = m_sets.size(); - s.Printf("%p: DynamicRegisterInfo contains %zu register sets:\n", this, num_sets); + s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " register sets:\n", + static_cast<const void*>(this), static_cast<uint64_t>(num_sets)); for (size_t i=0; i<num_sets; ++i) { - s.Printf("set[%zu] name = %s, regs = [", i, m_sets[i].name); + s.Printf("set[%" PRIu64 "] name = %s, regs = [", (uint64_t)i, m_sets[i].name); for (size_t idx=0; idx<m_sets[i].num_registers; ++idx) { s.Printf("%s ", m_regs[m_sets[i].registers[idx]].name); diff --git a/source/Plugins/Process/Utility/FreeBSDSignals.cpp b/source/Plugins/Process/Utility/FreeBSDSignals.cpp new file mode 100644 index 000000000000..b7c52aeb6d13 --- /dev/null +++ b/source/Plugins/Process/Utility/FreeBSDSignals.cpp @@ -0,0 +1,31 @@ +//===-- FreeBSDSignals.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "FreeBSDSignals.h" + +FreeBSDSignals::FreeBSDSignals() + : UnixSignals() +{ + Reset(); +} + +void +FreeBSDSignals::Reset() +{ + UnixSignals::Reset(); + + // SIGNO NAME SHORT NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============ ========== ======== ====== ====== =================================================== + AddSignal (32, "SIGTHR", "THR", false, true , true , "thread interrupt"); + AddSignal (33, "SIGLIBRT", "LIBRT", false, true , true , "reserved by real-time library"); +} diff --git a/source/Plugins/Process/Utility/FreeBSDSignals.h b/source/Plugins/Process/Utility/FreeBSDSignals.h new file mode 100644 index 000000000000..1e14ccb9fc4d --- /dev/null +++ b/source/Plugins/Process/Utility/FreeBSDSignals.h @@ -0,0 +1,28 @@ +//===-- FreeBSDSignals.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_FreeBSDSignals_H_ +#define liblldb_FreeBSDSignals_H_ + +// Project includes +#include "lldb/Target/UnixSignals.h" + +/// FreeBSD specific set of Unix signals. +class FreeBSDSignals + : public lldb_private::UnixSignals +{ +public: + FreeBSDSignals(); + +private: + void + Reset(); +}; + +#endif // liblldb_FreeBSDSignals_H_ diff --git a/source/Plugins/Process/Utility/HistoryThread.cpp b/source/Plugins/Process/Utility/HistoryThread.cpp index d045bc7e10d7..590bb0162c8a 100644 --- a/source/Plugins/Process/Utility/HistoryThread.cpp +++ b/source/Plugins/Process/Utility/HistoryThread.cpp @@ -20,12 +20,14 @@ using namespace lldb; using namespace lldb_private; +// Constructor + HistoryThread::HistoryThread (lldb_private::Process &process, lldb::tid_t tid, std::vector<lldb::addr_t> pcs, uint32_t stop_id, bool stop_id_is_valid) : - Thread (process, tid), + Thread (process, tid, true), m_framelist_mutex(), m_framelist(), m_pcs (pcs), @@ -40,14 +42,18 @@ HistoryThread::HistoryThread (lldb_private::Process &process, m_unwinder_ap.reset (new HistoryUnwind (*this, pcs, stop_id, stop_id_is_valid)); Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) - log->Printf ("%p HistoryThread::HistoryThread", this); + log->Printf ("%p HistoryThread::HistoryThread", + static_cast<void*>(this)); } +// Destructor + HistoryThread::~HistoryThread () { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) - log->Printf ("%p HistoryThread::~HistoryThread (tid=0x%" PRIx64 ")", this, GetID()); + log->Printf ("%p HistoryThread::~HistoryThread (tid=0x%" PRIx64 ")", + static_cast<void*>(this), GetID()); DestroyThread(); } @@ -72,7 +78,7 @@ HistoryThread::CreateRegisterContextForFrame (StackFrame *frame) lldb::StackFrameListSP HistoryThread::GetStackFrameList () { - Mutex::Locker (m_framelist_mutex); + Mutex::Locker (m_framelist_mutex); // FIXME do not throw away the lock after we acquire it.. if (m_framelist.get() == NULL) { m_framelist.reset (new StackFrameList (*this, StackFrameListSP(), true)); diff --git a/source/Plugins/Process/Utility/HistoryUnwind.cpp b/source/Plugins/Process/Utility/HistoryUnwind.cpp index 86665fd17b13..f809ebedcfc8 100644 --- a/source/Plugins/Process/Utility/HistoryUnwind.cpp +++ b/source/Plugins/Process/Utility/HistoryUnwind.cpp @@ -20,6 +20,8 @@ using namespace lldb; using namespace lldb_private; +// Constructor + HistoryUnwind::HistoryUnwind (Thread &thread, std::vector<lldb::addr_t> pcs, uint32_t stop_id, @@ -31,6 +33,8 @@ HistoryUnwind::HistoryUnwind (Thread &thread, { } +// Destructor + HistoryUnwind::~HistoryUnwind () { } @@ -62,7 +66,7 @@ HistoryUnwind::DoCreateRegisterContextForFrame (StackFrame *frame) bool HistoryUnwind::DoGetFrameInfoAtIndex (uint32_t frame_idx, lldb::addr_t& cfa, lldb::addr_t& pc) { - Mutex::Locker (m_unwind_mutex); + Mutex::Locker (m_unwind_mutex); // FIXME do not throw away the lock after we acquire it.. if (frame_idx < m_pcs.size()) { cfa = frame_idx; diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 1d5d19fad25f..4a94457466be 100644 --- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -117,11 +117,11 @@ lldb_private::InferiorCallMmap (Process *process, { ExecutionContext exe_ctx; frame->CalculateExecutionContext (exe_ctx); - ExecutionResults result = process->RunThreadPlan (exe_ctx, + ExpressionResults result = process->RunThreadPlan (exe_ctx, call_plan_sp, options, error_strm); - if (result == eExecutionCompleted) + if (result == eExpressionCompleted) { allocated_addr = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); @@ -202,11 +202,11 @@ lldb_private::InferiorCallMunmap (Process *process, { ExecutionContext exe_ctx; frame->CalculateExecutionContext (exe_ctx); - ExecutionResults result = process->RunThreadPlan (exe_ctx, + ExpressionResults result = process->RunThreadPlan (exe_ctx, call_plan_sp, options, error_strm); - if (result == eExecutionCompleted) + if (result == eExpressionCompleted) { return true; } @@ -260,11 +260,11 @@ lldb_private::InferiorCall (Process *process, { ExecutionContext exe_ctx; frame->CalculateExecutionContext (exe_ctx); - ExecutionResults result = process->RunThreadPlan (exe_ctx, + ExpressionResults result = process->RunThreadPlan (exe_ctx, call_plan_sp, options, error_strm); - if (result == eExecutionCompleted) + if (result == eExpressionCompleted) { returned_func = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); diff --git a/source/Plugins/Process/Utility/InstructionUtils.h b/source/Plugins/Process/Utility/InstructionUtils.h index 4bb644e6efe6..813990095c49 100644 --- a/source/Plugins/Process/Utility/InstructionUtils.h +++ b/source/Plugins/Process/Utility/InstructionUtils.h @@ -83,6 +83,8 @@ Rotl32 (uint32_t bits, uint32_t amt) static inline uint64_t MaskUpToBit (const uint64_t bit) { + if (bit >= 63) + return -1ll; return (1ull << (bit + 1ull)) - 1ull; } diff --git a/source/Plugins/Process/Utility/LinuxSignals.cpp b/source/Plugins/Process/Utility/LinuxSignals.cpp new file mode 100644 index 000000000000..fb49df681cae --- /dev/null +++ b/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -0,0 +1,62 @@ +//===-- LinuxSignals.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "LinuxSignals.h" + +using namespace process_linux; + +LinuxSignals::LinuxSignals() + : UnixSignals() +{ + Reset(); +} + +void +LinuxSignals::Reset() +{ + m_signals.clear(); + + AddSignal (1, "SIGHUP", "HUP", false, true , true , "hangup"); + AddSignal (2, "SIGINT", "INT", true , true , true , "interrupt"); + AddSignal (3, "SIGQUIT", "QUIT", false, true , true , "quit"); + AddSignal (4, "SIGILL", "ILL", false, true , true , "illegal instruction"); + AddSignal (5, "SIGTRAP", "TRAP", true , true , true , "trace trap (not reset when caught)"); + AddSignal (6, "SIGABRT", "ABRT", false, true , true , "abort()"); + AddSignal (6, "SIGIOT", "IOT", false, true , true , "IOT trap"); + AddSignal (7, "SIGBUS", "BUS", false, true , true , "bus error"); + AddSignal (8, "SIGFPE", "FPE", false, true , true , "floating point exception"); + AddSignal (9, "SIGKILL", "KILL", false, true , true , "kill"); + AddSignal (10, "SIGUSR1", "USR1", false, true , true , "user defined signal 1"); + AddSignal (11, "SIGSEGV", "SEGV", false, true , true , "segmentation violation"); + AddSignal (12, "SIGUSR2", "USR2", false, true , true , "user defined signal 2"); + AddSignal (13, "SIGPIPE", "PIPE", false, true , true , "write to pipe with reading end closed"); + AddSignal (14, "SIGALRM", "ALRM", false, false, false, "alarm"); + AddSignal (15, "SIGTERM", "TERM", false, true , true , "termination requested"); + AddSignal (16, "SIGSTKFLT", "STKFLT", false, true , true , "stack fault"); + AddSignal (16, "SIGCLD", "CLD", false, false, true , "same as SIGCHLD"); + AddSignal (17, "SIGCHLD", "CHLD", false, false, true , "child status has changed"); + AddSignal (18, "SIGCONT", "CONT", false, true , true , "process continue"); + AddSignal (19, "SIGSTOP", "STOP", true , true , true , "process stop"); + AddSignal (20, "SIGTSTP", "TSTP", false, true , true , "tty stop"); + AddSignal (21, "SIGTTIN", "TTIN", false, true , true , "background tty read"); + AddSignal (22, "SIGTTOU", "TTOU", false, true , true , "background tty write"); + AddSignal (23, "SIGURG", "URG", false, true , true , "urgent data on socket"); + 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 (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"); + AddSignal (30, "SIGPWR", "PWR", false, true , true , "power failure"); + AddSignal (31, "SIGSYS", "SYS", false, true , true , "invalid system call"); +} diff --git a/source/Plugins/Process/Utility/LinuxSignals.h b/source/Plugins/Process/Utility/LinuxSignals.h new file mode 100644 index 000000000000..9645b3d8725a --- /dev/null +++ b/source/Plugins/Process/Utility/LinuxSignals.h @@ -0,0 +1,35 @@ +//===-- LinuxSignals.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_LinuxSignals_H_ +#define liblldb_LinuxSignals_H_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Target/UnixSignals.h" + +namespace process_linux +{ + + /// Linux specific set of Unix signals. + class LinuxSignals + : public lldb_private::UnixSignals + { + public: + LinuxSignals(); + + private: + void + Reset(); + }; +} + +#endif diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp index 4d77b6f20fdc..4138a6aaa2aa 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp @@ -37,6 +37,8 @@ #include "ARM_GCC_Registers.h" #include "ARM_DWARF_Registers.h" +#include "llvm/ADT/STLExtras.h" + using namespace lldb; using namespace lldb_private; @@ -399,7 +401,7 @@ g_exc_regnums[] = exc_far, }; -static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo)); +static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos); void RegisterContextDarwin_arm::InvalidateAllRegisters () @@ -438,9 +440,9 @@ RegisterContextDarwin_arm::GetRegisterInfos () // Number of registers in each register set -const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t); -const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t); -const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t); +const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums); +const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); +const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); //---------------------------------------------------------------------- // Register set definitions. The first definitions at register set index @@ -454,7 +456,7 @@ static const RegisterSet g_reg_sets[] = { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums } }; -const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet); +const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets); size_t @@ -473,7 +475,7 @@ RegisterContextDarwin_arm::GetRegisterSet (size_t reg_set) //---------------------------------------------------------------------- -// Register information defintions for 32 bit i386. +// Register information definitions for 32 bit i386. //---------------------------------------------------------------------- int RegisterContextDarwin_arm::GetSetForNativeRegNum (int reg) @@ -864,7 +866,7 @@ RegisterContextDarwin_arm::WriteAllRegisterValues (const lldb::DataBufferSP &dat } uint32_t -RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg) +RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg) { if (kind == eRegisterKindGeneric) { diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h index 0bf204f57c80..23134efd43e6 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h @@ -87,7 +87,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); virtual uint32_t NumSupportedHardwareBreakpoints (); diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp new file mode 100644 index 000000000000..e08a87369e4d --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp @@ -0,0 +1,944 @@ +//===-- RegisterContextDarwin_arm64.cpp ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#if defined(__APPLE__) + +#include "RegisterContextDarwin_arm64.h" + +// C Includes +#include <mach/mach_types.h> +#include <mach/thread_act.h> +#include <sys/sysctl.h> + +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Host/Endian.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Compiler.h" + +#include "Plugins/Process/Utility/InstructionUtils.h" + +// Support building against older versions of LLVM, this macro was added +// recently. +#ifndef LLVM_EXTENSION +#define LLVM_EXTENSION +#endif + +// Project includes +#include "ARM64_GCC_Registers.h" +#include "ARM64_DWARF_Registers.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextDarwin_arm64::RegisterContextDarwin_arm64(Thread &thread, uint32_t concrete_frame_idx) : + RegisterContext(thread, concrete_frame_idx), + gpr(), + fpu(), + exc() +{ + uint32_t i; + for (i=0; i<kNumErrors; i++) + { + gpr_errs[i] = -1; + fpu_errs[i] = -1; + exc_errs[i] = -1; + } +} + +RegisterContextDarwin_arm64::~RegisterContextDarwin_arm64() +{ +} + + +#define GPR_OFFSET(idx) ((idx) * 8) +#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::GPR, reg)) + +#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextDarwin_arm64::GPR)) +#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::FPU, reg)) + +#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::EXC, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU)) +#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::DBG, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC)) + +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC)) + +//----------------------------------------------------------------------------- +// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. +//----------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_ARM64_STRUCT +#include "RegisterInfos_arm64.h" +#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT + +// General purpose registers +static uint32_t +g_gpr_regnums[] = +{ + gpr_x0, + gpr_x1, + gpr_x2, + gpr_x3, + gpr_x4, + gpr_x5, + gpr_x6, + gpr_x7, + gpr_x8, + gpr_x9, + gpr_x10, + gpr_x11, + gpr_x12, + gpr_x13, + gpr_x14, + gpr_x15, + gpr_x16, + gpr_x17, + gpr_x18, + gpr_x19, + gpr_x20, + gpr_x21, + gpr_x22, + gpr_x23, + gpr_x24, + gpr_x25, + gpr_x26, + gpr_x27, + gpr_x28, + gpr_fp, + gpr_lr, + gpr_sp, + gpr_pc, + gpr_cpsr +}; + +// Floating point registers +static uint32_t +g_fpu_regnums[] = +{ + fpu_v0, + fpu_v1, + fpu_v2, + fpu_v3, + fpu_v4, + fpu_v5, + fpu_v6, + fpu_v7, + fpu_v8, + fpu_v9, + fpu_v10, + fpu_v11, + fpu_v12, + fpu_v13, + fpu_v14, + fpu_v15, + fpu_v16, + fpu_v17, + fpu_v18, + fpu_v19, + fpu_v20, + fpu_v21, + fpu_v22, + fpu_v23, + fpu_v24, + fpu_v25, + fpu_v26, + fpu_v27, + fpu_v28, + fpu_v29, + fpu_v30, + fpu_v31, + fpu_fpsr, + fpu_fpcr +}; + +// Exception registers + +static uint32_t +g_exc_regnums[] = +{ + exc_far, + exc_esr, + exc_exception +}; + +static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos_arm64); + +void +RegisterContextDarwin_arm64::InvalidateAllRegisters () +{ + InvalidateAllRegisterStates(); +} + + +size_t +RegisterContextDarwin_arm64::GetRegisterCount () +{ + assert(k_num_register_infos == k_num_registers); + return k_num_registers; +} + +const RegisterInfo * +RegisterContextDarwin_arm64::GetRegisterInfoAtIndex (size_t reg) +{ + assert(k_num_register_infos == k_num_registers); + if (reg < k_num_registers) + return &g_register_infos_arm64[reg]; + return NULL; +} + +size_t +RegisterContextDarwin_arm64::GetRegisterInfosCount () +{ + return k_num_register_infos; +} + +const RegisterInfo * +RegisterContextDarwin_arm64::GetRegisterInfos () +{ + return g_register_infos_arm64; +} + + +// Number of registers in each register set +const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums); +const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); +const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); + +//---------------------------------------------------------------------- +// Register set definitions. The first definitions at register set index +// of zero is for all registers, followed by other registers sets. The +// register information for the all register set need not be filled in. +//---------------------------------------------------------------------- +static const RegisterSet g_reg_sets[] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, }, + { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums }, + { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums } +}; + +const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets); + + +size_t +RegisterContextDarwin_arm64::GetRegisterSetCount () +{ + return k_num_regsets; +} + +const RegisterSet * +RegisterContextDarwin_arm64::GetRegisterSet (size_t reg_set) +{ + if (reg_set < k_num_regsets) + return &g_reg_sets[reg_set]; + return NULL; +} + + +//---------------------------------------------------------------------- +// Register information definitions for arm64 +//---------------------------------------------------------------------- +int +RegisterContextDarwin_arm64::GetSetForNativeRegNum (int reg) +{ + if (reg < fpu_v0) + return GPRRegSet; + else if (reg < exc_far) + return FPURegSet; + else if (reg < k_num_registers) + return EXCRegSet; + return -1; +} + +int +RegisterContextDarwin_arm64::ReadGPR (bool force) +{ + int set = GPRRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr)); + } + return GetError(GPRRegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadFPU (bool force) +{ + int set = FPURegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu)); + } + return GetError(FPURegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadEXC (bool force) +{ + int set = EXCRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadEXC(GetThreadID(), set, exc)); + } + return GetError(EXCRegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadDBG (bool force) +{ + int set = DBGRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg)); + } + return GetError(DBGRegSet, Read); +} + +int +RegisterContextDarwin_arm64::WriteGPR () +{ + int set = GPRRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr)); + SetError (set, Read, -1); + return GetError(GPRRegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteFPU () +{ + int set = FPURegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu)); + SetError (set, Read, -1); + return GetError(FPURegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteEXC () +{ + int set = EXCRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc)); + SetError (set, Read, -1); + return GetError(EXCRegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteDBG () +{ + int set = DBGRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteDBG(GetThreadID(), set, dbg)); + SetError (set, Read, -1); + return GetError(DBGRegSet, Write); +} + + +int +RegisterContextDarwin_arm64::ReadRegisterSet (uint32_t set, bool force) +{ + switch (set) + { + case GPRRegSet: return ReadGPR(force); + case FPURegSet: return ReadFPU(force); + case EXCRegSet: return ReadEXC(force); + case DBGRegSet: return ReadDBG(force); + default: break; + } + return KERN_INVALID_ARGUMENT; +} + +int +RegisterContextDarwin_arm64::WriteRegisterSet (uint32_t set) +{ + // Make sure we have a valid context to set. + if (RegisterSetIsCached(set)) + { + switch (set) + { + case GPRRegSet: return WriteGPR(); + case FPURegSet: return WriteFPU(); + case EXCRegSet: return WriteEXC(); + case DBGRegSet: return WriteDBG(); + default: break; + } + } + return KERN_INVALID_ARGUMENT; +} + +void +RegisterContextDarwin_arm64::LogDBGRegisters (Log *log, const DBG& dbg) +{ + if (log) + { + for (uint32_t i=0; i<16; i++) + log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8llx, 0x%8.8llx } WVR%-2u/WCR%-2u = { 0x%8.8llx, 0x%8.8llx }", + i, i, dbg.bvr[i], dbg.bcr[i], + i, i, dbg.wvr[i], dbg.wcr[i]); + } +} + + +bool +RegisterContextDarwin_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + int set = RegisterContextDarwin_arm64::GetSetForNativeRegNum (reg); + + if (set == -1) + return false; + + if (ReadRegisterSet(set, false) != KERN_SUCCESS) + return false; + + switch (reg) + { + case gpr_x0: + case gpr_x1: + case gpr_x2: + case gpr_x3: + case gpr_x4: + case gpr_x5: + case gpr_x6: + case gpr_x7: + case gpr_x8: + case gpr_x9: + case gpr_x10: + case gpr_x11: + case gpr_x12: + case gpr_x13: + case gpr_x14: + case gpr_x15: + case gpr_x16: + case gpr_x17: + case gpr_x18: + case gpr_x19: + case gpr_x20: + case gpr_x21: + case gpr_x22: + case gpr_x23: + case gpr_x24: + case gpr_x25: + case gpr_x26: + case gpr_x27: + case gpr_x28: + case gpr_fp: + case gpr_sp: + case gpr_lr: + case gpr_pc: + case gpr_cpsr: + value.SetUInt64 (gpr.x[reg - gpr_x0]); + break; + + case fpu_v0: + case fpu_v1: + case fpu_v2: + case fpu_v3: + case fpu_v4: + case fpu_v5: + case fpu_v6: + case fpu_v7: + case fpu_v8: + case fpu_v9: + case fpu_v10: + case fpu_v11: + case fpu_v12: + case fpu_v13: + case fpu_v14: + case fpu_v15: + case fpu_v16: + case fpu_v17: + case fpu_v18: + case fpu_v19: + case fpu_v20: + case fpu_v21: + case fpu_v22: + case fpu_v23: + case fpu_v24: + case fpu_v25: + case fpu_v26: + case fpu_v27: + case fpu_v28: + case fpu_v29: + case fpu_v30: + case fpu_v31: + value.SetBytes(fpu.v[reg].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder()); + break; + + case fpu_fpsr: + value.SetUInt32 (fpu.fpsr); + break; + + case fpu_fpcr: + value.SetUInt32 (fpu.fpcr); + break; + + case exc_exception: + value.SetUInt32 (exc.exception); + break; + case exc_esr: + value.SetUInt32 (exc.esr); + break; + case exc_far: + value.SetUInt64 (exc.far); + break; + + default: + value.SetValueToInvalid(); + return false; + + } + return true; +} + + +bool +RegisterContextDarwin_arm64::WriteRegister (const RegisterInfo *reg_info, + const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + int set = GetSetForNativeRegNum (reg); + + if (set == -1) + return false; + + if (ReadRegisterSet(set, false) != KERN_SUCCESS) + return false; + + switch (reg) + { + case gpr_x0: + case gpr_x1: + case gpr_x2: + case gpr_x3: + case gpr_x4: + case gpr_x5: + case gpr_x6: + case gpr_x7: + case gpr_x8: + case gpr_x9: + case gpr_x10: + case gpr_x11: + case gpr_x12: + case gpr_x13: + case gpr_x14: + case gpr_x15: + case gpr_x16: + case gpr_x17: + case gpr_x18: + case gpr_x19: + case gpr_x20: + case gpr_x21: + case gpr_x22: + case gpr_x23: + case gpr_x24: + case gpr_x25: + case gpr_x26: + case gpr_x27: + case gpr_x28: + case gpr_fp: + case gpr_sp: + case gpr_lr: + case gpr_pc: + case gpr_cpsr: + gpr.x[reg - gpr_x0] = value.GetAsUInt64(); + break; + + case fpu_v0: + case fpu_v1: + case fpu_v2: + case fpu_v3: + case fpu_v4: + case fpu_v5: + case fpu_v6: + case fpu_v7: + case fpu_v8: + case fpu_v9: + case fpu_v10: + case fpu_v11: + case fpu_v12: + case fpu_v13: + case fpu_v14: + case fpu_v15: + case fpu_v16: + case fpu_v17: + case fpu_v18: + case fpu_v19: + case fpu_v20: + case fpu_v21: + case fpu_v22: + case fpu_v23: + case fpu_v24: + case fpu_v25: + case fpu_v26: + case fpu_v27: + case fpu_v28: + case fpu_v29: + case fpu_v30: + case fpu_v31: + ::memcpy (fpu.v[reg].bytes, value.GetBytes(), value.GetByteSize()); + break; + + case fpu_fpsr: + fpu.fpsr = value.GetAsUInt32(); + break; + + case fpu_fpcr: + fpu.fpcr = value.GetAsUInt32(); + break; + + case exc_exception: + exc.exception = value.GetAsUInt32(); + break; + case exc_esr: + exc.esr = value.GetAsUInt32(); + break; + case exc_far: + exc.far = value.GetAsUInt64(); + break; + + default: + return false; + + } + return WriteRegisterSet(set) == KERN_SUCCESS; +} + +bool +RegisterContextDarwin_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) +{ + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && + ReadGPR (false) == KERN_SUCCESS && + ReadFPU (false) == KERN_SUCCESS && + ReadEXC (false) == KERN_SUCCESS) + { + uint8_t *dst = data_sp->GetBytes(); + ::memcpy (dst, &gpr, sizeof(gpr)); + dst += sizeof(gpr); + + ::memcpy (dst, &fpu, sizeof(fpu)); + dst += sizeof(gpr); + + ::memcpy (dst, &exc, sizeof(exc)); + return true; + } + return false; +} + +bool +RegisterContextDarwin_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) +{ + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + const uint8_t *src = data_sp->GetBytes(); + ::memcpy (&gpr, src, sizeof(gpr)); + src += sizeof(gpr); + + ::memcpy (&fpu, src, sizeof(fpu)); + src += sizeof(gpr); + + ::memcpy (&exc, src, sizeof(exc)); + uint32_t success_count = 0; + if (WriteGPR() == KERN_SUCCESS) + ++success_count; + if (WriteFPU() == KERN_SUCCESS) + ++success_count; + if (WriteEXC() == KERN_SUCCESS) + ++success_count; + return success_count == 3; + } + return false; +} + +uint32_t +RegisterContextDarwin_arm64::ConvertRegisterKindToRegisterNumber (RegisterKind kind, uint32_t reg) +{ + if (kind == eRegisterKindGeneric) + { + switch (reg) + { + case LLDB_REGNUM_GENERIC_PC: return gpr_pc; + case LLDB_REGNUM_GENERIC_SP: return gpr_sp; + case LLDB_REGNUM_GENERIC_FP: return gpr_fp; + case LLDB_REGNUM_GENERIC_RA: return gpr_lr; + case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr; + default: + break; + } + } + else if (kind == eRegisterKindDWARF) + { + switch (reg) + { + case arm64_dwarf::x0: return gpr_x0; + case arm64_dwarf::x1: return gpr_x1; + case arm64_dwarf::x2: return gpr_x2; + case arm64_dwarf::x3: return gpr_x3; + case arm64_dwarf::x4: return gpr_x4; + case arm64_dwarf::x5: return gpr_x5; + case arm64_dwarf::x6: return gpr_x6; + case arm64_dwarf::x7: return gpr_x7; + case arm64_dwarf::x8: return gpr_x8; + case arm64_dwarf::x9: return gpr_x9; + case arm64_dwarf::x10: return gpr_x10; + case arm64_dwarf::x11: return gpr_x11; + case arm64_dwarf::x12: return gpr_x12; + case arm64_dwarf::x13: return gpr_x13; + case arm64_dwarf::x14: return gpr_x14; + case arm64_dwarf::x15: return gpr_x15; + case arm64_dwarf::x16: return gpr_x16; + case arm64_dwarf::x17: return gpr_x17; + case arm64_dwarf::x18: return gpr_x18; + case arm64_dwarf::x19: return gpr_x19; + case arm64_dwarf::x20: return gpr_x20; + case arm64_dwarf::x21: return gpr_x21; + case arm64_dwarf::x22: return gpr_x22; + case arm64_dwarf::x23: return gpr_x23; + case arm64_dwarf::x24: return gpr_x24; + case arm64_dwarf::x25: return gpr_x25; + case arm64_dwarf::x26: return gpr_x26; + case arm64_dwarf::x27: return gpr_x27; + case arm64_dwarf::x28: return gpr_x28; + + case arm64_dwarf::fp: return gpr_fp; + case arm64_dwarf::sp: return gpr_sp; + case arm64_dwarf::lr: return gpr_lr; + case arm64_dwarf::pc: return gpr_pc; + case arm64_dwarf::cpsr: return gpr_cpsr; + + case arm64_dwarf::v0: return fpu_v0; + case arm64_dwarf::v1: return fpu_v1; + case arm64_dwarf::v2: return fpu_v2; + case arm64_dwarf::v3: return fpu_v3; + case arm64_dwarf::v4: return fpu_v4; + case arm64_dwarf::v5: return fpu_v5; + case arm64_dwarf::v6: return fpu_v6; + case arm64_dwarf::v7: return fpu_v7; + case arm64_dwarf::v8: return fpu_v8; + case arm64_dwarf::v9: return fpu_v9; + case arm64_dwarf::v10: return fpu_v10; + case arm64_dwarf::v11: return fpu_v11; + case arm64_dwarf::v12: return fpu_v12; + case arm64_dwarf::v13: return fpu_v13; + case arm64_dwarf::v14: return fpu_v14; + case arm64_dwarf::v15: return fpu_v15; + case arm64_dwarf::v16: return fpu_v16; + case arm64_dwarf::v17: return fpu_v17; + case arm64_dwarf::v18: return fpu_v18; + case arm64_dwarf::v19: return fpu_v19; + case arm64_dwarf::v20: return fpu_v20; + case arm64_dwarf::v21: return fpu_v21; + case arm64_dwarf::v22: return fpu_v22; + case arm64_dwarf::v23: return fpu_v23; + case arm64_dwarf::v24: return fpu_v24; + case arm64_dwarf::v25: return fpu_v25; + case arm64_dwarf::v26: return fpu_v26; + case arm64_dwarf::v27: return fpu_v27; + case arm64_dwarf::v28: return fpu_v28; + case arm64_dwarf::v29: return fpu_v29; + case arm64_dwarf::v30: return fpu_v30; + case arm64_dwarf::v31: return fpu_v31; + + default: + break; + } + } + else if (kind == eRegisterKindGCC) + { + switch (reg) + { + case arm64_gcc::x0: return gpr_x0; + case arm64_gcc::x1: return gpr_x1; + case arm64_gcc::x2: return gpr_x2; + case arm64_gcc::x3: return gpr_x3; + case arm64_gcc::x4: return gpr_x4; + case arm64_gcc::x5: return gpr_x5; + case arm64_gcc::x6: return gpr_x6; + case arm64_gcc::x7: return gpr_x7; + case arm64_gcc::x8: return gpr_x8; + case arm64_gcc::x9: return gpr_x9; + case arm64_gcc::x10: return gpr_x10; + case arm64_gcc::x11: return gpr_x11; + case arm64_gcc::x12: return gpr_x12; + case arm64_gcc::x13: return gpr_x13; + case arm64_gcc::x14: return gpr_x14; + case arm64_gcc::x15: return gpr_x15; + case arm64_gcc::x16: return gpr_x16; + case arm64_gcc::x17: return gpr_x17; + case arm64_gcc::x18: return gpr_x18; + case arm64_gcc::x19: return gpr_x19; + case arm64_gcc::x20: return gpr_x20; + case arm64_gcc::x21: return gpr_x21; + case arm64_gcc::x22: return gpr_x22; + case arm64_gcc::x23: return gpr_x23; + case arm64_gcc::x24: return gpr_x24; + case arm64_gcc::x25: return gpr_x25; + case arm64_gcc::x26: return gpr_x26; + case arm64_gcc::x27: return gpr_x27; + case arm64_gcc::x28: return gpr_x28; + case arm64_gcc::fp: return gpr_fp; + case arm64_gcc::sp: return gpr_sp; + case arm64_gcc::lr: return gpr_lr; + case arm64_gcc::pc: return gpr_pc; + case arm64_gcc::cpsr: return gpr_cpsr; + } + } + else if (kind == eRegisterKindLLDB) + { + return reg; + } + return LLDB_INVALID_REGNUM; +} + + +uint32_t +RegisterContextDarwin_arm64::NumSupportedHardwareWatchpoints () +{ +#if defined (__arm64__) || defined (__aarch64__) + // autodetect how many watchpoints are supported dynamically... + static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX; + if (g_num_supported_hw_watchpoints == UINT32_MAX) + { + size_t len; + uint32_t n = 0; + len = sizeof (n); + if (::sysctlbyname("hw.optional.watchpoint", &n, &len, NULL, 0) == 0) + { + g_num_supported_hw_watchpoints = n; + } + } + return g_num_supported_hw_watchpoints; +#else + // TODO: figure out remote case here! + return 2; +#endif +} + + +uint32_t +RegisterContextDarwin_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write) +{ +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write); + + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + + // Can't watch zero bytes + if (size == 0) + return LLDB_INVALID_INDEX32; + + // We must watch for either read or write + if (read == false && write == false) + return LLDB_INVALID_INDEX32; + + // Can't watch more than 4 bytes per WVR/WCR pair + if (size > 4) + return LLDB_INVALID_INDEX32; + + // We can only watch up to four bytes that follow a 4 byte aligned address + // per watchpoint register pair. Since we have at most so we can only watch + // until the next 4 byte boundary and we need to make sure we can properly + // encode this. + uint32_t addr_word_offset = addr % 4; +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset); + + uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset; +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask); + if (byte_mask > 0xfu) + return LLDB_INVALID_INDEX32; + + // Read the debug state + int kret = ReadDBG (false); + + if (kret == KERN_SUCCESS) + { + // Check to make sure we have the needed hardware support + uint32_t i = 0; + + for (i=0; i<num_hw_watchpoints; ++i) + { + if ((dbg.wcr[i] & WCR_ENABLE) == 0) + break; // We found an available hw breakpoint slot (in i) + } + + // See if we found an available hw breakpoint slot above + if (i < num_hw_watchpoints) + { + // Make the byte_mask into a valid Byte Address Select mask + uint32_t byte_address_select = byte_mask << 5; + // Make sure bits 1:0 are clear in our address + dbg.wvr[i] = addr & ~((lldb::addr_t)3); + dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA that we will watch + S_USER | // Stop only in user mode + (read ? WCR_LOAD : 0) | // Stop on read access? + (write ? WCR_STORE : 0) | // Stop on write access? + WCR_ENABLE; // Enable this watchpoint; + + kret = WriteDBG(); +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret); + + if (kret == KERN_SUCCESS) + return i; + } + else + { +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); + } + } + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextDarwin_arm64::ClearHardwareWatchpoint (uint32_t hw_index) +{ + int kret = ReadDBG (false); + + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (kret == KERN_SUCCESS) + { + if (hw_index < num_hw_points) + { + dbg.wcr[hw_index] = 0; +// if (log) log->Printf ("RegisterContextDarwin_arm64::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x", +// hw_index, +// hw_index, +// dbg.wvr[hw_index], +// hw_index, +// dbg.wcr[hw_index]); + + kret = WriteDBG(); + + if (kret == KERN_SUCCESS) + return true; + } + } + return false; +} + +#endif diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h new file mode 100644 index 000000000000..aeac15e9b09a --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h @@ -0,0 +1,296 @@ +//===-- RegisterContextDarwin_arm64.h -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextDarwin_arm64_h_ +#define liblldb_RegisterContextDarwin_arm64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" + +// Break only in privileged or user mode +#define S_RSVD ((uint32_t)(0u << 1)) +#define S_PRIV ((uint32_t)(1u << 1)) +#define S_USER ((uint32_t)(2u << 1)) +#define S_PRIV_USER ((S_PRIV) | (S_USER)) + +#define WCR_ENABLE ((uint32_t)(1u)) + +// Watchpoint load/store +#define WCR_LOAD ((uint32_t)(1u << 3)) +#define WCR_STORE ((uint32_t)(1u << 4)) + +class RegisterContextDarwin_arm64 : public lldb_private::RegisterContext +{ +public: + + RegisterContextDarwin_arm64(lldb_private::Thread &thread, uint32_t concrete_frame_idx); + + virtual + ~RegisterContextDarwin_arm64(); + + virtual void + InvalidateAllRegisters (); + + virtual size_t + GetRegisterCount (); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex (size_t reg); + + virtual size_t + GetRegisterSetCount (); + + virtual const lldb_private::RegisterSet * + GetRegisterSet (size_t set); + + 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); + + virtual bool + ReadAllRegisterValues (lldb::DataBufferSP &data_sp); + + virtual bool + WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); + + virtual uint32_t + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); + + virtual uint32_t + NumSupportedHardwareWatchpoints (); + + virtual uint32_t + SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write); + + virtual bool + ClearHardwareWatchpoint (uint32_t hw_index); + + // mirrors <mach/arm/thread_status.h> arm_thread_state64_t + struct GPR + { + uint64_t x[29]; // x0-x28 + uint64_t fp; // x29 + uint64_t lr; // x30 + uint64_t sp; // x31 + uint64_t pc; // pc + uint32_t cpsr; // cpsr + }; + + + struct VReg + { + uint8_t bytes[16]; + }; + + // mirrors <mach/arm/thread_status.h> arm_neon_state64_t + struct FPU + { + VReg v[32]; + uint32_t fpsr; + uint32_t fpcr; + }; + + // mirrors <mach/arm/thread_status.h> arm_exception_state64_t + struct EXC + { + uint64_t far; // Virtual Fault Address + uint32_t esr; // Exception syndrome + uint32_t exception; // number of arm exception token + }; + + // mirrors <mach/arm/thread_status.h> arm_debug_state64_t + struct DBG + { + uint64_t bvr[16]; + uint64_t bcr[16]; + uint64_t wvr[16]; + uint64_t wcr[16]; + uint64_t mdscr_el1; + }; + + static void + LogDBGRegisters (lldb_private::Log *log, const DBG& dbg); + +protected: + + enum + { + GPRRegSet = 6, // ARM_THREAD_STATE64 + FPURegSet = 17, // ARM_NEON_STATE64 + EXCRegSet = 7, // ARM_EXCEPTION_STATE64 + DBGRegSet = 15 // ARM_DEBUG_STATE64 + }; + + enum + { + GPRWordCount = sizeof(GPR)/sizeof(uint32_t), // ARM_THREAD_STATE64_COUNT + FPUWordCount = sizeof(FPU)/sizeof(uint32_t), // ARM_NEON_STATE64_COUNT + EXCWordCount = sizeof(EXC)/sizeof(uint32_t), // ARM_EXCEPTION_STATE64_COUNT + DBGWordCount = sizeof(DBG)/sizeof(uint32_t) // ARM_DEBUG_STATE64_COUNT + }; + + enum + { + Read = 0, + Write = 1, + kNumErrors = 2 + }; + + GPR gpr; + FPU fpu; + EXC exc; + DBG dbg; + int gpr_errs[2]; // Read/Write errors + int fpu_errs[2]; // Read/Write errors + int exc_errs[2]; // Read/Write errors + int dbg_errs[2]; // Read/Write errors + + void + InvalidateAllRegisterStates() + { + SetError (GPRRegSet, Read, -1); + SetError (FPURegSet, Read, -1); + SetError (EXCRegSet, Read, -1); + } + + int + GetError (int flavor, uint32_t err_idx) const + { + if (err_idx < kNumErrors) + { + switch (flavor) + { + // When getting all errors, just OR all values together to see if + // we got any kind of error. + case GPRRegSet: return gpr_errs[err_idx]; + case FPURegSet: return fpu_errs[err_idx]; + case EXCRegSet: return exc_errs[err_idx]; + case DBGRegSet: return dbg_errs[err_idx]; + default: break; + } + } + return -1; + } + + bool + SetError (int flavor, uint32_t err_idx, int err) + { + if (err_idx < kNumErrors) + { + switch (flavor) + { + case GPRRegSet: + gpr_errs[err_idx] = err; + return true; + + case FPURegSet: + fpu_errs[err_idx] = err; + return true; + + case EXCRegSet: + exc_errs[err_idx] = err; + return true; + + case DBGRegSet: + exc_errs[err_idx] = err; + return true; + + default: break; + } + } + return false; + } + + bool + RegisterSetIsCached (int set) const + { + return GetError(set, Read) == 0; + } + + int + ReadGPR (bool force); + + int + ReadFPU (bool force); + + int + ReadEXC (bool force); + + int + ReadDBG (bool force); + + int + WriteGPR (); + + int + WriteFPU (); + + int + WriteEXC (); + + int + WriteDBG (); + + + // Subclasses override these to do the actual reading. + virtual int + DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) + { + return -1; + } + + virtual int + DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0; + + virtual int + DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0; + + virtual int + DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) = 0; + + virtual int + DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0; + + virtual int + DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0; + + virtual int + DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0; + + virtual int + DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) = 0; + + int + ReadRegisterSet (uint32_t set, bool force); + + int + WriteRegisterSet (uint32_t set); + + static uint32_t + GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num); + + static int + GetSetForNativeRegNum (int reg_num); + + static size_t + GetRegisterInfosCount (); + + static const lldb_private::RegisterInfo * + GetRegisterInfos (); +}; + +#endif // liblldb_RegisterContextDarwin_arm64_h_ diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp index a94d1f538a28..08144bf7ec26 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Host/Endian.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" // Support building against older versions of LLVM, this macro was added @@ -281,7 +282,7 @@ static RegisterInfo g_register_infos[] = { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL} }; -static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo)); +static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos); void RegisterContextDarwin_i386::InvalidateAllRegisters () @@ -384,9 +385,9 @@ g_exc_regnums[] = }; // Number of registers in each register set -const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t); -const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t); -const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t); +const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums); +const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); +const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); //---------------------------------------------------------------------- // Register set definitions. The first definitions at register set index @@ -400,7 +401,7 @@ static const RegisterSet g_reg_sets[] = { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums } }; -const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet); +const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets); size_t @@ -843,7 +844,7 @@ RegisterContextDarwin_i386::WriteAllRegisterValues (const lldb::DataBufferSP &da uint32_t -RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg) +RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg) { if (kind == eRegisterKindGeneric) { diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h index a588494f9dcf..1d03feb9f3dd 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h @@ -55,7 +55,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); virtual bool HardwareSingleStep (bool enable); diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp index 433782fe20c0..54124d187d54 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp @@ -9,6 +9,7 @@ // C Includes +#include <inttypes.h> // PRIx64 #include <stdarg.h> #include <stddef.h> // offsetof @@ -20,6 +21,7 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Host/Endian.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" // Support building against older versions of LLVM, this macro was added @@ -317,7 +319,7 @@ static RegisterInfo g_register_infos[] = { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL} }; -static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo)); +static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos); void @@ -431,9 +433,9 @@ g_exc_regnums[] = }; // Number of registers in each register set -const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t); -const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t); -const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t); +const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums); +const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); +const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); //---------------------------------------------------------------------- // Register set definitions. The first definitions at register set index @@ -447,7 +449,7 @@ static const RegisterSet g_reg_sets[] = { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums } }; -const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet); +const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets); size_t @@ -902,7 +904,7 @@ RegisterContextDarwin_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP & uint32_t -RegisterContextDarwin_x86_64::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg) +RegisterContextDarwin_x86_64::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg) { if (kind == eRegisterKindGeneric) { diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h index 4b8127af997c..09e35e9c423e 100644 --- a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h +++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h @@ -54,7 +54,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); virtual bool HardwareSingleStep (bool enable); diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/source/Plugins/Process/Utility/RegisterContextDummy.cpp index 1e282ce74f2e..329b0a7968a2 100644 --- a/source/Plugins/Process/Utility/RegisterContextDummy.cpp +++ b/source/Plugins/Process/Utility/RegisterContextDummy.cpp @@ -129,7 +129,7 @@ RegisterContextDummy::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) } uint32_t -RegisterContextDummy::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextDummy::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC) return 0; diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.h b/source/Plugins/Process/Utility/RegisterContextDummy.h index ee8d5a134bbc..ddf466713048 100644 --- a/source/Plugins/Process/Utility/RegisterContextDummy.h +++ b/source/Plugins/Process/Utility/RegisterContextDummy.h @@ -60,7 +60,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); private: //------------------------------------------------------------------ diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp index 01c9bb4cde8f..185ba26944fe 100644 --- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp @@ -62,27 +62,27 @@ RegisterContextFreeBSD_i386::RegisterContextFreeBSD_i386(const ArchSpec &target_ { } -RegisterContextFreeBSD_i386::~RegisterContextFreeBSD_i386() -{ -} - size_t -RegisterContextFreeBSD_i386::GetGPRSize() +RegisterContextFreeBSD_i386::GetGPRSize() const { return sizeof(GPR); } const RegisterInfo * -RegisterContextFreeBSD_i386::GetRegisterInfo() +RegisterContextFreeBSD_i386::GetRegisterInfo() const { - switch (m_target_arch.GetCore()) + switch (m_target_arch.GetMachine()) { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: + case llvm::Triple::x86: return g_register_infos_i386; default: assert(false && "Unhandled target architecture."); return NULL; } } + +uint32_t +RegisterContextFreeBSD_i386::GetRegisterCount () const +{ + return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0])); +} diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h index 4ec2ad3e9706..62792c02e2b9 100644 --- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.h +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h @@ -13,17 +13,19 @@ #include "RegisterContextPOSIX.h" class RegisterContextFreeBSD_i386 - : public RegisterInfoInterface + : public lldb_private::RegisterInfoInterface { public: RegisterContextFreeBSD_i386(const lldb_private::ArchSpec &target_arch); - virtual ~RegisterContextFreeBSD_i386(); size_t - GetGPRSize(); + GetGPRSize() const override; const lldb_private::RegisterInfo * - GetRegisterInfo(); + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; }; #endif diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp index 4714251fd2dc..c31b0ee7de53 100644 --- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp @@ -71,20 +71,23 @@ RegisterContextFreeBSD_mips64::RegisterContextFreeBSD_mips64(const ArchSpec &tar { } -RegisterContextFreeBSD_mips64::~RegisterContextFreeBSD_mips64() -{ -} - size_t -RegisterContextFreeBSD_mips64::GetGPRSize() +RegisterContextFreeBSD_mips64::GetGPRSize() const { return sizeof(GPR); } const RegisterInfo * -RegisterContextFreeBSD_mips64::GetRegisterInfo() +RegisterContextFreeBSD_mips64::GetRegisterInfo() const { assert (m_target_arch.GetCore() == ArchSpec::eCore_mips64); return g_register_infos_mips64; } +uint32_t +RegisterContextFreeBSD_mips64::GetRegisterCount () const +{ + return static_cast<uint32_t> (sizeof (g_register_infos_mips64) / sizeof (g_register_infos_mips64 [0])); +} + + diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h index 9ee767955347..f9a3ce09c5b1 100644 --- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.h +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h @@ -13,17 +13,19 @@ #include "RegisterContextPOSIX.h" class RegisterContextFreeBSD_mips64: - public RegisterInfoInterface + public lldb_private::RegisterInfoInterface { public: RegisterContextFreeBSD_mips64(const lldb_private::ArchSpec &target_arch); - virtual ~RegisterContextFreeBSD_mips64(); size_t - GetGPRSize(); + GetGPRSize() const override; const lldb_private::RegisterInfo * - GetRegisterInfo(); + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; }; #endif diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp index 2162aaffff18..257de7198590 100644 --- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp @@ -67,10 +67,17 @@ struct dbreg { #include "RegisterInfos_x86_64.h" #undef DECLARE_REGISTER_INFOS_X86_64_STRUCT +static std::vector<lldb_private::RegisterInfo>& +GetSharedRegisterInfoVector () +{ + static std::vector<lldb_private::RegisterInfo> register_infos; + return register_infos; +} + static const RegisterInfo * GetRegisterInfo_i386(const lldb_private::ArchSpec& arch) { - static std::vector<lldb_private::RegisterInfo> g_register_infos; + static std::vector<lldb_private::RegisterInfo> g_register_infos (GetSharedRegisterInfoVector ()); // Allocate RegisterInfo only once if (g_register_infos.empty()) @@ -92,35 +99,61 @@ GetRegisterInfo_i386(const lldb_private::ArchSpec& arch) return &g_register_infos[0]; } -RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) : - RegisterInfoInterface(target_arch) +static const RegisterInfo * +PrivateGetRegisterInfoPtr (const lldb_private::ArchSpec& target_arch) { + switch (target_arch.GetMachine()) + { + case llvm::Triple::x86: + return GetRegisterInfo_i386 (target_arch); + case llvm::Triple::x86_64: + return g_register_infos_x86_64; + default: + assert(false && "Unhandled target architecture."); + return nullptr; + } } -RegisterContextFreeBSD_x86_64::~RegisterContextFreeBSD_x86_64() +static uint32_t +PrivateGetRegisterCount (const lldb_private::ArchSpec& target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::x86: + // This vector should have already been filled. + assert (!GetSharedRegisterInfoVector ().empty () && "i386 register info vector not filled."); + return static_cast<uint32_t> (GetSharedRegisterInfoVector().size ()); + case llvm::Triple::x86_64: + return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) : + lldb_private::RegisterInfoInterface(target_arch), + m_register_info_p (PrivateGetRegisterInfoPtr (target_arch)), + m_register_count (PrivateGetRegisterCount (target_arch)) { } size_t -RegisterContextFreeBSD_x86_64::GetGPRSize() +RegisterContextFreeBSD_x86_64::GetGPRSize() const { return sizeof(GPR); } const RegisterInfo * -RegisterContextFreeBSD_x86_64::GetRegisterInfo() +RegisterContextFreeBSD_x86_64::GetRegisterInfo() const { - switch (m_target_arch.GetCore()) - { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - return GetRegisterInfo_i386 (m_target_arch); - case ArchSpec::eCore_x86_64_x86_64: - return g_register_infos_x86_64; - default: - assert(false && "Unhandled target architecture."); - return NULL; - } + return m_register_info_p; +} + +uint32_t +RegisterContextFreeBSD_x86_64::GetRegisterCount () const +{ + return m_register_count; } + diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h index 731bb0ea6bcc..21fbdb4681b3 100644 --- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h @@ -13,17 +13,23 @@ #include "RegisterContextPOSIX.h" class RegisterContextFreeBSD_x86_64: - public RegisterInfoInterface + public lldb_private::RegisterInfoInterface { public: RegisterContextFreeBSD_x86_64(const lldb_private::ArchSpec &target_arch); - virtual ~RegisterContextFreeBSD_x86_64(); size_t - GetGPRSize(); + GetGPRSize() const override; const lldb_private::RegisterInfo * - GetRegisterInfo(); + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + const uint32_t m_register_count; }; #endif diff --git a/source/Plugins/Process/Utility/RegisterContextHistory.cpp b/source/Plugins/Process/Utility/RegisterContextHistory.cpp index b7adb202ba49..3c370103629e 100644 --- a/source/Plugins/Process/Utility/RegisterContextHistory.cpp +++ b/source/Plugins/Process/Utility/RegisterContextHistory.cpp @@ -130,7 +130,7 @@ RegisterContextHistory::WriteAllRegisterValues (const lldb::DataBufferSP &data_s } uint32_t -RegisterContextHistory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextHistory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC) return 0; diff --git a/source/Plugins/Process/Utility/RegisterContextHistory.h b/source/Plugins/Process/Utility/RegisterContextHistory.h index 58e16080b52e..04842c62aff1 100644 --- a/source/Plugins/Process/Utility/RegisterContextHistory.h +++ b/source/Plugins/Process/Utility/RegisterContextHistory.h @@ -60,7 +60,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); private: //------------------------------------------------------------------ diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index f209d538a712..b58e6bb607ed 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -163,15 +163,17 @@ RegisterContextLLDB::InitializeZerothFrame() UnwindLogMsg ("using architectural default unwind method"); } - // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us. + // We require either a symbol or function in the symbols context to be successfully + // filled in or this context is of no use to us. + const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; if (pc_module_sp.get() - && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, resolve_scope, m_sym_ctx) & resolve_scope)) { m_sym_ctx_valid = true; } AddressRange addr_range; - m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range); + m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range); if (IsTrapHandlerSymbol (process, m_sym_ctx)) { @@ -216,7 +218,7 @@ RegisterContextLLDB::InitializeZerothFrame() UnwindPlan::RowSP active_row; int cfa_offset = 0; - int row_register_kind = -1; + lldb::RegisterKind row_register_kind = eRegisterKindGeneric; if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc)) { active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); @@ -362,7 +364,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() m_current_offset = -1; m_current_offset_backed_up_one = -1; addr_t cfa_regval = LLDB_INVALID_ADDRESS; - int row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); + RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0); if (row.get()) { @@ -417,18 +419,20 @@ RegisterContextLLDB::InitializeNonZerothFrame() // a function/symbol because it is beyond the bounds of the correct // function and there's no symbol there. ResolveSymbolContextForAddress // will fail to find a symbol, back up the pc by 1 and re-search. + const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, - eSymbolContextFunction | eSymbolContextSymbol, + resolve_scope, m_sym_ctx, resolve_tail_call_address); - // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us. - if ((resolved_scope & eSymbolContextSymbol) == eSymbolContextSymbol) + // We require either a symbol or function in the symbols context to be successfully + // filled in or this context is of no use to us. + if (resolve_scope & resolved_scope) { m_sym_ctx_valid = true; } AddressRange addr_range; - if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) + if (!m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range)) { m_sym_ctx_valid = false; } @@ -461,13 +465,12 @@ RegisterContextLLDB::InitializeNonZerothFrame() temporary_pc.SetOffset(m_current_pc.GetOffset() - 1); m_sym_ctx.Clear(false); m_sym_ctx_valid = false; - if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; + + if (pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope) { - m_sym_ctx_valid = true; - } - if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) - { - m_sym_ctx_valid = false; + if (m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range)) + m_sym_ctx_valid = true; } } @@ -510,7 +513,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() UnwindPlan::RowSP active_row; int cfa_offset = 0; - int row_register_kind = -1; + RegisterKind row_register_kind = eRegisterKindGeneric; // Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get // (e.g. if we have to parse the entire eh_frame section of an ObjectFile for the first time.) @@ -591,7 +594,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() repeating_frames = true; } } - if (repeating_frames && abi->FunctionCallsChangeCFA()) + if (repeating_frames && abi && abi->FunctionCallsChangeCFA()) { UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping"); m_frame_type = eNotAValidFrame; @@ -707,7 +710,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // Note, if we have a symbol context & a symbol, we don't want to follow this code path. This is // for jumping to memory regions without any information available. - if ((!m_sym_ctx_valid || m_sym_ctx.symbol == NULL) && behaves_like_zeroth_frame && m_current_pc.IsValid()) + if ((!m_sym_ctx_valid || (m_sym_ctx.function == NULL && m_sym_ctx.symbol == NULL)) && behaves_like_zeroth_frame && m_current_pc.IsValid()) { uint32_t permissions; addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()); @@ -791,7 +794,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions if (behaves_like_zeroth_frame) { - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); + 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)) { if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) @@ -819,8 +822,8 @@ 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 (m_thread); - if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) + 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 // don't have any eh_frame instructions available. @@ -889,7 +892,7 @@ RegisterContextLLDB::GetRegisterSet (size_t reg_set) } uint32_t -RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num); } @@ -1415,7 +1418,7 @@ RegisterContextLLDB::TryFallbackUnwindPlan () // where frame 0 (the "next" frame) saved that and retrieve the value. bool -RegisterContextLLDB::ReadGPRValue (int register_kind, uint32_t regnum, addr_t &value) +RegisterContextLLDB::ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, addr_t &value) { if (!IsValid()) return false; diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h index 0a60bfe382b5..d6ecfeb68caa 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -67,7 +67,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); bool IsValid () const; @@ -178,7 +178,7 @@ private: // Get the contents of a general purpose (address-size) register for this frame // (usually retrieved from the next frame) bool - ReadGPRValue (int register_kind, uint32_t regnum, lldb::addr_t &value); + ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, lldb::addr_t &value); lldb::UnwindPlanSP GetFastUnwindPlanForFrame (); diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp new file mode 100644 index 000000000000..8c23e39ff013 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp @@ -0,0 +1,89 @@ +//===-- RegisterContextLinux_arm64.cpp -------------------------*- 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> +#include <vector> +#include <cassert> + +#include "llvm/Support/Compiler.h" +#include "lldb/lldb-defines.h" + +#include "RegisterContextLinux_arm64.h" + +// Based on RegisterContextDarwin_arm64.cpp +#define GPR_OFFSET(idx) ((idx) * 8) +#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::GPR, reg)) + +#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextLinux_arm64::GPR)) +#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::FPU, reg)) + +#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::EXC, reg) + sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU)) +#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::DBG, reg) + sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU) + sizeof (RegisterContextLinux_arm64::EXC)) + +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define REG_CONTEXT_SIZE (sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU) + sizeof (RegisterContextLinux_arm64::EXC)) + + +//----------------------------------------------------------------------------- +// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. +//----------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_ARM64_STRUCT +#include "RegisterInfos_arm64.h" +#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT + +static const lldb_private::RegisterInfo * +GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + return g_register_infos_arm64; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } +} + +static uint32_t +GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + return static_cast<uint32_t>(sizeof(g_register_infos_arm64) / sizeof(g_register_infos_arm64[0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextLinux_arm64::RegisterContextLinux_arm64(const lldb_private::ArchSpec &target_arch) : + lldb_private::RegisterInfoInterface(target_arch), + m_register_info_p(GetRegisterInfoPtr(target_arch)), + m_register_info_count(GetRegisterInfoCount(target_arch)) +{ +} + +size_t +RegisterContextLinux_arm64::GetGPRSize() const +{ + return sizeof(struct RegisterContextLinux_arm64::GPR); +} + +const lldb_private::RegisterInfo * +RegisterContextLinux_arm64::GetRegisterInfo() const +{ + return m_register_info_p; +} + +uint32_t +RegisterContextLinux_arm64::GetRegisterCount() const +{ + return m_register_info_count; +} diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h b/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h new file mode 100644 index 000000000000..a9a5a0985f25 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h @@ -0,0 +1,81 @@ +//===-- RegisterContextLinux_arm64.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextLinux_arm64_H_ +#define liblldb_RegisterContextLinux_arm64_H_ + +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" +#include "RegisterContextPOSIX.h" +#include "RegisterInfoInterface.h" + +class RegisterContextLinux_arm64 + : public lldb_private::RegisterInfoInterface +{ +public: + // based on RegisterContextDarwin_arm64.h + struct GPR + { + uint64_t x[29]; // x0-x28 + uint64_t fp; // x29 + uint64_t lr; // x30 + uint64_t sp; // x31 + uint64_t pc; // pc + uint32_t cpsr; // cpsr + }; + + // based on RegisterContextDarwin_arm64.h + struct VReg + { + uint8_t bytes[16]; + }; + + // based on RegisterContextDarwin_arm64.h + struct FPU + { + VReg v[32]; + uint32_t fpsr; + uint32_t fpcr; + }; + + // based on RegisterContextDarwin_arm64.h + struct EXC + { + uint64_t far; // Virtual Fault Address + uint32_t esr; // Exception syndrome + uint32_t exception; // number of arm exception token + }; + + // based on RegisterContextDarwin_arm64.h + struct DBG + { + uint64_t bvr[16]; + uint64_t bcr[16]; + uint64_t wvr[16]; + uint64_t wcr[16]; + uint64_t mdscr_el1; + }; + + RegisterContextLinux_arm64(const lldb_private::ArchSpec &target_arch); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + uint32_t m_register_info_count; +}; + +#endif diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_i386.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp index 0828efbc6c3c..b9b9dca07be4 100644 --- a/source/Plugins/Process/POSIX/RegisterContextLinux_i386.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp @@ -34,11 +34,39 @@ struct GPR uint32_t ss; }; +struct FPR_i386 +{ + uint16_t fctrl; // FPU Control Word (fcw) + uint16_t fstat; // FPU Status Word (fsw) + uint16_t ftag; // FPU Tag Word (ftw) + uint16_t fop; // Last Instruction Opcode (fop) + union + { + struct + { + uint64_t fip; // Instruction Pointer + uint64_t fdp; // Data Pointer + } x86_64; + struct + { + uint32_t fioff; // FPU IP Offset (fip) + uint32_t fiseg; // FPU IP Selector (fcs) + uint32_t fooff; // FPU Operand Pointer Offset (foo) + uint32_t foseg; // FPU Operand Pointer Selector (fos) + } i386_;// Added _ in the end to avoid error with gcc defining i386 in some cases + } ptr; + uint32_t mxcsr; // MXCSR Register State + uint32_t mxcsrmask; // MXCSR Mask + MMSReg stmm[8]; // 8*16 bytes for each FP-reg = 128 bytes + XMMReg xmm[8]; // 8*16 bytes for each XMM-reg = 128 bytes + uint32_t padding[56]; +}; + struct UserArea { GPR regs; // General purpose registers. int32_t fpvalid; // True if FPU is being used. - FXSAVE i387; // FPU registers. + FPR_i386 i387; // FPU registers. uint32_t tsize; // Text segment size. uint32_t dsize; // Data segment size. uint32_t ssize; // Stack segment size. @@ -54,9 +82,11 @@ struct UserArea uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7). }; -#define DR_SIZE sizeof(UserArea::u_debugreg[0]) +#define DR_SIZE sizeof(((UserArea*)NULL)->u_debugreg[0]) +#define DR_0_OFFSET 0xFC #define DR_OFFSET(reg_index) \ - (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index])) + (DR_0_OFFSET + (reg_index * 4)) +#define FPR_SIZE(reg) sizeof(((FPR_i386*)NULL)->reg) //--------------------------------------------------------------------------- // Include RegisterInfos_i386 to declare our g_register_infos_i386 structure. @@ -70,27 +100,28 @@ RegisterContextLinux_i386::RegisterContextLinux_i386(const ArchSpec &target_arch { } -RegisterContextLinux_i386::~RegisterContextLinux_i386() -{ -} - size_t -RegisterContextLinux_i386::GetGPRSize() +RegisterContextLinux_i386::GetGPRSize() const { return sizeof(GPR); } const RegisterInfo * -RegisterContextLinux_i386::GetRegisterInfo() +RegisterContextLinux_i386::GetRegisterInfo() const { - switch (m_target_arch.GetCore()) + switch (m_target_arch.GetMachine()) { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: + case llvm::Triple::x86: return g_register_infos_i386; default: assert(false && "Unhandled target architecture."); return NULL; } } + +uint32_t +RegisterContextLinux_i386::GetRegisterCount () const +{ + return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0])); +} + diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_i386.h b/source/Plugins/Process/Utility/RegisterContextLinux_i386.h index 81afdbf8b1cf..f8b21fc8e87d 100644 --- a/source/Plugins/Process/POSIX/RegisterContextLinux_i386.h +++ b/source/Plugins/Process/Utility/RegisterContextLinux_i386.h @@ -13,17 +13,19 @@ #include "RegisterContextPOSIX.h" class RegisterContextLinux_i386 - : public RegisterInfoInterface + : public lldb_private::RegisterInfoInterface { public: RegisterContextLinux_i386(const lldb_private::ArchSpec &target_arch); - virtual ~RegisterContextLinux_i386(); size_t - GetGPRSize(); + GetGPRSize() const override; const lldb_private::RegisterInfo * - GetRegisterInfo(); + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; }; #endif diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp index 5434ddfcf38b..74f016bd744d 100644 --- a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp @@ -69,7 +69,7 @@ struct UserArea uint64_t fault_address; // Control register CR3. }; -#define DR_SIZE sizeof(UserArea::u_debugreg[0]) +#define DR_SIZE sizeof(((UserArea*)NULL)->u_debugreg[0]) #define DR_OFFSET(reg_index) \ (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index])) @@ -80,10 +80,17 @@ struct UserArea #include "RegisterInfos_x86_64.h" #undef DECLARE_REGISTER_INFOS_X86_64_STRUCT +static std::vector<lldb_private::RegisterInfo>& +GetPrivateRegisterInfoVector () +{ + static std::vector<lldb_private::RegisterInfo> g_register_infos; + return g_register_infos; +} + static const RegisterInfo * GetRegisterInfo_i386(const lldb_private::ArchSpec &arch) { - static std::vector<lldb_private::RegisterInfo> g_register_infos; + std::vector<lldb_private::RegisterInfo> &g_register_infos = GetPrivateRegisterInfoVector (); // Allocate RegisterInfo only once if (g_register_infos.empty()) @@ -105,35 +112,60 @@ GetRegisterInfo_i386(const lldb_private::ArchSpec &arch) return &g_register_infos[0]; } -RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) : - RegisterInfoInterface(target_arch) +static const RegisterInfo * +GetRegisterInfoPtr (const ArchSpec &target_arch) { + switch (target_arch.GetMachine()) + { + case llvm::Triple::x86: + return GetRegisterInfo_i386 (target_arch); + case llvm::Triple::x86_64: + return g_register_infos_x86_64; + default: + assert(false && "Unhandled target architecture."); + return nullptr; + } } -RegisterContextLinux_x86_64::~RegisterContextLinux_x86_64() +static uint32_t +GetRegisterInfoCount (const ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::x86: + { + assert (!GetPrivateRegisterInfoVector ().empty () && "i386 register info not yet filled."); + return static_cast<uint32_t> (GetPrivateRegisterInfoVector ().size ()); + } + case llvm::Triple::x86_64: + return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) : + lldb_private::RegisterInfoInterface(target_arch), + m_register_info_p (GetRegisterInfoPtr (target_arch)), + m_register_info_count (GetRegisterInfoCount (target_arch)) { } size_t -RegisterContextLinux_x86_64::GetGPRSize() +RegisterContextLinux_x86_64::GetGPRSize() const { return sizeof(GPR); } const RegisterInfo * -RegisterContextLinux_x86_64::GetRegisterInfo() +RegisterContextLinux_x86_64::GetRegisterInfo() const { - switch (m_target_arch.GetCore()) - { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - return GetRegisterInfo_i386 (m_target_arch); - case ArchSpec::eCore_x86_64_x86_64: - return g_register_infos_x86_64; - default: - assert(false && "Unhandled target architecture."); - return NULL; - } + return m_register_info_p; } +uint32_t +RegisterContextLinux_x86_64::GetRegisterCount () const +{ + return m_register_info_count; +} diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h index 21c809b5dc33..7b6828661c1e 100644 --- a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h +++ b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h @@ -13,17 +13,23 @@ #include "RegisterContextPOSIX.h" class RegisterContextLinux_x86_64 - : public RegisterInfoInterface + : public lldb_private::RegisterInfoInterface { public: RegisterContextLinux_x86_64(const lldb_private::ArchSpec &target_arch); - virtual ~RegisterContextLinux_x86_64(); size_t - GetGPRSize(); + GetGPRSize() const override; const lldb_private::RegisterInfo * - GetRegisterInfo(); + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + uint32_t m_register_info_count; }; #endif diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp index 5b6d9fe9f3bb..e246e715de86 100644 --- a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp +++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp @@ -149,7 +149,7 @@ 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(_MSC_VER) && !defined(__mips__) +#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) && !defined(_MSC_VER) && !defined(__mips__) case sizeof (long double): if (sizeof (long double) == sizeof(uint32_t)) { @@ -199,7 +199,7 @@ RegisterContextMacOSXFrameBackchain::WriteAllRegisterValues (const lldb::DataBuf uint32_t -RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num); } diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h index 449e053e5ef1..505b8d44a27a 100644 --- a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h +++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h @@ -63,7 +63,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); private: UnwindMacOSXFrameBackchain::Cursor m_cursor; diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/source/Plugins/Process/Utility/RegisterContextMemory.cpp index 8c33a6814acc..40d00b1eed80 100644 --- a/source/Plugins/Process/Utility/RegisterContextMemory.cpp +++ b/source/Plugins/Process/Utility/RegisterContextMemory.cpp @@ -98,7 +98,7 @@ RegisterContextMemory::GetRegisterSet (size_t reg_set) } uint32_t -RegisterContextMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextMemory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { return m_reg_infos.ConvertRegisterKindToRegisterNumber (kind, num); } diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.h b/source/Plugins/Process/Utility/RegisterContextMemory.h index 8bba52c627f3..9d97dfa723be 100644 --- a/source/Plugins/Process/Utility/RegisterContextMemory.h +++ b/source/Plugins/Process/Utility/RegisterContextMemory.h @@ -55,7 +55,7 @@ public: GetRegisterSet (size_t reg_set); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); //------------------------------------------------------------------ diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX.h b/source/Plugins/Process/Utility/RegisterContextPOSIX.h index 600dae73b5b7..6ddd9cfe4c21 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIX.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX.h @@ -15,6 +15,7 @@ // Other libraries and framework includes #include "lldb/Core/ArchSpec.h" #include "lldb/Target/RegisterContext.h" +#include "RegisterInfoInterface.h" //------------------------------------------------------------------------------ /// @class POSIXBreakpointProtocol @@ -74,25 +75,5 @@ protected: bool m_watchpoints_initialized; }; -//------------------------------------------------------------------------------ -/// @class RegisterInfoInterface -/// -/// @brief RegisterInfo interface to patch RegisterInfo structure for archs. -class RegisterInfoInterface -{ -public: - RegisterInfoInterface(const lldb_private::ArchSpec& target_arch) : m_target_arch(target_arch) {} - virtual ~RegisterInfoInterface () {} - - virtual size_t - GetGPRSize () = 0; - - virtual const lldb_private::RegisterInfo * - GetRegisterInfo () = 0; - -public: - lldb_private::ArchSpec m_target_arch; -}; - #endif // #ifndef liblldb_RegisterContextPOSIX_H_ diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp new file mode 100644 index 000000000000..ea54a9ad9cf4 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -0,0 +1,299 @@ +//===-- RegisterContextPOSIX_arm64.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_arm64.h" +#include "Plugins/Process/elf-core/ProcessElfCore.h" + +// ARM64 general purpose registers. +const uint32_t g_gpr_regnums_arm64[] = +{ + gpr_x0_arm64, + gpr_x1_arm64, + gpr_x2_arm64, + gpr_x3_arm64, + gpr_x4_arm64, + gpr_x5_arm64, + gpr_x6_arm64, + gpr_x7_arm64, + gpr_x8_arm64, + gpr_x9_arm64, + gpr_x10_arm64, + gpr_x11_arm64, + gpr_x12_arm64, + gpr_x13_arm64, + gpr_x14_arm64, + gpr_x15_arm64, + gpr_x16_arm64, + gpr_x17_arm64, + gpr_x18_arm64, + gpr_x19_arm64, + gpr_x20_arm64, + gpr_x21_arm64, + gpr_x22_arm64, + gpr_x23_arm64, + gpr_x24_arm64, + gpr_x25_arm64, + gpr_x26_arm64, + gpr_x27_arm64, + gpr_x28_arm64, + gpr_fp_arm64, + gpr_lr_arm64, + gpr_sp_arm64, + gpr_pc_arm64, + gpr_cpsr_arm64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \ + "g_gpr_regnums_arm64 has wrong number of register infos"); + +// ARM64 floating point registers. +static const uint32_t g_fpu_regnums_arm64[] = +{ + fpu_v0_arm64, + fpu_v1_arm64, + fpu_v2_arm64, + fpu_v3_arm64, + fpu_v4_arm64, + fpu_v5_arm64, + fpu_v6_arm64, + fpu_v7_arm64, + fpu_v8_arm64, + fpu_v9_arm64, + fpu_v10_arm64, + fpu_v11_arm64, + fpu_v12_arm64, + fpu_v13_arm64, + fpu_v14_arm64, + fpu_v15_arm64, + fpu_v16_arm64, + fpu_v17_arm64, + fpu_v18_arm64, + fpu_v19_arm64, + fpu_v20_arm64, + fpu_v21_arm64, + fpu_v22_arm64, + fpu_v23_arm64, + fpu_v24_arm64, + fpu_v25_arm64, + fpu_v26_arm64, + fpu_v27_arm64, + fpu_v28_arm64, + fpu_v29_arm64, + fpu_v30_arm64, + fpu_v31_arm64, + fpu_fpsr_arm64, + fpu_fpcr_arm64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \ + "g_fpu_regnums_arm64 has wrong number of register infos"); + +// Number of register sets provided by this context. +enum +{ + k_num_register_sets = 2 +}; + +// Register sets for ARM64. +static const lldb_private::RegisterSet +g_reg_sets_arm64[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 } +}; + +bool RegisterContextPOSIX_arm64::IsGPR(unsigned reg) +{ + return reg <= m_reg_info.last_gpr; // GPR's come first. +} + +bool RegisterContextPOSIX_arm64::IsFPR(unsigned reg) +{ + return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); +} + +RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : lldb_private::RegisterContext(thread, concrete_frame_idx) +{ + m_register_info_ap.reset(register_info); + + switch (register_info->m_target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + m_reg_info.num_registers = k_num_registers_arm64; + m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64; + m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64; + m_reg_info.last_gpr = k_last_gpr_arm64; + m_reg_info.first_fpr = k_first_fpr_arm64; + m_reg_info.last_fpr = k_last_fpr_arm64; + m_reg_info.first_fpr_v = fpu_v0_arm64; + m_reg_info.last_fpr_v = fpu_v31_arm64; + m_reg_info.gpr_flags = gpr_cpsr_arm64; + break; + default: + assert(false && "Unhandled target architecture."); + break; + } + + ::memset(&m_fpr, 0, sizeof m_fpr); + + // elf-core yet to support ReadFPR() + lldb::ProcessSP base = CalculateProcess(); + if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) + return; +} + +RegisterContextPOSIX_arm64::~RegisterContextPOSIX_arm64() +{ +} + +void +RegisterContextPOSIX_arm64::Invalidate() +{ +} + +void +RegisterContextPOSIX_arm64::InvalidateAllRegisters() +{ +} + +unsigned +RegisterContextPOSIX_arm64::GetRegisterOffset(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_offset; +} + +unsigned +RegisterContextPOSIX_arm64::GetRegisterSize(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_size; +} + +size_t +RegisterContextPOSIX_arm64::GetRegisterCount() +{ + size_t num_registers = m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers; + return num_registers; +} + +size_t +RegisterContextPOSIX_arm64::GetGPRSize() +{ + return m_register_info_ap->GetGPRSize (); +} + +const lldb_private::RegisterInfo * +RegisterContextPOSIX_arm64::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 lldb_private::RegisterInfo * +RegisterContextPOSIX_arm64::GetRegisterInfoAtIndex(size_t reg) +{ + if (reg < m_reg_info.num_registers) + return &GetRegisterInfo()[reg]; + else + return NULL; +} + +size_t +RegisterContextPOSIX_arm64::GetRegisterSetCount() +{ + size_t sets = 0; + for (size_t set = 0; set < k_num_register_sets; ++set) + { + if (IsRegisterSetAvailable(set)) + ++sets; + } + + return sets; +} + +const lldb_private::RegisterSet * +RegisterContextPOSIX_arm64::GetRegisterSet(size_t set) +{ + if (IsRegisterSetAvailable(set)) + { + switch (m_register_info_ap->m_target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + return &g_reg_sets_arm64[set]; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } + } + return NULL; +} + +const char * +RegisterContextPOSIX_arm64::GetRegisterName(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register offset."); + return GetRegisterInfo()[reg].name; +} + +lldb::ByteOrder +RegisterContextPOSIX_arm64::GetByteOrder() +{ + // Get the target process whose privileged thread was used for the register read. + lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; + lldb_private::Process *process = CalculateProcess().get(); + + if (process) + byte_order = process->GetByteOrder(); + return byte_order; +} + +bool +RegisterContextPOSIX_arm64::IsRegisterSetAvailable(size_t set_index) +{ + return set_index < k_num_register_sets; +} + + +// Used when parsing DWARF and EH frame information and any other +// object file sections that contain register numbers in them. +uint32_t +RegisterContextPOSIX_arm64::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) +{ + const uint32_t num_regs = GetRegisterCount(); + + assert (kind < lldb::kNumRegisterKinds); + for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) + { + const lldb_private::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_arm64.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h new file mode 100644 index 000000000000..3639960ef3de --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h @@ -0,0 +1,272 @@ +//===-- RegisterContextPOSIX_arm64.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIX_arm64_H_ +#define liblldb_RegisterContextPOSIX_arm64_H_ + +#include "lldb/Core/Log.h" +#include "RegisterContextPOSIX.h" + +class ProcessMonitor; + +//--------------------------------------------------------------------------- +// Internal codes for all ARM64 registers. +//--------------------------------------------------------------------------- +enum +{ + k_first_gpr_arm64, + gpr_x0_arm64 = k_first_gpr_arm64, + gpr_x1_arm64, + gpr_x2_arm64, + gpr_x3_arm64, + gpr_x4_arm64, + gpr_x5_arm64, + gpr_x6_arm64, + gpr_x7_arm64, + gpr_x8_arm64, + gpr_x9_arm64, + gpr_x10_arm64, + gpr_x11_arm64, + gpr_x12_arm64, + gpr_x13_arm64, + gpr_x14_arm64, + gpr_x15_arm64, + gpr_x16_arm64, + gpr_x17_arm64, + gpr_x18_arm64, + gpr_x19_arm64, + gpr_x20_arm64, + gpr_x21_arm64, + gpr_x22_arm64, + gpr_x23_arm64, + gpr_x24_arm64, + gpr_x25_arm64, + gpr_x26_arm64, + gpr_x27_arm64, + gpr_x28_arm64, + gpr_fp_arm64, + gpr_lr_arm64, + gpr_sp_arm64, + gpr_pc_arm64, + gpr_cpsr_arm64, + + k_last_gpr_arm64 = gpr_cpsr_arm64, + + k_first_fpr_arm64, + fpu_v0_arm64 = k_first_fpr_arm64, + fpu_v1_arm64, + fpu_v2_arm64, + fpu_v3_arm64, + fpu_v4_arm64, + fpu_v5_arm64, + fpu_v6_arm64, + fpu_v7_arm64, + fpu_v8_arm64, + fpu_v9_arm64, + fpu_v10_arm64, + fpu_v11_arm64, + fpu_v12_arm64, + fpu_v13_arm64, + fpu_v14_arm64, + fpu_v15_arm64, + fpu_v16_arm64, + fpu_v17_arm64, + fpu_v18_arm64, + fpu_v19_arm64, + fpu_v20_arm64, + fpu_v21_arm64, + fpu_v22_arm64, + fpu_v23_arm64, + fpu_v24_arm64, + fpu_v25_arm64, + fpu_v26_arm64, + fpu_v27_arm64, + fpu_v28_arm64, + fpu_v29_arm64, + fpu_v30_arm64, + fpu_v31_arm64, + fpu_fpsr_arm64, + fpu_fpcr_arm64, + k_last_fpr_arm64 = fpu_fpcr_arm64, + + exc_far_arm64, + exc_esr_arm64, + exc_exception_arm64, + + dbg_bvr0_arm64, + dbg_bvr1_arm64, + dbg_bvr2_arm64, + dbg_bvr3_arm64, + dbg_bvr4_arm64, + dbg_bvr5_arm64, + dbg_bvr6_arm64, + dbg_bvr7_arm64, + dbg_bvr8_arm64, + dbg_bvr9_arm64, + dbg_bvr10_arm64, + dbg_bvr11_arm64, + dbg_bvr12_arm64, + dbg_bvr13_arm64, + dbg_bvr14_arm64, + dbg_bvr15_arm64, + dbg_bcr0_arm64, + dbg_bcr1_arm64, + dbg_bcr2_arm64, + dbg_bcr3_arm64, + dbg_bcr4_arm64, + dbg_bcr5_arm64, + dbg_bcr6_arm64, + dbg_bcr7_arm64, + dbg_bcr8_arm64, + dbg_bcr9_arm64, + dbg_bcr10_arm64, + dbg_bcr11_arm64, + dbg_bcr12_arm64, + dbg_bcr13_arm64, + dbg_bcr14_arm64, + dbg_bcr15_arm64, + dbg_wvr0_arm64, + dbg_wvr1_arm64, + dbg_wvr2_arm64, + dbg_wvr3_arm64, + dbg_wvr4_arm64, + dbg_wvr5_arm64, + dbg_wvr6_arm64, + dbg_wvr7_arm64, + dbg_wvr8_arm64, + dbg_wvr9_arm64, + dbg_wvr10_arm64, + dbg_wvr11_arm64, + dbg_wvr12_arm64, + dbg_wvr13_arm64, + dbg_wvr14_arm64, + dbg_wvr15_arm64, + dbg_wcr0_arm64, + dbg_wcr1_arm64, + dbg_wcr2_arm64, + dbg_wcr3_arm64, + dbg_wcr4_arm64, + dbg_wcr5_arm64, + dbg_wcr6_arm64, + dbg_wcr7_arm64, + dbg_wcr8_arm64, + dbg_wcr9_arm64, + dbg_wcr10_arm64, + dbg_wcr11_arm64, + dbg_wcr12_arm64, + dbg_wcr13_arm64, + dbg_wcr14_arm64, + dbg_wcr15_arm64, + + k_num_registers_arm64, + k_num_gpr_registers_arm64 = k_last_gpr_arm64 - k_first_gpr_arm64 + 1, + k_num_fpr_registers_arm64 = k_last_fpr_arm64 - k_first_fpr_arm64 + 1 +}; + +class RegisterContextPOSIX_arm64 + : public lldb_private::RegisterContext +{ +public: + RegisterContextPOSIX_arm64 (lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + + ~RegisterContextPOSIX_arm64(); + + 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: + struct RegInfo + { + uint32_t num_registers; + uint32_t num_gpr_registers; + uint32_t num_fpr_registers; + + uint32_t last_gpr; + uint32_t first_fpr; + uint32_t last_fpr; + + uint32_t first_fpr_v; + uint32_t last_fpr_v; + + uint32_t gpr_flags; + }; + + // based on RegisterContextDarwin_arm64.h + struct VReg + { + uint8_t bytes[16]; + }; + + // based on RegisterContextDarwin_arm64.h + struct FPU + { + VReg v[32]; + uint32_t fpsr; + uint32_t fpcr; + }; + + uint64_t m_gpr_arm64[k_num_gpr_registers_arm64]; // 64-bit general purpose registers. + RegInfo m_reg_info; + struct RegisterContextPOSIX_arm64::FPU m_fpr; // floating-point registers including extended register sets. + 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_arm64_H_ diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp index 45c99aec1657..cefedaec63c1 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp @@ -20,7 +20,6 @@ #include "lldb/Host/Endian.h" #include "llvm/Support/Compiler.h" -#include "ProcessPOSIX.h" #include "RegisterContextPOSIX_mips64.h" #include "Plugins/Process/elf-core/ProcessElfCore.h" @@ -219,7 +218,7 @@ RegisterContextPOSIX_mips64::IsRegisterSetAvailable(size_t set_index) // Used when parsing DWARF and EH frame information and any other // object file sections that contain register numbers in them. uint32_t -RegisterContextPOSIX_mips64::ConvertRegisterKindToRegisterNumber(uint32_t kind, +RegisterContextPOSIX_mips64::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num) { const uint32_t num_regs = GetRegisterCount(); diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h index a2a7d1f45271..991179bdec66 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h @@ -73,7 +73,7 @@ class RegisterContextPOSIX_mips64 public: RegisterContextPOSIX_mips64 (lldb_private::Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info); + lldb_private::RegisterInfoInterface *register_info); ~RegisterContextPOSIX_mips64(); @@ -108,11 +108,11 @@ public: GetRegisterName(unsigned reg); uint32_t - ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num); protected: uint64_t m_gpr_mips64[k_num_gpr_registers_mips64]; // general purpose registers. - std::unique_ptr<RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) + 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 diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp index 9ae541a6309b..2925a33a1690 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp @@ -20,7 +20,6 @@ #include "lldb/Host/Endian.h" #include "llvm/Support/Compiler.h" -#include "ProcessPOSIX.h" #include "RegisterContext_x86.h" #include "RegisterContextPOSIX_x86.h" #include "Plugins/Process/elf-core/ProcessElfCore.h" @@ -62,9 +61,10 @@ g_gpr_regnums_i386[] = gpr_al_i386, gpr_bl_i386, gpr_cl_i386, - gpr_dl_i386 + gpr_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])) == k_num_gpr_registers_i386, +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 @@ -103,9 +103,10 @@ g_fpu_regnums_i386[] = fpu_xmm4_i386, fpu_xmm5_i386, fpu_xmm6_i386, - fpu_xmm7_i386 + fpu_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])) == k_num_fpr_registers_i386, +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"); const uint32_t @@ -118,9 +119,10 @@ g_avx_regnums_i386[] = fpu_ymm4_i386, fpu_ymm5_i386, fpu_ymm6_i386, - fpu_ymm7_i386 + fpu_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])) == k_num_avx_registers_i386, +static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 == k_num_avx_registers_i386, " g_avx_regnums_i386 has wrong number of register infos"); static const @@ -202,8 +204,9 @@ uint32_t g_gpr_regnums_x86_64[] = 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_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])) == k_num_gpr_registers_x86_64, +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 @@ -250,9 +253,10 @@ g_fpu_regnums_x86_64[] = fpu_xmm12_x86_64, fpu_xmm13_x86_64, fpu_xmm14_x86_64, - fpu_xmm15_x86_64 + fpu_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])) == k_num_fpr_registers_x86_64, +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 const uint32_t @@ -273,9 +277,10 @@ g_avx_regnums_x86_64[] = fpu_ymm12_x86_64, fpu_ymm13_x86_64, fpu_ymm14_x86_64, - fpu_ymm15_x86_64 + fpu_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])) == k_num_avx_registers_x86_64, +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 }; @@ -384,11 +389,9 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread, { m_register_info_ap.reset(register_info); - switch (register_info->m_target_arch.GetCore()) + switch (register_info->m_target_arch.GetMachine()) { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: + case llvm::Triple::x86: m_reg_info.num_registers = k_num_registers_i386; m_reg_info.num_gpr_registers = k_num_gpr_registers_i386; m_reg_info.num_fpr_registers = k_num_fpr_registers_i386; @@ -407,7 +410,7 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread, m_reg_info.first_dr = dr0_i386; m_reg_info.gpr_flags = gpr_eflags_i386; break; - case ArchSpec::eCore_x86_64_x86_64: + case llvm::Triple::x86_64: m_reg_info.num_registers = k_num_registers_x86_64; m_reg_info.num_gpr_registers = k_num_gpr_registers_x86_64; m_reg_info.num_fpr_registers = k_num_fpr_registers_x86_64; @@ -537,13 +540,11 @@ RegisterContextPOSIX_x86::GetRegisterSet(size_t set) { if (IsRegisterSetAvailable(set)) { - switch (m_register_info_ap->m_target_arch.GetCore()) + switch (m_register_info_ap->m_target_arch.GetMachine()) { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: + case llvm::Triple::x86: return &g_reg_sets_i386[set]; - case ArchSpec::eCore_x86_64_x86_64: + case llvm::Triple::x86_64: return &g_reg_sets_x86_64[set]; default: assert(false && "Unhandled target architecture."); @@ -647,8 +648,8 @@ RegisterContextPOSIX_x86::IsRegisterSetAvailable(size_t set_index) // Used when parsing DWARF and EH frame information and any other // object file sections that contain register numbers in them. uint32_t -RegisterContextPOSIX_x86::ConvertRegisterKindToRegisterNumber(uint32_t kind, - uint32_t num) +RegisterContextPOSIX_x86::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) { const uint32_t num_regs = GetRegisterCount(); diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h index 5e922025b830..4db7802e1b44 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h @@ -296,7 +296,7 @@ class RegisterContextPOSIX_x86 public: RegisterContextPOSIX_x86 (lldb_private::Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info); + lldb_private::RegisterInfoInterface *register_info); ~RegisterContextPOSIX_x86(); @@ -331,7 +331,7 @@ public: GetRegisterName(unsigned reg); uint32_t - ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num); //--------------------------------------------------------------------------- // Note: prefer kernel definitions over user-land @@ -428,7 +428,7 @@ protected: FPR m_fpr; // floating-point registers including extended register sets. IOVEC m_iovec; // wrapper for xsave. YMM m_ymm_set; // copy of ymmh and xmm register halves. - std::unique_ptr<RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) + 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 diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp index d35a5d095705..46dafa11d8f7 100644 --- a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp +++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp @@ -167,7 +167,7 @@ RegisterContextThreadMemory::CopyFromRegisterContext (lldb::RegisterContextSP re } uint32_t -RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { UpdateRegisterContext (); if (m_reg_ctx_sp) diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h index 8d7a4b622fe8..161ef040e651 100644 --- a/source/Plugins/Process/Utility/RegisterContextThreadMemory.h +++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h @@ -66,7 +66,7 @@ public: CopyFromRegisterContext (lldb::RegisterContextSP context); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); //------------------------------------------------------------------ // Subclasses can override these functions if desired diff --git a/source/Plugins/Process/POSIX/RegisterContext_mips64.h b/source/Plugins/Process/Utility/RegisterContext_mips64.h index dfd473d7cbec..dfd473d7cbec 100644 --- a/source/Plugins/Process/POSIX/RegisterContext_mips64.h +++ b/source/Plugins/Process/Utility/RegisterContext_mips64.h diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86.h b/source/Plugins/Process/Utility/RegisterContext_x86.h index df3e1e5a84bf..6b3f6fb43e33 100644 --- a/source/Plugins/Process/POSIX/RegisterContext_x86.h +++ b/source/Plugins/Process/Utility/RegisterContext_x86.h @@ -34,8 +34,16 @@ enum gcc_ecx_i386, gcc_edx_i386, gcc_ebx_i386, - gcc_ebp_i386, // Warning: these are switched from dwarf values - gcc_esp_i386, // + + // on Darwin esp & ebp are reversed in the eh_frame section for i386 (versus dwarf's reg numbering). + // To be specific: + // i386+darwin eh_frame: 4 is ebp, 5 is esp + // i386+everyone else eh_frame: 4 is esp, 5 is ebp + // i386 dwarf: 4 is esp, 5 is ebp + // lldb will get the darwin-specific eh_frame reg numberings from debugserver instead of here so we + // only encode the 4 == esp, 5 == ebp numbers in this generic header. + gcc_esp_i386, + gcc_ebp_i386, gcc_esi_i386, gcc_edi_i386, gcc_eip_i386, @@ -411,7 +419,7 @@ struct FXSAVE uint32_t fiseg; // FPU IP Selector (fcs) uint32_t fooff; // FPU Operand Pointer Offset (foo) uint32_t foseg; // FPU Operand Pointer Selector (fos) - } i386; + } i386_;// Added _ in the end to avoid error with gcc defining i386 in some cases } ptr; uint32_t mxcsr; // MXCSR Register State uint32_t mxcsrmask; // MXCSR Mask diff --git a/source/Plugins/Process/Utility/RegisterInfoInterface.h b/source/Plugins/Process/Utility/RegisterInfoInterface.h new file mode 100644 index 000000000000..382475f4523a --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterInfoInterface.h @@ -0,0 +1,49 @@ +//===-- RegisterInfoInterface.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_RegisterInfoInterface_h +#define lldb_RegisterInfoInterface_h + +#include "lldb/Core/ArchSpec.h" + +namespace lldb_private +{ + + ///------------------------------------------------------------------------------ + /// @class RegisterInfoInterface + /// + /// @brief RegisterInfo interface to patch RegisterInfo structure for archs. + ///------------------------------------------------------------------------------ + class RegisterInfoInterface + { + public: + RegisterInfoInterface(const lldb_private::ArchSpec& target_arch) : m_target_arch(target_arch) {} + virtual ~RegisterInfoInterface () {} + + virtual size_t + GetGPRSize () const = 0; + + virtual const lldb_private::RegisterInfo * + GetRegisterInfo () const = 0; + + virtual uint32_t + GetRegisterCount () const = 0; + + const lldb_private::ArchSpec& + GetTargetArchitecture() const + { return m_target_arch; } + + public: + // FIXME make private. + lldb_private::ArchSpec m_target_arch; + }; + +} + +#endif diff --git a/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/source/Plugins/Process/Utility/RegisterInfos_arm64.h new file mode 100644 index 000000000000..1bb4e89c8f78 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterInfos_arm64.h @@ -0,0 +1,347 @@ +//===-- RegisterInfos_arm64.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT + +#include <stddef.h> + +#include "lldb/lldb-private.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" + +#include "ARM64_GCC_Registers.h" +#include "ARM64_DWARF_Registers.h" + +#ifndef GPR_OFFSET +#error GPR_OFFSET must be defined before including this header file +#endif + +#ifndef GPR_OFFSET_NAME +#error GPR_OFFSET_NAME must be defined before including this header file +#endif + +#ifndef FPU_OFFSET +#error FPU_OFFSET must be defined before including this header file +#endif + +#ifndef FPU_OFFSET_NAME +#error FPU_OFFSET_NAME must be defined before including this header file +#endif + +#ifndef EXC_OFFSET_NAME +#error EXC_OFFSET_NAME must be defined before including this header file +#endif + +#ifndef DBG_OFFSET_NAME +#error DBG_OFFSET_NAME must be defined before including this header file +#endif + +#ifndef DEFINE_DBG +#error DEFINE_DBG must be defined before including this header file +#endif + +enum +{ + gpr_x0 = 0, + gpr_x1, + gpr_x2, + gpr_x3, + gpr_x4, + gpr_x5, + gpr_x6, + gpr_x7, + gpr_x8, + gpr_x9, + gpr_x10, + gpr_x11, + gpr_x12, + gpr_x13, + gpr_x14, + gpr_x15, + gpr_x16, + gpr_x17, + gpr_x18, + gpr_x19, + gpr_x20, + gpr_x21, + gpr_x22, + gpr_x23, + gpr_x24, + gpr_x25, + gpr_x26, + gpr_x27, + gpr_x28, + gpr_x29 = 29, gpr_fp = gpr_x29, + gpr_x30 = 30, gpr_lr = gpr_x30, gpr_ra = gpr_x30, + gpr_x31 = 31, gpr_sp = gpr_x31, + gpr_pc = 32, + gpr_cpsr, + + fpu_v0, + fpu_v1, + fpu_v2, + fpu_v3, + fpu_v4, + fpu_v5, + fpu_v6, + fpu_v7, + fpu_v8, + fpu_v9, + fpu_v10, + fpu_v11, + fpu_v12, + fpu_v13, + fpu_v14, + fpu_v15, + fpu_v16, + fpu_v17, + fpu_v18, + fpu_v19, + fpu_v20, + fpu_v21, + fpu_v22, + fpu_v23, + fpu_v24, + fpu_v25, + fpu_v26, + fpu_v27, + fpu_v28, + fpu_v29, + fpu_v30, + fpu_v31, + + fpu_fpsr, + fpu_fpcr, + + exc_far, + exc_esr, + exc_exception, + + dbg_bvr0, + dbg_bvr1, + dbg_bvr2, + dbg_bvr3, + dbg_bvr4, + dbg_bvr5, + dbg_bvr6, + dbg_bvr7, + dbg_bvr8, + dbg_bvr9, + dbg_bvr10, + dbg_bvr11, + dbg_bvr12, + dbg_bvr13, + dbg_bvr14, + dbg_bvr15, + + dbg_bcr0, + dbg_bcr1, + dbg_bcr2, + dbg_bcr3, + dbg_bcr4, + dbg_bcr5, + dbg_bcr6, + dbg_bcr7, + dbg_bcr8, + dbg_bcr9, + dbg_bcr10, + dbg_bcr11, + dbg_bcr12, + dbg_bcr13, + dbg_bcr14, + dbg_bcr15, + + dbg_wvr0, + dbg_wvr1, + dbg_wvr2, + dbg_wvr3, + dbg_wvr4, + dbg_wvr5, + dbg_wvr6, + dbg_wvr7, + dbg_wvr8, + dbg_wvr9, + dbg_wvr10, + dbg_wvr11, + dbg_wvr12, + dbg_wvr13, + dbg_wvr14, + dbg_wvr15, + + dbg_wcr0, + dbg_wcr1, + dbg_wcr2, + dbg_wcr3, + dbg_wcr4, + dbg_wcr5, + dbg_wcr6, + dbg_wcr7, + dbg_wcr8, + dbg_wcr9, + dbg_wcr10, + dbg_wcr11, + dbg_wcr12, + dbg_wcr13, + dbg_wcr14, + dbg_wcr15, + + k_num_registers +}; + +static lldb_private::RegisterInfo g_register_infos_arm64[] = { +// General purpose registers +// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS +// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== =============== +{ "x0", NULL, 8, GPR_OFFSET(0), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x0, arm64_dwarf::x0, LLDB_INVALID_REGNUM, arm64_gcc::x0, gpr_x0 }, NULL, NULL}, +{ "x1", NULL, 8, GPR_OFFSET(1), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x1, arm64_dwarf::x1, LLDB_INVALID_REGNUM, arm64_gcc::x1, gpr_x1 }, NULL, NULL}, +{ "x2", NULL, 8, GPR_OFFSET(2), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x2, arm64_dwarf::x2, LLDB_INVALID_REGNUM, arm64_gcc::x2, gpr_x2 }, NULL, NULL}, +{ "x3", NULL, 8, GPR_OFFSET(3), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x3, arm64_dwarf::x3, LLDB_INVALID_REGNUM, arm64_gcc::x3, gpr_x3 }, NULL, NULL}, +{ "x4", NULL, 8, GPR_OFFSET(4), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x4, arm64_dwarf::x4, LLDB_INVALID_REGNUM, arm64_gcc::x4, gpr_x4 }, NULL, NULL}, +{ "x5", NULL, 8, GPR_OFFSET(5), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x5, arm64_dwarf::x5, LLDB_INVALID_REGNUM, arm64_gcc::x5, gpr_x5 }, NULL, NULL}, +{ "x6", NULL, 8, GPR_OFFSET(6), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x6, arm64_dwarf::x6, LLDB_INVALID_REGNUM, arm64_gcc::x6, gpr_x6 }, NULL, NULL}, +{ "x7", NULL, 8, GPR_OFFSET(7), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x7, arm64_dwarf::x7, LLDB_INVALID_REGNUM, arm64_gcc::x7, gpr_x7 }, NULL, NULL}, +{ "x8", NULL, 8, GPR_OFFSET(8), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x8, arm64_dwarf::x8, LLDB_INVALID_REGNUM, arm64_gcc::x8, gpr_x8 }, NULL, NULL}, +{ "x9", NULL, 8, GPR_OFFSET(9), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x9, arm64_dwarf::x9, LLDB_INVALID_REGNUM, arm64_gcc::x9, gpr_x9 }, NULL, NULL}, +{ "x10", NULL, 8, GPR_OFFSET(10), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x10, arm64_dwarf::x10, LLDB_INVALID_REGNUM, arm64_gcc::x10, gpr_x10 }, NULL, NULL}, +{ "x11", NULL, 8, GPR_OFFSET(11), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x11, arm64_dwarf::x11, LLDB_INVALID_REGNUM, arm64_gcc::x11, gpr_x11 }, NULL, NULL}, +{ "x12", NULL, 8, GPR_OFFSET(12), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x12, arm64_dwarf::x12, LLDB_INVALID_REGNUM, arm64_gcc::x12, gpr_x12 }, NULL, NULL}, +{ "x13", NULL, 8, GPR_OFFSET(13), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x13, arm64_dwarf::x13, LLDB_INVALID_REGNUM, arm64_gcc::x13, gpr_x13 }, NULL, NULL}, +{ "x14", NULL, 8, GPR_OFFSET(14), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x14, arm64_dwarf::x14, LLDB_INVALID_REGNUM, arm64_gcc::x14, gpr_x14 }, NULL, NULL}, +{ "x15", NULL, 8, GPR_OFFSET(15), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x15, arm64_dwarf::x15, LLDB_INVALID_REGNUM, arm64_gcc::x15, gpr_x15 }, NULL, NULL}, +{ "x16", NULL, 8, GPR_OFFSET(16), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x16, arm64_dwarf::x16, LLDB_INVALID_REGNUM, arm64_gcc::x16, gpr_x16 }, NULL, NULL}, +{ "x17", NULL, 8, GPR_OFFSET(17), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x17, arm64_dwarf::x17, LLDB_INVALID_REGNUM, arm64_gcc::x17, gpr_x17 }, NULL, NULL}, +{ "x18", NULL, 8, GPR_OFFSET(18), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x18, arm64_dwarf::x18, LLDB_INVALID_REGNUM, arm64_gcc::x18, gpr_x18 }, NULL, NULL}, +{ "x19", NULL, 8, GPR_OFFSET(19), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x19, arm64_dwarf::x19, LLDB_INVALID_REGNUM, arm64_gcc::x19, gpr_x19 }, NULL, NULL}, +{ "x20", NULL, 8, GPR_OFFSET(20), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x20, arm64_dwarf::x20, LLDB_INVALID_REGNUM, arm64_gcc::x20, gpr_x20 }, NULL, NULL}, +{ "x21", NULL, 8, GPR_OFFSET(21), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x21, arm64_dwarf::x21, LLDB_INVALID_REGNUM, arm64_gcc::x21, gpr_x21 }, NULL, NULL}, +{ "x22", NULL, 8, GPR_OFFSET(22), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x22, arm64_dwarf::x22, LLDB_INVALID_REGNUM, arm64_gcc::x22, gpr_x22 }, NULL, NULL}, +{ "x23", NULL, 8, GPR_OFFSET(23), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x23, arm64_dwarf::x23, LLDB_INVALID_REGNUM, arm64_gcc::x23, gpr_x23 }, NULL, NULL}, +{ "x24", NULL, 8, GPR_OFFSET(24), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x24, arm64_dwarf::x24, LLDB_INVALID_REGNUM, arm64_gcc::x24, gpr_x24 }, NULL, NULL}, +{ "x25", NULL, 8, GPR_OFFSET(25), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x25, arm64_dwarf::x25, LLDB_INVALID_REGNUM, arm64_gcc::x25, gpr_x25 }, NULL, NULL}, +{ "x26", NULL, 8, GPR_OFFSET(26), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x26, arm64_dwarf::x26, LLDB_INVALID_REGNUM, arm64_gcc::x26, gpr_x26 }, NULL, NULL}, +{ "x27", NULL, 8, GPR_OFFSET(27), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x27, arm64_dwarf::x27, LLDB_INVALID_REGNUM, arm64_gcc::x27, gpr_x27 }, NULL, NULL}, +{ "x28", NULL, 8, GPR_OFFSET(28), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x28, arm64_dwarf::x28, LLDB_INVALID_REGNUM, arm64_gcc::x28, gpr_x28 }, NULL, NULL}, + +{ "fp", "x29", 8, GPR_OFFSET(29), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::fp, arm64_dwarf::fp, LLDB_REGNUM_GENERIC_FP, arm64_gcc::fp, gpr_fp }, NULL, NULL}, +{ "lr", "x30", 8, GPR_OFFSET(30), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::lr, arm64_dwarf::lr, LLDB_REGNUM_GENERIC_RA, arm64_gcc::lr, gpr_lr }, NULL, NULL}, +{ "sp", "x31", 8, GPR_OFFSET(31), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::sp, arm64_dwarf::sp, LLDB_REGNUM_GENERIC_SP, arm64_gcc::sp, gpr_sp }, NULL, NULL}, +{ "pc", NULL, 8, GPR_OFFSET(32), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::pc, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, arm64_gcc::pc, gpr_pc }, NULL, NULL}, + +{ "cpsr", NULL, 4, GPR_OFFSET_NAME(cpsr), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::cpsr, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, arm64_gcc::cpsr, gpr_cpsr }, NULL, NULL}, + +{ "v0", NULL, 16, FPU_OFFSET(0), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, arm64_gcc::v0, fpu_v0 }, NULL, NULL}, +{ "v1", NULL, 16, FPU_OFFSET(1), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, arm64_gcc::v1, fpu_v1 }, NULL, NULL}, +{ "v2", NULL, 16, FPU_OFFSET(2), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, arm64_gcc::v2, fpu_v2 }, NULL, NULL}, +{ "v3", NULL, 16, FPU_OFFSET(3), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, arm64_gcc::v3, fpu_v3 }, NULL, NULL}, +{ "v4", NULL, 16, FPU_OFFSET(4), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, arm64_gcc::v4, fpu_v4 }, NULL, NULL}, +{ "v5", NULL, 16, FPU_OFFSET(5), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, arm64_gcc::v5, fpu_v5 }, NULL, NULL}, +{ "v6", NULL, 16, FPU_OFFSET(6), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, arm64_gcc::v6, fpu_v6 }, NULL, NULL}, +{ "v7", NULL, 16, FPU_OFFSET(7), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, arm64_gcc::v7, fpu_v7 }, NULL, NULL}, +{ "v8", NULL, 16, FPU_OFFSET(8), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, arm64_gcc::v8, fpu_v8 }, NULL, NULL}, +{ "v9", NULL, 16, FPU_OFFSET(9), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, arm64_gcc::v9, fpu_v9 }, NULL, NULL}, +{ "v10", NULL, 16, FPU_OFFSET(10), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, arm64_gcc::v10, fpu_v10 }, NULL, NULL}, +{ "v11", NULL, 16, FPU_OFFSET(11), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, arm64_gcc::v11, fpu_v11 }, NULL, NULL}, +{ "v12", NULL, 16, FPU_OFFSET(12), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, arm64_gcc::v12, fpu_v12 }, NULL, NULL}, +{ "v13", NULL, 16, FPU_OFFSET(13), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, arm64_gcc::v13, fpu_v13 }, NULL, NULL}, +{ "v14", NULL, 16, FPU_OFFSET(14), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, arm64_gcc::v14, fpu_v14 }, NULL, NULL}, +{ "v15", NULL, 16, FPU_OFFSET(15), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, arm64_gcc::v15, fpu_v15 }, NULL, NULL}, +{ "v16", NULL, 16, FPU_OFFSET(16), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, arm64_gcc::v16, fpu_v16 }, NULL, NULL}, +{ "v17", NULL, 16, FPU_OFFSET(17), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, arm64_gcc::v17, fpu_v17 }, NULL, NULL}, +{ "v18", NULL, 16, FPU_OFFSET(18), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, arm64_gcc::v18, fpu_v18 }, NULL, NULL}, +{ "v19", NULL, 16, FPU_OFFSET(19), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, arm64_gcc::v19, fpu_v19 }, NULL, NULL}, +{ "v20", NULL, 16, FPU_OFFSET(20), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, arm64_gcc::v20, fpu_v20 }, NULL, NULL}, +{ "v21", NULL, 16, FPU_OFFSET(21), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, arm64_gcc::v21, fpu_v21 }, NULL, NULL}, +{ "v22", NULL, 16, FPU_OFFSET(22), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, arm64_gcc::v22, fpu_v22 }, NULL, NULL}, +{ "v23", NULL, 16, FPU_OFFSET(23), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, arm64_gcc::v23, fpu_v23 }, NULL, NULL}, +{ "v24", NULL, 16, FPU_OFFSET(24), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, arm64_gcc::v24, fpu_v24 }, NULL, NULL}, +{ "v25", NULL, 16, FPU_OFFSET(25), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, arm64_gcc::v25, fpu_v25 }, NULL, NULL}, +{ "v26", NULL, 16, FPU_OFFSET(26), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, arm64_gcc::v26, fpu_v26 }, NULL, NULL}, +{ "v27", NULL, 16, FPU_OFFSET(27), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, arm64_gcc::v27, fpu_v27 }, NULL, NULL}, +{ "v28", NULL, 16, FPU_OFFSET(28), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, arm64_gcc::v28, fpu_v28 }, NULL, NULL}, +{ "v29", NULL, 16, FPU_OFFSET(29), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, arm64_gcc::v29, fpu_v29 }, NULL, NULL}, +{ "v30", NULL, 16, FPU_OFFSET(30), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, arm64_gcc::v30, fpu_v30 }, NULL, NULL}, +{ "v31", NULL, 16, FPU_OFFSET(31), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, arm64_gcc::v31, fpu_v31 }, NULL, NULL}, + +{ "fpsr", NULL, 4, FPU_OFFSET_NAME(fpsr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpsr }, NULL, NULL}, +{ "fpcr", NULL, 4, FPU_OFFSET_NAME(fpcr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpcr }, NULL, NULL}, + +{ "far", NULL, 8, EXC_OFFSET_NAME(far), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL}, +{ "esr", NULL, 4, EXC_OFFSET_NAME(esr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_esr }, NULL, NULL}, +{ "exception",NULL, 4, EXC_OFFSET_NAME(exception), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL}, + +{ DEFINE_DBG (bvr, 0) }, +{ DEFINE_DBG (bvr, 1) }, +{ DEFINE_DBG (bvr, 2) }, +{ DEFINE_DBG (bvr, 3) }, +{ DEFINE_DBG (bvr, 4) }, +{ DEFINE_DBG (bvr, 5) }, +{ DEFINE_DBG (bvr, 6) }, +{ DEFINE_DBG (bvr, 7) }, +{ DEFINE_DBG (bvr, 8) }, +{ DEFINE_DBG (bvr, 9) }, +{ DEFINE_DBG (bvr, 10) }, +{ DEFINE_DBG (bvr, 11) }, +{ DEFINE_DBG (bvr, 12) }, +{ DEFINE_DBG (bvr, 13) }, +{ DEFINE_DBG (bvr, 14) }, +{ DEFINE_DBG (bvr, 15) }, + +{ DEFINE_DBG (bcr, 0) }, +{ DEFINE_DBG (bcr, 1) }, +{ DEFINE_DBG (bcr, 2) }, +{ DEFINE_DBG (bcr, 3) }, +{ DEFINE_DBG (bcr, 4) }, +{ DEFINE_DBG (bcr, 5) }, +{ DEFINE_DBG (bcr, 6) }, +{ DEFINE_DBG (bcr, 7) }, +{ DEFINE_DBG (bcr, 8) }, +{ DEFINE_DBG (bcr, 9) }, +{ DEFINE_DBG (bcr, 10) }, +{ DEFINE_DBG (bcr, 11) }, +{ DEFINE_DBG (bcr, 12) }, +{ DEFINE_DBG (bcr, 13) }, +{ DEFINE_DBG (bcr, 14) }, +{ DEFINE_DBG (bcr, 15) }, + +{ DEFINE_DBG (wvr, 0) }, +{ DEFINE_DBG (wvr, 1) }, +{ DEFINE_DBG (wvr, 2) }, +{ DEFINE_DBG (wvr, 3) }, +{ DEFINE_DBG (wvr, 4) }, +{ DEFINE_DBG (wvr, 5) }, +{ DEFINE_DBG (wvr, 6) }, +{ DEFINE_DBG (wvr, 7) }, +{ DEFINE_DBG (wvr, 8) }, +{ DEFINE_DBG (wvr, 9) }, +{ DEFINE_DBG (wvr, 10) }, +{ DEFINE_DBG (wvr, 11) }, +{ DEFINE_DBG (wvr, 12) }, +{ DEFINE_DBG (wvr, 13) }, +{ DEFINE_DBG (wvr, 14) }, +{ DEFINE_DBG (wvr, 15) }, + +{ DEFINE_DBG (wcr, 0) }, +{ DEFINE_DBG (wcr, 1) }, +{ DEFINE_DBG (wcr, 2) }, +{ DEFINE_DBG (wcr, 3) }, +{ DEFINE_DBG (wcr, 4) }, +{ DEFINE_DBG (wcr, 5) }, +{ DEFINE_DBG (wcr, 6) }, +{ DEFINE_DBG (wcr, 7) }, +{ DEFINE_DBG (wcr, 8) }, +{ DEFINE_DBG (wcr, 9) }, +{ DEFINE_DBG (wcr, 10) }, +{ DEFINE_DBG (wcr, 11) }, +{ DEFINE_DBG (wcr, 12) }, +{ DEFINE_DBG (wcr, 13) }, +{ DEFINE_DBG (wcr, 14) }, +{ DEFINE_DBG (wcr, 15) } +}; + +#endif // DECLARE_REGISTER_INFOS_ARM64_STRUCT diff --git a/source/Plugins/Process/POSIX/RegisterInfos_i386.h b/source/Plugins/Process/Utility/RegisterInfos_i386.h index 7c516568cd62..fa152b4147ce 100644 --- a/source/Plugins/Process/POSIX/RegisterInfos_i386.h +++ b/source/Plugins/Process/Utility/RegisterInfos_i386.h @@ -8,6 +8,8 @@ //===---------------------------------------------------------------------===// #include "llvm/Support/Compiler.h" +#include <stddef.h> + #ifdef DECLARE_REGISTER_INFOS_I386_STRUCT // Computes the offset of the given GPR in the user data area. @@ -24,7 +26,9 @@ (LLVM_EXTENSION offsetof(YMM, regname)) // Number of bytes needed to represent a FPR. +#if !defined(FPR_SIZE) #define FPR_SIZE(reg) sizeof(((FXSAVE*)NULL)->reg) +#endif // Number of bytes needed to represent the i'th FP register. #define FP_SIZE sizeof(((MMSReg*)NULL)->bytes) @@ -37,7 +41,7 @@ // 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::reg), GPR_OFFSET(reg), eEncodingUint, \ + { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_i386 }, NULL, NULL } #define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ @@ -129,10 +133,10 @@ g_register_infos_i386[] = DEFINE_FPR(fstat, fstat, LLDB_INVALID_REGNUM, dwarf_fstat_i386, LLDB_INVALID_REGNUM, gdb_fstat_i386), DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftag_i386), DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop_i386), - DEFINE_FPR(fiseg, ptr.i386.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_i386), - DEFINE_FPR(fioff, ptr.i386.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_i386), - DEFINE_FPR(foseg, ptr.i386.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_i386), - DEFINE_FPR(fooff, ptr.i386.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_i386), + DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_i386), + DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_i386), + DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_i386), + DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_i386), DEFINE_FPR(mxcsr, mxcsr, LLDB_INVALID_REGNUM, dwarf_mxcsr_i386, LLDB_INVALID_REGNUM, gdb_mxcsr_i386), DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), diff --git a/source/Plugins/Process/POSIX/RegisterInfos_mips64.h b/source/Plugins/Process/Utility/RegisterInfos_mips64.h index 13526e3680b7..187b8e98332e 100644 --- a/source/Plugins/Process/POSIX/RegisterInfos_mips64.h +++ b/source/Plugins/Process/Utility/RegisterInfos_mips64.h @@ -7,6 +7,8 @@ // //===---------------------------------------------------------------------===// +#include <stddef.h> + // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) \ (offsetof(GPR, regname)) @@ -15,7 +17,7 @@ // 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::reg), GPR_OFFSET(reg), eEncodingUint, \ + { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL } static RegisterInfo diff --git a/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h index 86abdba68db6..c4dc6041ce43 100644 --- a/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h +++ b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h @@ -8,6 +8,8 @@ //===---------------------------------------------------------------------===// #include "llvm/Support/Compiler.h" +#include <stddef.h> + // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(GPR, regname)) @@ -39,7 +41,7 @@ // 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::reg), GPR_OFFSET(reg), eEncodingUint, \ + { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_x86_64 }, NULL, NULL } #define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ @@ -175,10 +177,10 @@ g_register_infos_x86_64[] = DEFINE_FPR(fstat, fstat, gcc_dwarf_fstat_x86_64, gcc_dwarf_fstat_x86_64, LLDB_INVALID_REGNUM, gdb_fstat_x86_64), DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftag_x86_64), DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop_x86_64), - DEFINE_FPR(fiseg, ptr.i386.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_x86_64), - DEFINE_FPR(fioff, ptr.i386.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_x86_64), - DEFINE_FPR(foseg, ptr.i386.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_x86_64), - DEFINE_FPR(fooff, ptr.i386.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_x86_64), + DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_x86_64), + DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_x86_64), + DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_x86_64), + DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_x86_64), DEFINE_FPR(mxcsr, mxcsr, gcc_dwarf_mxcsr_x86_64, gcc_dwarf_mxcsr_x86_64, LLDB_INVALID_REGNUM, gdb_mxcsr_x86_64), DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), @@ -343,10 +345,10 @@ do { UPDATE_FPR_INFO(fstat, fstat); UPDATE_FPR_INFO(ftag, ftag); UPDATE_FPR_INFO(fop, fop); - UPDATE_FPR_INFO(fiseg, ptr.i386.fiseg); - UPDATE_FPR_INFO(fioff, ptr.i386.fioff); - UPDATE_FPR_INFO(fooff, ptr.i386.fooff); - UPDATE_FPR_INFO(foseg, ptr.i386.foseg); + UPDATE_FPR_INFO(fiseg, ptr.i386_.fiseg); + UPDATE_FPR_INFO(fioff, ptr.i386_.fioff); + UPDATE_FPR_INFO(fooff, ptr.i386_.fooff); + UPDATE_FPR_INFO(foseg, ptr.i386_.foseg); UPDATE_FPR_INFO(mxcsr, mxcsr); UPDATE_FPR_INFO(mxcsrmask, mxcsrmask); diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp index 51d2052e1931..0e3e559aef5c 100644 --- a/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -363,20 +363,30 @@ StopInfoMachException::CreateStopReasonWithMachException if (exc_code == 1) // EXC_I386_SGL { if (!exc_sub_code) - return StopInfo::CreateStopReasonToTrace(thread); - - // It's a watchpoint, then. - // The exc_sub_code indicates the data break address. - lldb::WatchpointSP wp_sp; - if (target) - wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); - if (wp_sp && wp_sp->IsEnabled()) { - // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. - // Set the hardware index if that's the case. - if (exc_data_count >=3) - wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); - return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); + // This looks like a plain trap. + // Have to check if there is a breakpoint here as well. When you single-step onto a trap, + // the single step stops you not to trap. Since we also do that check below, let's just use + // that logic. + is_actual_breakpoint = true; + is_trace_if_actual_breakpoint_missing = true; + } + else + { + + // It's a watchpoint, then. + // The exc_sub_code indicates the data break address. + lldb::WatchpointSP wp_sp; + if (target) + wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); + if (wp_sp && wp_sp->IsEnabled()) + { + // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. + // Set the hardware index if that's the case. + if (exc_data_count >=3) + wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); + return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); + } } } else if (exc_code == 2 || // EXC_I386_BPT @@ -429,6 +439,38 @@ StopInfoMachException::CreateStopReasonWithMachException } break; + case llvm::Triple::aarch64: + { + if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT + { + // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0 is set + return StopInfo::CreateStopReasonToTrace(thread); + } + if (exc_code == 0x102) // EXC_ARM_DA_DEBUG + { + // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled + // data break address from our watchpoint list. + lldb::WatchpointSP wp_sp; + if (target) + wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); + if (wp_sp && wp_sp->IsEnabled()) + { + // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. + // Set the hardware index if that's the case. + if (exc_data_count >= 3) + 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); + } + // It looks like exc_sub_code has the 4 bytes of the instruction that triggered the + // exception, i.e. our breakpoint opcode + is_actual_breakpoint = exc_code == 1; + break; + } + default: break; } diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp index 5db08e5c26de..37fd4f489552 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -347,7 +347,7 @@ bool UnwindLLDB::SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc, uint32_t starting_frame_num, bool pc_reg) { int64_t frame_num = starting_frame_num; - if (frame_num >= m_frames.size()) + if (static_cast<size_t>(frame_num) >= m_frames.size()) return false; // Never interrogate more than one level while looking for the saved pc value. If the value diff --git a/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/source/Plugins/Process/Utility/lldb-x86-register-enums.h new file mode 100644 index 000000000000..c4706d567b70 --- /dev/null +++ b/source/Plugins/Process/Utility/lldb-x86-register-enums.h @@ -0,0 +1,292 @@ +//===-- lldb-x86-register-enums.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_x86_register_enums_h +#define lldb_x86_register_enums_h + +namespace lldb_private +{ + + //--------------------------------------------------------------------------- + // 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 + }; + +} + +#endif // #ifndef lldb_x86_register_enums_h diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 7ea5c89e7df4..566816783c7e 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -17,12 +17,17 @@ #include "lldb/Core/Section.h" #include "lldb/Core/State.h" #include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Log.h" #include "lldb/Target/Target.h" #include "lldb/Target/DynamicLoader.h" -#include "ProcessPOSIXLog.h" +#include "lldb/Target/UnixSignals.h" + +#include "llvm/Support/ELF.h" #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h" +#include "Plugins/Process/Utility/FreeBSDSignals.h" +#include "Plugins/Process/Utility/LinuxSignals.h" // Project includes #include "ProcessElfCore.h" @@ -54,8 +59,25 @@ lldb::ProcessSP ProcessElfCore::CreateInstance (Target &target, Listener &listener, const FileSpec *crash_file) { lldb::ProcessSP process_sp; - if (crash_file) - process_sp.reset(new ProcessElfCore (target, listener, *crash_file)); + if (crash_file) + { + // Read enough data for a ELF32 header or ELF64 header + const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr); + + lldb::DataBufferSP data_sp (crash_file->ReadFileContents(0, header_size)); + if (data_sp && data_sp->GetByteSize() == header_size && + elf::ELFHeader::MagicBytesMatch (data_sp->GetBytes())) + { + elf::ELFHeader elf_header; + DataExtractor data(data_sp, lldb::eByteOrderLittle, 4); + lldb::offset_t data_offset = 0; + if (elf_header.Parse(data, &data_offset)) + { + if (elf_header.e_type == llvm::ELF::ET_CORE) + process_sp.reset(new ProcessElfCore (target, listener, *crash_file)); + } + } + } return process_sp; } @@ -66,7 +88,7 @@ ProcessElfCore::CanDebug(Target &target, bool plugin_specified_by_name) if (!m_core_module_sp && m_core_file.Exists()) { ModuleSpec core_module_spec(m_core_file, target.GetArchitecture()); - Error error (ModuleList::GetSharedModule (core_module_spec, m_core_module_sp, + Error error (ModuleList::GetSharedModule (core_module_spec, m_core_module_sp, NULL, NULL, NULL)); if (m_core_module_sp) { @@ -87,6 +109,7 @@ ProcessElfCore::ProcessElfCore(Target& target, Listener &listener, m_core_module_sp (), m_core_file (core_file), m_dyld_plugin_name (), + m_os(llvm::Triple::UnknownOS), m_thread_data_valid(false), m_thread_data(), m_core_aranges () @@ -154,21 +177,21 @@ ProcessElfCore::DoLoadCore () Error error; if (!m_core_module_sp) { - error.SetErrorString ("invalid core module"); + error.SetErrorString ("invalid core module"); return error; } ObjectFileELF *core = (ObjectFileELF *)(m_core_module_sp->GetObjectFile()); if (core == NULL) { - error.SetErrorString ("invalid core object file"); + error.SetErrorString ("invalid core object file"); return error; } const uint32_t num_segments = core->GetProgramHeaderCount(); if (num_segments == 0) { - error.SetErrorString ("core file has no sections"); + error.SetErrorString ("core file has no sections"); return error; } @@ -209,7 +232,25 @@ ProcessElfCore::DoLoadCore () // it to match the core file which is always single arch. ArchSpec arch (m_core_module_sp->GetArchitecture()); if (arch.IsValid()) - m_target.SetArchitecture(arch); + m_target.SetArchitecture(arch); + + switch (m_os) + { + case llvm::Triple::FreeBSD: + { + static UnixSignalsSP s_freebsd_signals_sp(new FreeBSDSignals ()); + SetUnixSignals(s_freebsd_signals_sp); + break; + } + case llvm::Triple::Linux: + { + static UnixSignalsSP s_linux_signals_sp(new process_linux::LinuxSignals ()); + SetUnixSignals(s_linux_signals_sp); + break; + } + default: + break; + } return error; } @@ -324,13 +365,17 @@ void ProcessElfCore::Clear() { m_thread_list.Clear(); + m_os = llvm::Triple::UnknownOS; + + static UnixSignalsSP s_default_unix_signals_sp(new UnixSignals()); + SetUnixSignals(s_default_unix_signals_sp); } void ProcessElfCore::Initialize() { static bool g_initialized = false; - + if (g_initialized == false) { g_initialized = true; @@ -378,7 +423,7 @@ ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, arch.GetMachine() == llvm::Triple::x86_64); int pr_version = data.GetU32(&offset); - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + Log *log (GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) { if (pr_version > 1) @@ -395,7 +440,7 @@ ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, offset += 4; // pr_pid if (lp64) offset += 4; - + size_t len = data.GetByteSize() - offset; thread_data.gpregset = DataExtractor(data, offset, len); } @@ -421,7 +466,7 @@ ParseFreeBSDThrMisc(ThreadData &thread_data, DataExtractor &data) /// a) Each thread context(2 or more NOTE entries) contained in its own segment (PT_NOTE) /// b) All thread context is stored in a single segment(PT_NOTE). /// This case is little tricker since while parsing we have to find where the -/// new thread starts. The current implementation marks beginning of +/// new thread starts. The current implementation marks beginning of /// new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry. /// For case (b) there may be either one NT_PRPSINFO per thread, or a single /// one that applies to all threads (depending on the platform type). @@ -468,6 +513,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader * DataExtractor note_data (segment_data, note_start, note_size); if (note.n_name == "FreeBSD") { + m_os = llvm::Triple::FreeBSD; switch (note.n_type) { case NT_FREEBSD_PRSTATUS: @@ -553,4 +599,3 @@ ProcessElfCore::GetAuxvData() lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(start, len)); return buffer; } - diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.h b/source/Plugins/Process/elf-core/ProcessElfCore.h index 1c1ed98ce17a..2fc2e4ee7949 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -37,45 +37,45 @@ public: // Constructors and Destructors //------------------------------------------------------------------ static lldb::ProcessSP - CreateInstance (lldb_private::Target& target, - lldb_private::Listener &listener, + CreateInstance (lldb_private::Target& target, + lldb_private::Listener &listener, const lldb_private::FileSpec *crash_file_path); - + static void Initialize(); - + static void Terminate(); - + static lldb_private::ConstString GetPluginNameStatic(); - + static const char * GetPluginDescriptionStatic(); - + //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ - ProcessElfCore(lldb_private::Target& target, + ProcessElfCore(lldb_private::Target& target, lldb_private::Listener &listener, const lldb_private::FileSpec &core_file); - + virtual ~ProcessElfCore(); - + //------------------------------------------------------------------ // Check if a given Process //------------------------------------------------------------------ virtual bool CanDebug (lldb_private::Target &target, bool plugin_specified_by_name); - + //------------------------------------------------------------------ // Creating a new process, or attaching to an existing one //------------------------------------------------------------------ virtual lldb_private::Error DoLoadCore (); - + virtual lldb_private::DynamicLoader * GetDynamicLoader (); @@ -84,19 +84,19 @@ public: //------------------------------------------------------------------ virtual lldb_private::ConstString GetPluginName(); - + virtual uint32_t GetPluginVersion(); - + //------------------------------------------------------------------ // Process Control - //------------------------------------------------------------------ + //------------------------------------------------------------------ virtual lldb_private::Error DoDestroy (); - + virtual void RefreshStateAfterStop(); - + //------------------------------------------------------------------ // Process Queries //------------------------------------------------------------------ @@ -108,10 +108,10 @@ public: //------------------------------------------------------------------ virtual size_t ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error); - + virtual size_t DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error); - + virtual lldb::addr_t GetImageInfoAddress (); @@ -120,16 +120,16 @@ public: // Returns AUXV structure found in the core file const lldb::DataBufferSP - GetAuxvData(); + GetAuxvData() override; protected: void Clear ( ); - + virtual bool - UpdateThreadList (lldb_private::ThreadList &old_thread_list, + UpdateThreadList (lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list); - + private: //------------------------------------------------------------------ // For ProcessElfCore only @@ -142,6 +142,8 @@ private: std::string m_dyld_plugin_name; DISALLOW_COPY_AND_ASSIGN (ProcessElfCore); + llvm::Triple::OSType m_os; + // True if m_thread_contexts contains valid entries bool m_thread_data_valid; diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp index b95a51130ca7..fbf397b933cc 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp @@ -21,13 +21,9 @@ RegisterContextCorePOSIX_mips64::RegisterContextCorePOSIX_mips64(Thread &thread, const DataExtractor &fpregset) : RegisterContextPOSIX_mips64(thread, 0, register_info) { - size_t i; - lldb::offset_t offset = 0; - - for (i = 0; i < k_num_gpr_registers_mips64; i++) - { - m_reg[i] = gpregset.GetU64(&offset); - } + m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize())); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); } RegisterContextCorePOSIX_mips64::~RegisterContextCorePOSIX_mips64() @@ -63,10 +59,14 @@ RegisterContextCorePOSIX_mips64::WriteFPR() bool RegisterContextCorePOSIX_mips64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { - int reg_num = reg_info->byte_offset / 8; - assert(reg_num < k_num_gpr_registers_mips64); - value = m_reg[reg_num]; - return true; + lldb::offset_t offset = reg_info->byte_offset; + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) + { + value = v; + return true; + } + return false; } bool diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h index 92e486bf2235..ca29d4f0febd 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h @@ -10,14 +10,15 @@ #ifndef liblldb_RegisterContextCorePOSIX_mips64_H_ #define liblldb_RegisterContextCorePOSIX_mips64_H_ -#include "Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h" +#include "lldb/Core/DataBufferHeap.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" class RegisterContextCorePOSIX_mips64 : public RegisterContextPOSIX_mips64 { public: RegisterContextCorePOSIX_mips64 (lldb_private::Thread &thread, - RegisterInfoInterface *register_info, + lldb_private::RegisterInfoInterface *register_info, const lldb_private::DataExtractor &gpregset, const lldb_private::DataExtractor &fpregset); @@ -52,7 +53,8 @@ protected: WriteFPR(); private: - uint64_t m_reg[40]; + lldb::DataBufferSP m_gpr_buffer; + lldb_private::DataExtractor m_gpr; }; #endif // #ifndef liblldb_RegisterContextCorePOSIX_mips64_H_ diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h index d4ea14fab7b1..ac0f49c3db52 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h @@ -10,14 +10,14 @@ #ifndef liblldb_RegisterContextCorePOSIX_x86_64_H_ #define liblldb_RegisterContextCorePOSIX_x86_64_H_ -#include "Plugins/Process/POSIX/RegisterContextPOSIX_x86.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h" class RegisterContextCorePOSIX_x86_64 : public RegisterContextPOSIX_x86 { public: RegisterContextCorePOSIX_x86_64 (lldb_private::Thread &thread, - RegisterInfoInterface *register_info, + lldb_private::RegisterInfoInterface *register_info, const lldb_private::DataExtractor &gpregset, const lldb_private::DataExtractor &fpregset); diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp index cadcf53ca543..d9f6cc04a343 100644 --- a/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -8,11 +8,11 @@ //===----------------------------------------------------------------------===// #include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Unwind.h" -#include "ProcessPOSIXLog.h" #include "ThreadElfCore.h" #include "ProcessElfCore.h" @@ -74,7 +74,7 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) { RegisterContextSP reg_ctx_sp; uint32_t concrete_frame_idx = 0; - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + Log *log (GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (frame) concrete_frame_idx = frame->GetConcreteFrameIndex (); @@ -108,7 +108,7 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) } break; } - + case llvm::Triple::Linux: { switch (arch.GetMachine()) diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.h b/source/Plugins/Process/elf-core/ThreadElfCore.h index 2661edfa50cd..f1f00cf019b3 100644 --- a/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -40,7 +40,7 @@ struct ELFLinuxPrStatus int32_t si_errno; int16_t pr_cursig; - + uint64_t pr_sigpend; uint64_t pr_sighold; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 72600d835934..1f4dd93976ec 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -22,14 +22,21 @@ #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/Socket.h" #include "lldb/Host/TimeValue.h" #include "lldb/Target/Process.h" // Project includes #include "ProcessGDBRemoteLog.h" -#define DEBUGSERVER_BASENAME "debugserver" +#if defined(__APPLE__) +# define DEBUGSERVER_BASENAME "debugserver" +#else +# define DEBUGSERVER_BASENAME "lldb-gdbserver" +#endif using namespace lldb; using namespace lldb_private; @@ -321,6 +328,7 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac switch (status) { case eConnectionStatusTimedOut: + case eConnectionStatusInterrupted: timed_out = true; break; case eConnectionStatusSuccess: @@ -457,7 +465,8 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri assert (content_length <= m_bytes.size()); assert (total_length <= m_bytes.size()); assert (content_length <= total_length); - + const size_t content_end = content_start + content_length; + bool success = true; std::string &packet_str = packet.GetStringRef(); @@ -471,7 +480,45 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri if (!m_history.DidDumpToLog ()) m_history.Dump (log); - log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); + bool binary = false; + // Only detect binary for packets that start with a '$' and have a '#CC' checksum + if (m_bytes[0] == '$' && total_length > 4) + { + for (size_t i=0; !binary && i<total_length; ++i) + { + if (isprint(m_bytes[i]) == 0) + binary = true; + } + } + if (binary) + { + StreamString strm; + // Packet header... + strm.Printf("<%4" PRIu64 "> read packet: %c", (uint64_t)total_length, m_bytes[0]); + for (size_t i=content_start; i<content_end; ++i) + { + // Remove binary escaped bytes when displaying the packet... + const char ch = m_bytes[i]; + if (ch == 0x7d) + { + // 0x7d is the escape character. The next character is to + // be XOR'd with 0x20. + const char escapee = m_bytes[++i] ^ 0x20; + strm.Printf("%2.2x", escapee); + } + else + { + strm.Printf("%2.2x", (uint8_t)ch); + } + } + // Packet footer... + strm.Printf("%c%c%c", m_bytes[total_length-3], m_bytes[total_length-2], m_bytes[total_length-1]); + log->PutCString(strm.GetString().c_str()); + } + else + { + log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); + } } m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length); @@ -482,7 +529,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri // run-length encoding in the process. // Reserve enough byte for the most common case (no RLE used) packet_str.reserve(m_bytes.length()); - for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_start + content_length; ++c) + for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_end; ++c) { if (*c == '*') { @@ -610,6 +657,10 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, lldb_private::ProcessLaunchInfo &launch_info, uint16_t &out_port) { + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port); + out_port = in_port; Error error; // If we locate debugserver, keep that located version around @@ -622,24 +673,34 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, // to the debugserver to use and use it if we do. const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); if (env_debugserver_path) + { debugserver_file_spec.SetFile (env_debugserver_path, false); + if (log) + log->Printf ("GDBRemoteCommunication::%s() gdb-remote stub exe path set from environment variable: %s", __FUNCTION__, env_debugserver_path); + } else debugserver_file_spec = g_debugserver_file_spec; bool debugserver_exists = debugserver_file_spec.Exists(); if (!debugserver_exists) { // The debugserver binary is in the LLDB.framework/Resources - // directory. - if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) + // directory. + if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, debugserver_file_spec)) { - debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); + debugserver_file_spec.AppendPathComponent (DEBUGSERVER_BASENAME); debugserver_exists = debugserver_file_spec.Exists(); if (debugserver_exists) { + if (log) + log->Printf ("GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); + g_debugserver_file_spec = debugserver_file_spec; } else { + if (log) + log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); + g_debugserver_file_spec.Clear(); debugserver_file_spec.Clear(); } @@ -690,9 +751,9 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, // Binding to port zero, we need to figure out what port it ends up // using using a named pipe... FileSpec tmpdir_file_spec; - if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) + if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { - tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX"); + tmpdir_file_spec.AppendPathComponent("debugserver-named-pipe.XXXXXX"); strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path)); } else @@ -702,7 +763,7 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, if (::mktemp (named_pipe_path)) { -#if defined(_MSC_VER) +#if defined(_WIN32) if ( false ) #else if (::mkfifo(named_pipe_path, 0600) == 0) @@ -722,21 +783,28 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, { // No host and port given, so lets listen on our end and make the debugserver // connect to us.. - error = StartListenThread ("localhost", 0); + error = StartListenThread ("127.0.0.1", 0); if (error.Fail()) return error; ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); - out_port = connection->GetBoundPort(3); - assert (out_port != 0); - char port_cstr[32]; - snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_port); - // Send the host and port down that debugserver and specify an option - // so that it connects back to the port we are listening to in this process - debugserver_args.AppendArgument("--reverse-connect"); - debugserver_args.AppendArgument(port_cstr); + // Wait for 10 seconds to resolve the bound port + out_port = connection->GetListeningPort(10); + if (out_port > 0) + { + char port_cstr[32]; + snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_port); + // Send the host and port down that debugserver and specify an option + // so that it connects back to the port we are listening to in this process + debugserver_args.AppendArgument("--reverse-connect"); + debugserver_args.AppendArgument(port_cstr); + } + else + { + error.SetErrorString ("failed to bind to port 0 on 127.0.0.1"); + return error; + } } - const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); if (env_debugserver_log_file) @@ -751,7 +819,25 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } - + + // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back. + uint32_t env_var_index = 1; + bool has_env_var; + do + { + char env_var_name[64]; + snprintf (env_var_name, sizeof (env_var_name), "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++); + const char *extra_arg = getenv(env_var_name); + has_env_var = extra_arg != nullptr; + + if (has_env_var) + { + debugserver_args.AppendArgument (extra_arg); + if (log) + log->Printf ("GDBRemoteCommunication::%s adding env var %s contents to stub command line (%s)", __FUNCTION__, env_var_name, extra_arg); + } + } while (has_env_var); + // Close STDIN, STDOUT and STDERR. We might need to redirect them // to "/dev/null" if we run into any problems. launch_info.AppendCloseFileAction (STDIN_FILENO); @@ -760,31 +846,34 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, error = Host::LaunchProcess(launch_info); - if (named_pipe_path[0]) + if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { - File name_pipe_file; - error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); - if (error.Success()) + if (named_pipe_path[0]) { - 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(); + File name_pipe_file; + error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); + 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(); + } + FileSystem::Unlink(named_pipe_path); + } + else if (listen) + { + + } + else + { + // Make sure we actually connect with the debugserver... + JoinListenThread(); } - Host::Unlink(named_pipe_path); - } - else if (listen) - { - - } - else - { - // Make sure we actually connect with the debugserver... - JoinListenThread(); } } else diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index d8361113ddc8..b11d38563207 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -271,7 +271,7 @@ protected: lldb_private::Error - StartListenThread (const char *hostname = "localhost", + StartListenThread (const char *hostname = "127.0.0.1", uint16_t port = 0); bool diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index ab3bf7f5aa2a..5e4ed7648f95 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -17,6 +17,7 @@ #include <sstream> // Other libraries and framework includes +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include "lldb/Interpreter/Args.h" #include "lldb/Core/ConnectionFileDescriptor.h" @@ -26,7 +27,9 @@ #include "lldb/Core/StreamString.h" #include "lldb/Host/Endian.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Target/Target.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -37,7 +40,7 @@ using namespace lldb; using namespace lldb_private; -#ifdef LLDB_DISABLE_POSIX +#if defined(LLDB_DISABLE_POSIX) && !defined(SIGSTOP) #define SIGSTOP 17 #endif @@ -56,7 +59,9 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_supports_vCont_s (eLazyBoolCalculate), m_supports_vCont_S (eLazyBoolCalculate), m_qHostInfo_is_valid (eLazyBoolCalculate), + m_curr_pid_is_valid (eLazyBoolCalculate), m_qProcessInfo_is_valid (eLazyBoolCalculate), + m_qGDBServerVersion_is_valid (eLazyBoolCalculate), m_supports_alloc_dealloc_memory (eLazyBoolCalculate), m_supports_memory_region_info (eLazyBoolCalculate), m_supports_watchpoint_support_info (eLazyBoolCalculate), @@ -65,10 +70,14 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply (eLazyBoolCalculate), m_supports_p (eLazyBoolCalculate), + m_supports_x (eLazyBoolCalculate), + m_avoid_g_packets (eLazyBoolCalculate), m_supports_QSaveRegisterState (eLazyBoolCalculate), + m_supports_qXfer_auxv_read (eLazyBoolCalculate), m_supports_qXfer_libraries_read (eLazyBoolCalculate), m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate), m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate), + m_supports_jThreadExtendedInfo (eLazyBoolCalculate), m_supports_qProcessInfoPID (true), m_supports_qfProcessInfo (true), m_supports_qUserName (true), @@ -81,6 +90,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_supports_z4 (true), m_supports_QEnvironment (true), m_supports_QEnvironmentHexEncoded (true), + m_curr_pid (LLDB_INVALID_PROCESS_ID), m_curr_tid (LLDB_INVALID_THREAD_ID), m_curr_tid_run (LLDB_INVALID_THREAD_ID), m_num_supported_hardware_watchpoints (0), @@ -90,6 +100,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_async_result (PacketResult::Success), m_async_response (), m_async_signal (-1), + m_interrupt_sent (false), m_thread_id_to_used_usec_map (), m_host_arch(), m_process_arch(), @@ -99,6 +110,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_os_build (), m_os_kernel (), m_hostname (), + m_gdb_server_name(), + m_gdb_server_version(UINT32_MAX), m_default_packet_timeout (0), m_max_packet_size (0) { @@ -187,6 +200,16 @@ GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported () return (m_supports_qXfer_libraries_read == eLazyBoolYes); } +bool +GDBRemoteCommunicationClient::GetQXferAuxvReadSupported () +{ + if (m_supports_qXfer_auxv_read == eLazyBoolCalculate) + { + GetRemoteQSupported(); + } + return (m_supports_qXfer_auxv_read == eLazyBoolYes); +} + uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() { @@ -205,8 +228,18 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported () m_send_acks = true; m_supports_not_sending_acks = eLazyBoolNo; + // This is the first real packet that we'll send in a debug session and it may take a little + // longer than normal to receive a reply. Wait at least 6 seconds for a reply to this packet. + + const uint32_t minimum_timeout = 6; + uint32_t old_timeout = GetPacketTimeoutInMicroSeconds() / lldb_private::TimeValue::MicroSecPerSec; + SetPacketTimeout (std::max (old_timeout, minimum_timeout)); + StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success) + PacketResult packet_send_result = SendPacketAndWaitForResponse("QStartNoAckMode", response, false); + SetPacketTimeout (old_timeout); + + if (packet_send_result == PacketResult::Success) { if (response.IsOKResponse()) { @@ -287,13 +320,18 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_vCont_s = eLazyBoolCalculate; m_supports_vCont_S = eLazyBoolCalculate; m_supports_p = eLazyBoolCalculate; + m_supports_x = eLazyBoolCalculate; m_supports_QSaveRegisterState = eLazyBoolCalculate; m_qHostInfo_is_valid = eLazyBoolCalculate; + m_curr_pid_is_valid = eLazyBoolCalculate; m_qProcessInfo_is_valid = eLazyBoolCalculate; + m_qGDBServerVersion_is_valid = eLazyBoolCalculate; m_supports_alloc_dealloc_memory = eLazyBoolCalculate; m_supports_memory_region_info = eLazyBoolCalculate; m_prepare_for_reg_writing_reply = eLazyBoolCalculate; m_attach_or_wait_reply = eLazyBoolCalculate; + m_avoid_g_packets = eLazyBoolCalculate; + m_supports_qXfer_auxv_read = eLazyBoolCalculate; m_supports_qXfer_libraries_read = eLazyBoolCalculate; m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; @@ -310,8 +348,18 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_z4 = true; m_supports_QEnvironment = true; m_supports_QEnvironmentHexEncoded = true; + m_host_arch.Clear(); m_process_arch.Clear(); + m_os_version_major = UINT32_MAX; + m_os_version_minor = UINT32_MAX; + m_os_version_update = UINT32_MAX; + m_os_build.clear(); + m_os_kernel.clear(); + m_hostname.clear(); + m_gdb_server_name.clear(); + m_gdb_server_version = UINT32_MAX; + m_default_packet_timeout = 0; m_max_packet_size = 0; } @@ -320,8 +368,9 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported () { // Clear out any capabilities we expect to see in the qSupported response - m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; + m_supports_qXfer_auxv_read = eLazyBoolNo; m_supports_qXfer_libraries_read = eLazyBoolNo; + m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; m_supports_augmented_libraries_svr4_read = eLazyBoolNo; m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if not, we assume no limit @@ -331,6 +380,8 @@ GDBRemoteCommunicationClient::GetRemoteQSupported () /*send_async=*/false) == PacketResult::Success) { const char *response_cstr = response.GetStringRef().c_str(); + if (::strstr (response_cstr, "qXfer:auxv:read+")) + m_supports_qXfer_auxv_read = eLazyBoolYes; if (::strstr (response_cstr, "qXfer:libraries-svr4:read+")) m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; if (::strstr (response_cstr, "augmented-libraries-svr4-read")) @@ -457,6 +508,42 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid) return m_supports_p; } +bool +GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported () +{ + if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate) + { + StringExtractorGDBRemote response; + m_supports_jThreadExtendedInfo = eLazyBoolNo; + if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + { + m_supports_jThreadExtendedInfo = eLazyBoolYes; + } + } + } + return m_supports_jThreadExtendedInfo; +} + +bool +GDBRemoteCommunicationClient::GetxPacketSupported () +{ + if (m_supports_x == eLazyBoolCalculate) + { + StringExtractorGDBRemote response; + m_supports_x = eLazyBoolNo; + char packet[256]; + snprintf (packet, sizeof (packet), "x0,0"); + if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + m_supports_x = eLazyBoolYes; + } + } + return m_supports_x; +} + GDBRemoteCommunicationClient::PacketResult GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses ( @@ -502,11 +589,8 @@ GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses { return PacketResult::ErrorReplyInvalid; } - // Skip past m or l - const char *s = this_string.c_str() + 1; - - // Concatenate the result so far - response_string += s; + // Concatenate the result so far (skipping 'm' or 'l') + response_string.append(this_string, 1, std::string::npos); if (first_char == 'l') // We're done return PacketResult::Success; @@ -550,7 +634,6 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse PacketResult packet_result = PacketResult::ErrorSendFailed; Mutex::Locker locker; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - size_t response_len = 0; if (GetSequenceMutex (locker)) { packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); @@ -588,7 +671,6 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse // Swap the response buffer to avoid malloc and string copy response.GetStringRef().swap (m_async_response.GetStringRef()); - response_len = response.GetStringRef().size(); packet_result = m_async_result; } else @@ -772,6 +854,8 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str()); if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) state = eStateInvalid; + else + m_interrupt_sent = false; m_private_is_running.SetValue (true, eBroadcastAlways); } @@ -1047,7 +1131,7 @@ GDBRemoteCommunicationClient::SendAsyncSignal (int signo) // then the caller that requested the interrupt will want to keep the sequence // locked down so that no one else can send packets while the caller has control. // This function usually gets called when we are running and need to stop the -// target. It can also be used when we are running and and we need to do something +// target. It can also be used when we are running and we need to do something // else (like read/write memory), so we need to interrupt the running process // (gdb remote protocol requires this), and do what we need to do, then resume. @@ -1128,13 +1212,40 @@ GDBRemoteCommunicationClient::SendInterrupt lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID () { - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success) + if (m_curr_pid_is_valid == eLazyBoolYes) + return m_curr_pid; + + // First try to retrieve the pid via the qProcessInfo request. + GetCurrentProcessInfo (); + if (m_curr_pid_is_valid == eLazyBoolYes) + { + // We really got it. + return m_curr_pid; + } + else { - if (response.GetChar() == 'Q') - if (response.GetChar() == 'C') - return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID); + // If we don't get a response for qProcessInfo, check if $qC gives us a result. + // $qC only returns a real process id on older debugserver and lldb-platform stubs. + // The gdb remote protocol documents $qC as returning the thread id, which newer + // debugserver and lldb-gdbserver stubs return correctly. + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success) + { + if (response.GetChar() == 'Q') + { + if (response.GetChar() == 'C') + { + m_curr_pid = response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID); + if (m_curr_pid != LLDB_INVALID_PROCESS_ID) + { + m_curr_pid_is_valid = eLazyBoolYes; + return m_curr_pid; + } + } + } + } } + return LLDB_INVALID_PROCESS_ID; } @@ -1168,7 +1279,7 @@ int GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info) { // Since we don't get the send argv0 separate from the executable path, we need to - // make sure to use the actual exectuable path found in the launch_info... + // make sure to use the actual executable path found in the launch_info... std::vector<const char *> argv; FileSpec exe_file = launch_info.GetExecutableFile(); std::string exe_path; @@ -1304,6 +1415,41 @@ GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch) return -1; } +int +GDBRemoteCommunicationClient::SendLaunchEventDataPacket (char const *data, bool *was_supported) +{ + if (data && *data != '\0') + { + StreamString packet; + packet.Printf("QSetProcessEvent:%s", data); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + { + if (was_supported) + *was_supported = true; + return 0; + } + else if (response.IsUnsupportedResponse()) + { + if (was_supported) + *was_supported = false; + return -1; + } + else + { + uint8_t error = response.GetError(); + if (was_supported) + *was_supported = true; + if (error) + return error; + } + } + } + return -1; +} + bool GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major, uint32_t &minor, @@ -1384,10 +1530,75 @@ GDBRemoteCommunicationClient::GetProcessArchitecture () return m_process_arch; } +bool +GDBRemoteCommunicationClient::GetGDBServerVersion() +{ + if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) + { + m_gdb_server_name.clear(); + m_gdb_server_version = 0; + m_qGDBServerVersion_is_valid = eLazyBoolNo; + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success) + { + if (response.IsNormalResponse()) + { + std::string name; + std::string value; + bool success = false; + while (response.GetNameColonValue(name, value)) + { + if (name.compare("name") == 0) + { + success = true; + m_gdb_server_name.swap(value); + } + else if (name.compare("version") == 0) + { + size_t dot_pos = value.find('.'); + if (dot_pos != std::string::npos) + value[dot_pos] = '\0'; + const uint32_t version = Args::StringToUInt32(value.c_str(), UINT32_MAX, 0); + if (version != UINT32_MAX) + { + success = true; + m_gdb_server_version = version; + } + } + } + if (success) + m_qGDBServerVersion_is_valid = eLazyBoolYes; + } + } + } + return m_qGDBServerVersion_is_valid == eLazyBoolYes; +} + +const char * +GDBRemoteCommunicationClient::GetGDBServerProgramName() +{ + if (GetGDBServerVersion()) + { + if (!m_gdb_server_name.empty()) + return m_gdb_server_name.c_str(); + } + return NULL; +} + +uint32_t +GDBRemoteCommunicationClient::GetGDBServerProgramVersion() +{ + if (GetGDBServerVersion()) + return m_gdb_server_version; + return 0; +} bool GDBRemoteCommunicationClient::GetHostInfo (bool force) { + Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS)); + if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) { m_qHostInfo_is_valid = eLazyBoolNo; @@ -1432,10 +1643,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) } else if (name.compare("triple") == 0) { - // The triple comes as ASCII hex bytes since it contains '-' chars - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (triple); + triple.swap(value); ++num_keys_decoded; } else if (name.compare ("distribution_id") == 0) @@ -1548,6 +1756,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { switch (m_host_arch.GetMachine()) { + case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::thumb: os_name = "ios"; @@ -1588,6 +1797,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { switch (m_host_arch.GetMachine()) { + case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::thumb: host_triple.setOS(llvm::Triple::IOS); @@ -1619,6 +1829,9 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { assert (byte_order == m_host_arch.GetByteOrder()); } + + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s parsed host architecture as %s, triple as %s from triple text %s", __FUNCTION__, m_host_arch.GetArchitectureName () ? m_host_arch.GetArchitectureName () : "<null-arch-name>", m_host_arch.GetTriple ().getTriple ().c_str(), triple.c_str ()); } if (!distribution_id.empty ()) m_host_arch.SetDistributionId (distribution_id.c_str ()); @@ -1682,7 +1895,9 @@ GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions) StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { - if (!response.IsErrorResponse()) + if (response.IsUnsupportedResponse()) + m_supports_alloc_dealloc_memory = eLazyBoolNo; + else if (!response.IsErrorResponse()) return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); } else @@ -1705,7 +1920,9 @@ GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr) StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { - if (response.IsOKResponse()) + if (response.IsUnsupportedResponse()) + m_supports_alloc_dealloc_memory = eLazyBoolNo; + else if (response.IsOKResponse()) return true; } else @@ -1746,14 +1963,16 @@ GDBRemoteCommunicationClient::Detach (bool keep_stopped) } else { - PacketResult packet_result = SendPacket ("D1", 2); + StringExtractorGDBRemote response; + PacketResult packet_result = SendPacketAndWaitForResponse ("D1", 1, response, false); if (packet_result != PacketResult::Success) error.SetErrorString ("Sending extended disconnect packet failed."); } } else { - PacketResult packet_result = SendPacket ("D", 1); + StringExtractorGDBRemote response; + PacketResult packet_result = SendPacketAndWaitForResponse ("D", 1, response, false); if (packet_result != PacketResult::Success) error.SetErrorString ("Sending disconnect packet failed."); } @@ -2051,6 +2270,25 @@ GDBRemoteCommunicationClient::SetDisableASLR (bool enable) return -1; } +int +GDBRemoteCommunicationClient::SetDetachOnError (bool enable) +{ + char packet[32]; + const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDetachOnError:%i", enable ? 1 : 0); + assert (packet_len < (int)sizeof(packet)); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + return -1; +} + + bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info) { @@ -2093,10 +2331,6 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot } else if (name.compare("triple") == 0) { - // The triple comes as ASCII hex bytes since it contains '-' chars - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (value); process_info.GetArchitecture ().SetTriple (value.c_str()); } else if (name.compare("name") == 0) @@ -2192,8 +2426,8 @@ 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)) { if (name.compare("cputype") == 0) @@ -2208,6 +2442,11 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () if (sub != 0) ++num_keys_decoded; } + else if (name.compare("triple") == 0) + { + triple = value; + ++num_keys_decoded; + } else if (name.compare("ostype") == 0) { os_name.swap (value); @@ -2220,15 +2459,10 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () } else if (name.compare("endian") == 0) { - ++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; + if (value.compare("little") == 0 || + value.compare("big") == 0 || + value.compare("pdp") == 0) + ++num_keys_decoded; } else if (name.compare("ptrsize") == 0) { @@ -2236,20 +2470,42 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () if (pointer_byte_size != 0) ++num_keys_decoded; } + else if (name.compare("pid") == 0) + { + pid = Args::StringToUInt64(value.c_str(), 0, 16); + if (pid != LLDB_INVALID_PROCESS_ID) + ++num_keys_decoded; + } } if (num_keys_decoded > 0) m_qProcessInfo_is_valid = eLazyBoolYes; - if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty()) + if (pid != LLDB_INVALID_PROCESS_ID) + { + m_curr_pid_is_valid = eLazyBoolYes; + m_curr_pid = pid; + } + + // Set the ArchSpec from the triple if we have it. + if (!triple.empty ()) + { + m_process_arch.SetTriple (triple.c_str ()); + if (pointer_byte_size) + { + assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); + } + } + else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty()) { m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub); if (pointer_byte_size) { assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); } + 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)); - return true; } + return true; } } else @@ -2333,7 +2589,7 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat const ArchSpec &match_arch = match_info.GetProcessInfo().GetArchitecture(); const llvm::Triple &triple = match_arch.GetTriple(); packet.PutCString("triple:"); - packet.PutCStringAsRawHex8(triple.getTriple().c_str()); + packet.PutCString(triple.getTriple().c_str()); packet.PutChar (';'); } } @@ -2429,8 +2685,8 @@ GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets) { static uint32_t g_send_sizes[] = { 0, 64, 128, 512, 1024 }; static uint32_t g_recv_sizes[] = { 0, 64, 128, 512, 1024 }; //, 4*1024, 8*1024, 16*1024, 32*1024, 48*1024, 64*1024, 96*1024, 128*1024 }; - const size_t k_num_send_sizes = sizeof(g_send_sizes)/sizeof(uint32_t); - const size_t k_num_recv_sizes = sizeof(g_recv_sizes)/sizeof(uint32_t); + const size_t k_num_send_sizes = llvm::array_lengthof(g_send_sizes); + const size_t k_num_recv_sizes = llvm::array_lengthof(g_recv_sizes); const uint64_t k_recv_amount = 4*1024*1024; // Receive 4MB for (uint32_t send_idx = 0; send_idx < k_num_send_sizes; ++send_idx) { @@ -2539,7 +2795,7 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const hostname = remote_accept_hostname; else { - if (Host::GetHostname (hostname)) + if (HostInfo::GetHostname(hostname)) { // Make the GDB server we launch only accept connections from this host stream.Printf("host:%s;", hostname.c_str()); @@ -2687,7 +2943,7 @@ GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, type, addr, length); - // Check we havent overwritten the end of the packet buffer + // Check we haven't overwritten the end of the packet buffer assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; // Try to send the breakpoint packet, and check that it was correctly sent @@ -2715,7 +2971,7 @@ GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, } } } - // Signal generic faliure + // Signal generic failure return UINT8_MAX; } @@ -2977,7 +3233,7 @@ GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &fil else { const uint32_t mode = response.GetS32(-1); - if (mode == -1) + if (static_cast<int32_t>(mode) == -1) { if (response.GetChar() == ',') { @@ -3217,6 +3473,38 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s } bool +GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process) +{ + // Some targets have issues with g/G packets and we need to avoid using them + if (m_avoid_g_packets == eLazyBoolCalculate) + { + if (process) + { + m_avoid_g_packets = eLazyBoolNo; + const ArchSpec &arch = process->GetTarget().GetArchitecture(); + if (arch.IsValid() + && arch.GetTriple().getVendor() == llvm::Triple::Apple + && arch.GetTriple().getOS() == llvm::Triple::IOS + && arch.GetTriple().getArch() == llvm::Triple::aarch64) + { + m_avoid_g_packets = eLazyBoolYes; + uint32_t gdb_server_version = GetGDBServerProgramVersion(); + if (gdb_server_version != 0) + { + const char *gdb_server_name = GetGDBServerProgramName(); + if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0) + { + if (gdb_server_version >= 310) + m_avoid_g_packets = eLazyBoolNo; + } + } + } + } + } + return m_avoid_g_packets == eLazyBoolYes; +} + +bool GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response) { Mutex::Locker locker; @@ -3309,7 +3597,7 @@ GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save bool GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id) { - // We use the "m_supports_QSaveRegisterState" variable here becuase the + // We use the "m_supports_QSaveRegisterState" variable here because the // QSaveRegisterState and QRestoreRegisterState packets must both be supported in // order to be useful if (m_supports_QSaveRegisterState == eLazyBoolNo) diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index a1e982b3ec4e..fddcd6cd1426 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -92,7 +92,7 @@ public: // indicates if the packet was send and any response was received // even in the response is UNIMPLEMENTED. If the packet failed to // get a response, then false is returned. This quickly tells us - // if we were able to connect and communicte with the remote GDB + // if we were able to connect and communicate with the remote GDB // server bool QueryNoAckModeSupported (); @@ -159,6 +159,10 @@ public: int SendLaunchArchPacket (const char *arch); + + int + SendLaunchEventDataPacket (const char *data, bool *was_supported = NULL); + //------------------------------------------------------------------ /// Sends a "vAttach:PID" where PID is in hex. /// @@ -201,13 +205,25 @@ public: /// be launched with the 'A' packet. /// /// @param[in] enable - /// A boolean value indicating wether to disable ASLR or not. + /// A boolean value indicating whether to disable ASLR or not. /// /// @return /// Zero if the for success, or an error code for failure. //------------------------------------------------------------------ int SetDisableASLR (bool enable); + + //------------------------------------------------------------------ + /// Sets the DetachOnError flag to \a enable for the process controlled by the stub. + /// + /// @param[in] enable + /// A boolean value indicating whether to detach on error or not. + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int + SetDetachOnError (bool enable); //------------------------------------------------------------------ /// Sets the working directory to \a path for a process that will @@ -217,7 +233,7 @@ public: /// directory for the platform process. /// /// @param[in] path - /// The path to a directory to use when launching our processs + /// The path to a directory to use when launching our process /// /// @return /// Zero if the for success, or an error code for failure. @@ -279,6 +295,9 @@ public: GetpPacketSupported (lldb::tid_t tid); bool + GetxPacketSupported (); + + bool GetVAttachOrWaitSupported (); bool @@ -384,6 +403,9 @@ public: SetCurrentThreadForRun (uint64_t tid); bool + GetQXferAuxvReadSupported (); + + bool GetQXferLibrariesReadSupported (); bool @@ -491,7 +513,19 @@ public: bool RestoreRegisterState (lldb::tid_t tid, uint32_t save_id); + + const char * + GetGDBServerProgramName(); + uint32_t + GetGDBServerProgramVersion(); + + bool + AvoidGPackets(ProcessGDBRemote *process); + + bool + GetThreadExtendedInfoSupported(); + protected: PacketResult @@ -502,6 +536,9 @@ protected: bool GetCurrentProcessInfo (); + bool + GetGDBServerVersion(); + //------------------------------------------------------------------ // Classes that inherit from GDBRemoteCommunicationClient can see and modify these //------------------------------------------------------------------ @@ -515,7 +552,9 @@ protected: lldb_private::LazyBool m_supports_vCont_s; lldb_private::LazyBool m_supports_vCont_S; lldb_private::LazyBool m_qHostInfo_is_valid; + lldb_private::LazyBool m_curr_pid_is_valid; lldb_private::LazyBool m_qProcessInfo_is_valid; + lldb_private::LazyBool m_qGDBServerVersion_is_valid; lldb_private::LazyBool m_supports_alloc_dealloc_memory; lldb_private::LazyBool m_supports_memory_region_info; lldb_private::LazyBool m_supports_watchpoint_support_info; @@ -524,10 +563,14 @@ protected: lldb_private::LazyBool m_attach_or_wait_reply; lldb_private::LazyBool m_prepare_for_reg_writing_reply; lldb_private::LazyBool m_supports_p; + lldb_private::LazyBool m_supports_x; + lldb_private::LazyBool m_avoid_g_packets; lldb_private::LazyBool m_supports_QSaveRegisterState; + lldb_private::LazyBool m_supports_qXfer_auxv_read; lldb_private::LazyBool m_supports_qXfer_libraries_read; lldb_private::LazyBool m_supports_qXfer_libraries_svr4_read; lldb_private::LazyBool m_supports_augmented_libraries_svr4_read; + lldb_private::LazyBool m_supports_jThreadExtendedInfo; bool m_supports_qProcessInfoPID:1, @@ -543,7 +586,7 @@ protected: m_supports_QEnvironment:1, m_supports_QEnvironmentHexEncoded:1; - + lldb::pid_t m_curr_pid; lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for continue, step, etc @@ -570,6 +613,8 @@ protected: std::string m_os_build; std::string m_os_kernel; std::string m_hostname; + std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if qGDBServerVersion is not supported + uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if qGDBServerVersion is not supported uint32_t m_default_packet_timeout; uint64_t m_max_packet_size; // as returned by qSupported diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index df95542d2c0f..ffcdd169eb9f 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -9,24 +9,38 @@ #include <errno.h> +#include "lldb/Host/Config.h" + #include "GDBRemoteCommunicationServer.h" #include "lldb/Core/StreamGDBRemote.h" // C Includes // C++ Includes +#include <cstring> +#include <chrono> +#include <thread> + // 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/Debug.h" #include "lldb/Host/Endian.h" #include "lldb/Host/File.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Target/FileAction.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" +#include "lldb/Target/NativeRegisterContext.h" +#include "Host/common/NativeProcessProtocol.h" +#include "Host/common/NativeThreadProtocol.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -37,6 +51,22 @@ using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- +// GDBRemote Errors +//---------------------------------------------------------------------- + +namespace +{ + enum GDBRemoteServerError + { + // Set to the first unused error number in literal form below + eErrorFirst = 29, + eErrorNoProcess = eErrorFirst, + eErrorResume, + eErrorExitStatus + }; +} + +//---------------------------------------------------------------------- // GDBRemoteCommunicationServer constructor //---------------------------------------------------------------------- GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : @@ -50,12 +80,28 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : m_proc_infos (), m_proc_infos_index (0), m_port_map (), - m_port_offset(0) + m_port_offset(0), + m_current_tid (LLDB_INVALID_THREAD_ID), + m_continue_tid (LLDB_INVALID_THREAD_ID), + m_debugged_process_mutex (Mutex::eMutexTypeRecursive), + m_debugged_process_sp (), + m_debugger_sp (), + m_stdio_communication ("process.stdio"), + m_exit_now (false), + m_inferior_prev_state (StateType::eStateInvalid), + m_thread_suffix_supported (false), + m_list_threads_in_stop_reply (false), + m_active_auxv_buffer_sp (), + m_saved_registers_mutex (), + m_saved_registers_map (), + m_next_saved_registers_id (1) { + assert(is_platform && "must be lldb-platform if debugger is not specified"); } GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform, - const lldb::PlatformSP& platform_sp) : + const lldb::PlatformSP& platform_sp, + lldb::DebuggerSP &debugger_sp) : GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), m_platform_sp (platform_sp), m_async_thread (LLDB_INVALID_HOST_THREAD), @@ -66,9 +112,24 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform, m_proc_infos (), m_proc_infos_index (0), m_port_map (), - m_port_offset(0) + m_port_offset(0), + m_current_tid (LLDB_INVALID_THREAD_ID), + m_continue_tid (LLDB_INVALID_THREAD_ID), + m_debugged_process_mutex (Mutex::eMutexTypeRecursive), + m_debugged_process_sp (), + m_debugger_sp (debugger_sp), + m_stdio_communication ("process.stdio"), + m_exit_now (false), + m_inferior_prev_state (StateType::eStateInvalid), + m_thread_suffix_supported (false), + m_list_threads_in_stop_reply (false), + m_active_auxv_buffer_sp (), + m_saved_registers_mutex (), + m_saved_registers_map (), + m_next_saved_registers_id (1) { assert(platform_sp); + assert((is_platform || debugger_sp) && "must specify non-NULL debugger_sp when lldb-gdbserver"); } //---------------------------------------------------------------------- @@ -78,37 +139,14 @@ GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() { } - -//void * -//GDBRemoteCommunicationServer::AsyncThread (void *arg) -//{ -// GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg; -// -// Log *log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); -// if (log) -// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID()); -// -// StringExtractorGDBRemote packet; -// -// while () -// { -// if (packet. -// } -// -// if (log) -// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID()); -// -// process->m_async_thread = LLDB_INVALID_HOST_THREAD; -// return NULL; -//} -// -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, Error &error, bool &interrupt, bool &quit) { StringExtractorGDBRemote packet; + PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec); if (packet_result == PacketResult::Success) { @@ -124,11 +162,6 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, quit = true; break; - case StringExtractorGDBRemote::eServerPacketType_interrupt: - error.SetErrorString("interrupt received"); - interrupt = true; - break; - default: case StringExtractorGDBRemote::eServerPacketType_unimplemented: packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); @@ -164,6 +197,7 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_k: packet_result = Handle_k (packet); + quit = true; break; case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess: @@ -174,6 +208,10 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, packet_result = Handle_qGroupName (packet); break; + case StringExtractorGDBRemote::eServerPacketType_qProcessInfo: + packet_result = Handle_qProcessInfo (packet); + break; + case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID: packet_result = Handle_qProcessInfoPID (packet); break; @@ -202,6 +240,10 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, packet_result = Handle_QSetDisableASLR (packet); break; + case StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError: + packet_result = Handle_QSetDetachOnError (packet); + break; + case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN: packet_result = Handle_QSetSTDIN (packet); break; @@ -234,6 +276,26 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, packet_result = Handle_qPlatform_shell (packet); break; + case StringExtractorGDBRemote::eServerPacketType_C: + packet_result = Handle_C (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_c: + packet_result = Handle_c (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_vCont: + packet_result = Handle_vCont (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_vCont_actions: + packet_result = Handle_vCont_actions (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_stop_reason: // ? + packet_result = Handle_stop_reason (packet); + break; + case StringExtractorGDBRemote::eServerPacketType_vFile_open: packet_result = Handle_vFile_Open (packet); break; @@ -277,6 +339,96 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: packet_result = Handle_vFile_unlink (packet); break; + + case StringExtractorGDBRemote::eServerPacketType_qRegisterInfo: + packet_result = Handle_qRegisterInfo (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qfThreadInfo: + packet_result = Handle_qfThreadInfo (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qsThreadInfo: + packet_result = Handle_qsThreadInfo (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_p: + packet_result = Handle_p (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_P: + packet_result = Handle_P (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_H: + packet_result = Handle_H (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_m: + packet_result = Handle_m (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_M: + packet_result = Handle_M (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported: + packet_result = Handle_qMemoryRegionInfoSupported (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo: + packet_result = Handle_qMemoryRegionInfo (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_interrupt: + if (IsGdbServer ()) + packet_result = Handle_interrupt (packet); + else + { + error.SetErrorString("interrupt received"); + interrupt = true; + } + break; + + case StringExtractorGDBRemote::eServerPacketType_Z: + packet_result = Handle_Z (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_z: + packet_result = Handle_z (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_s: + packet_result = Handle_s (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qSupported: + packet_result = Handle_qSupported (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported: + packet_result = Handle_QThreadSuffixSupported (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply: + packet_result = Handle_QListThreadsInStopReply (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read: + packet_result = Handle_qXfer_auxv_read (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState: + packet_result = Handle_QSaveRegisterState (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState: + packet_result = Handle_QRestoreRegisterState (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_vAttach: + packet_result = Handle_vAttach (packet); + break; } } else @@ -291,7 +443,12 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, error.SetErrorString("timeout"); } } - return packet_result == PacketResult::Success; + + // Check if anything occurred that would force us to want to exit. + if (m_exit_now) + quit = true; + + return packet_result; } lldb_private::Error @@ -314,6 +471,96 @@ GDBRemoteCommunicationServer::SetLaunchFlags (unsigned int launch_flags) lldb_private::Error 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 (); + else + return LaunchPlatformProcess (); +} + +lldb_private::Error +GDBRemoteCommunicationServer::LaunchDebugServerProcess () +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) + return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); + + lldb_private::Error error; + { + Mutex::Locker locker (m_debugged_process_mutex); + assert (!m_debugged_process_sp && "lldb-gdbserver creating debugged process but one already exists"); + error = m_platform_sp->LaunchNativeProcess ( + m_process_launch_info, + *this, + m_debugged_process_sp); + } + + if (!error.Success ()) + { + fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); + return error; + } + + // Setup stdout/stderr mapping from inferior. + 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); + } + + printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID ()); + + // Add to list of spawned processes. + lldb::pid_t pid; + 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__); + + } + + return error; +} + +lldb_private::Error +GDBRemoteCommunicationServer::LaunchPlatformProcess () +{ if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); @@ -337,13 +584,571 @@ GDBRemoteCommunicationServer::LaunchProcess () lldb::pid_t pid; if ( (pid = m_process_launch_info.GetProcessID()) != LLDB_INVALID_PROCESS_ID ) { + // add to spawned pids + { + Mutex::Locker locker (m_spawned_pids_mutex); + m_spawned_pids.insert(pid); + } + } + + return error; +} + +lldb_private::Error +GDBRemoteCommunicationServer::AttachToProcess (lldb::pid_t pid) +{ + Error error; + + if (!IsGdbServer ()) + { + error.SetErrorString("cannot AttachToProcess () unless process is lldb-gdbserver"); + return error; + } + + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64, __FUNCTION__, pid); + + // Scope for mutex locker. + { + // Before we try to attach, make sure we aren't already monitoring something else. + Mutex::Locker locker (m_spawned_pids_mutex); + if (!m_spawned_pids.empty ()) + { + error.SetErrorStringWithFormat ("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, *m_spawned_pids.begin()); + return error; + } + + // Try to attach. + error = m_platform_sp->AttachNativeProcess (pid, *this, m_debugged_process_sp); + if (!error.Success ()) + { + fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ()); + return error; + } + + // Setup stdout/stderr mapping from inferior. + 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); + } + + printf ("Attached to process %" PRIu64 "...\n", pid); + + // Add to list of spawned processes. + assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed"); + m_spawned_pids.insert (pid); + + return error; + } +} + +void +GDBRemoteCommunicationServer::InitializeDelegate (lldb_private::NativeProcessProtocol *process) +{ + assert (process && "process cannot be NULL"); + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", current state: %s", + __FUNCTION__, + process->GetID (), + StateAsCString (process->GetState ())); + } +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendWResponse (lldb_private::NativeProcessProtocol *process) +{ + assert (process && "process cannot be NULL"); + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // send W notification + ExitType exit_type = ExitType::eExitTypeInvalid; + int return_code = 0; + std::string exit_description; + + const bool got_exit_info = process->GetExitStatus (&exit_type, &return_code, exit_description); + if (!got_exit_info) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", failed to retrieve process exit status", __FUNCTION__, process->GetID ()); + + StreamGDBRemote response; + response.PutChar ('E'); + response.PutHex8 (GDBRemoteServerError::eErrorExitStatus); + return SendPacketNoLock(response.GetData(), response.GetSize()); + } + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", returning exit type %d, return code %d [%s]", __FUNCTION__, process->GetID (), exit_type, return_code, exit_description.c_str ()); + + StreamGDBRemote response; + + 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::eExitTypeInvalid: + default: return_type_code = 'E'; break; + } + response.PutChar (return_type_code); + + // POSIX exit status limited to unsigned 8 bits. + response.PutHex8 (return_code); + + return SendPacketNoLock(response.GetData(), response.GetSize()); + } +} + +static void +AppendHexValue (StreamString &response, const uint8_t* buf, uint32_t buf_size, bool swap) +{ + int64_t i; + if (swap) + { + for (i = buf_size-1; i >= 0; i--) + response.PutHex8 (buf[i]); + } + else + { + for (i = 0; i < buf_size; i++) + response.PutHex8 (buf[i]); + } +} + +static void +WriteRegisterValueInHexFixedWidth (StreamString &response, + NativeRegisterContextSP ®_ctx_sp, + const RegisterInfo ®_info, + const RegisterValue *reg_value_p) +{ + RegisterValue reg_value; + if (!reg_value_p) + { + Error error = reg_ctx_sp->ReadRegister (®_info, reg_value); + if (error.Success ()) + reg_value_p = ®_value; + // else log. + } + + if (reg_value_p) + { + AppendHexValue (response, (const uint8_t*) reg_value_p->GetBytes (), reg_value_p->GetByteSize (), false); + } + else + { + // Zero-out any unreadable values. + if (reg_info.byte_size > 0) + { + std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0'); + AppendHexValue (response, zeros.data(), zeros.size(), false); + } + } +} + +// WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value); + + +static void +WriteGdbRegnumWithFixedWidthHexRegisterValue (StreamString &response, + NativeRegisterContextSP ®_ctx_sp, + const RegisterInfo ®_info, + const RegisterValue ®_value) +{ + // Output the register number as 'NN:VVVVVVVV;' where NN is a 2 bytes HEX + // gdb register number, and VVVVVVVV is the correct number of hex bytes + // as ASCII for the register value. + if (reg_info.kinds[eRegisterKindGDB] == LLDB_INVALID_REGNUM) + return; + + response.Printf ("%.02x:", reg_info.kinds[eRegisterKindGDB]); + WriteRegisterValueInHexFixedWidth (response, reg_ctx_sp, reg_info, ®_value); + response.PutChar (';'); +} + + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendStopReplyPacketForThread (lldb::tid_t tid) +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + + // Ensure we're llgs. + if (!IsGdbServer ()) + { + // Only supported on llgs + return SendUnimplementedResponse (""); + } + + // Ensure we have a debugged process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse (50); + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s preparing packet for pid %" PRIu64 " tid %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID (), tid); + + // Ensure we can get info on the given thread. + NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); + if (!thread_sp) + return SendErrorResponse (51); + + // Grab the reason this thread stopped. + struct ThreadStopInfo tid_stop_info; + if (!thread_sp->GetStopReason (tid_stop_info)) + return SendErrorResponse (52); + + const bool did_exec = tid_stop_info.reason == eStopReasonExec; + // FIXME implement register handling for exec'd inferiors. + // if (did_exec) + // { + // const bool force = true; + // InitializeRegisters(force); + // } + + StreamString response; + // Output the T packet with the thread + response.PutChar ('T'); + int signum = tid_stop_info.details.signal.signo; + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64, + __FUNCTION__, + m_debugged_process_sp->GetID (), + tid, + signum, + tid_stop_info.reason, + tid_stop_info.details.exception.type); + } + + switch (tid_stop_info.reason) + { + case eStopReasonSignal: + case eStopReasonException: + signum = thread_sp->TranslateStopInfoToGdbSignal (tid_stop_info); + break; + default: + signum = 0; + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " has stop reason %d, using signo = 0 in stop reply response", + __FUNCTION__, + m_debugged_process_sp->GetID (), + tid, + tid_stop_info.reason); + } + break; + } + + // Print the signal number. + response.PutHex8 (signum & 0xff); + + // Include the 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]) + { + size_t thread_name_len = strlen(thread_name); + + if (::strcspn (thread_name, "$#+-;:") == thread_name_len) + { + response.PutCString ("name:"); + response.PutCString (thread_name); + } + else + { + // The thread name contains special chars, send as hex bytes. + response.PutCString ("hexname:"); + response.PutCStringAsRawHex8 (thread_name); + } + response.PutChar (';'); + } + + // FIXME look for analog + // thread_identifier_info_data_t thread_ident_info; + // if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info)) + // { + // if (thread_ident_info.dispatch_qaddr != 0) + // ostrm << std::hex << "qaddr:" << thread_ident_info.dispatch_qaddr << ';'; + // } + + // If a 'QListThreadsInStopReply' was sent to enable this feature, we + // will send all thread IDs back in the "threads" key whose value is + // a list of hex thread IDs separated by commas: + // "threads:10a,10b,10c;" + // This will save the debugger from having to send a pair of qfThreadInfo + // and qsThreadInfo packets, but it also might take a lot of room in the + // stop reply packet, so it must be enabled only on systems where there + // are no limits on packet lengths. + if (m_list_threads_in_stop_reply) + { + response.PutCString ("threads:"); + + uint32_t thread_index = 0; + NativeThreadProtocolSP listed_thread_sp; + for (listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); listed_thread_sp; ++thread_index, listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) + { + if (thread_index > 0) + response.PutChar (','); + response.Printf ("%" PRIx64, listed_thread_sp->GetID ()); + } + response.PutChar (';'); + } + + // + // Expedite registers. + // + + // Grab the register context. + NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext (); + if (reg_ctx_sp) + { + // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers. + const RegisterSet *reg_set_p; + if (reg_ctx_sp->GetRegisterSetCount () > 0 && ((reg_set_p = reg_ctx_sp->GetRegisterSet (0)) != nullptr)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s expediting registers from set '%s' (registers set count: %zu)", __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", reg_set_p->num_registers); + + for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) + { + const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex (*reg_num_p); + if (reg_info_p == nullptr) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to get register info for register set '%s', register index %" PRIu32, __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", *reg_num_p); + } + else if (reg_info_p->value_regs == nullptr) + { + // Only expediate registers that are not contained in other registers. + RegisterValue reg_value; + Error error = reg_ctx_sp->ReadRegister (reg_info_p, reg_value); + if (error.Success ()) + WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value); + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, reg_info_p->name ? reg_info_p->name : "<unnamed-register>", *reg_num_p, error.AsCString ()); + + } + } + } + } + } + + if (did_exec) + { + response.PutCString ("reason:exec;"); + } + else if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) + { + response.PutCString ("metype:"); + response.PutHex64 (tid_stop_info.details.exception.type); + response.PutCString (";mecount:"); + response.PutHex32 (tid_stop_info.details.exception.data_count); + response.PutChar (';'); + + for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) + { + response.PutCString ("medata:"); + response.PutHex64 (tid_stop_info.details.exception.data[i]); + response.PutChar (';'); + } + } + + return SendPacketNoLock (response.GetData(), response.GetSize()); +} + +void +GDBRemoteCommunicationServer::HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process) +{ + assert (process && "process cannot be NULL"); + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); + + // Send the exit result, and don't flush output. + // Note: flushing output here would join the inferior stdio reflection thread, which + // would gunk up the waitpid monitor thread that is calling this. + PacketResult result = SendStopReasonForState (StateType::eStateExited, false); + if (result != PacketResult::Success) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); + } + + // Remove the process from the list of spawned pids. + { Mutex::Locker locker (m_spawned_pids_mutex); - m_spawned_pids.insert(pid); + if (m_spawned_pids.erase (process->GetID ()) < 1) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to remove PID %" PRIu64 " from the spawned pids list", __FUNCTION__, process->GetID ()); + + } } + // FIXME can't do this yet - since process state propagation is currently + // synchronous, it is running off the NativeProcessProtocol's innards and + // will tear down the NPP while it still has code to execute. +#if 0 + // Clear the NativeProcessProtocol pointer. + { + Mutex::Locker locker (m_debugged_process_mutex); + m_debugged_process_sp.reset(); + } +#endif + + // Close the pipe to the inferior terminal i/o if we launched it + // and set one up. Otherwise, 'k' and its flush of stdio could + // end up waiting on a thread join that will never end. Consider + // adding a timeout to the connection thread join call so we + // can avoid that scenario altogether. + MaybeCloseInferiorTerminalConnection (); + + // We are ready to exit the debug monitor. + m_exit_now = true; +} + +void +GDBRemoteCommunicationServer::HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process) +{ + assert (process && "process cannot be NULL"); + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); + + // Send the stop reason unless this is the stop after the + // launch or attach. + switch (m_inferior_prev_state) + { + case eStateLaunching: + case eStateAttaching: + // Don't send anything per debugserver behavior. + break; + default: + // In all other cases, send the stop reason. + PacketResult result = SendStopReasonForState (StateType::eStateStopped, false); + if (result != PacketResult::Success) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); + } + break; + } +} + +void +GDBRemoteCommunicationServer::ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state) +{ + assert (process && "process cannot be NULL"); + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", state: %s", + __FUNCTION__, + process->GetID (), + StateAsCString (state)); + } + + switch (state) + { + case StateType::eStateExited: + HandleInferiorState_Exited (process); + break; + + case StateType::eStateStopped: + HandleInferiorState_Stopped (process); + break; + + default: + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s didn't handle state change for pid %" PRIu64 ", new state: %s", + __FUNCTION__, + process->GetID (), + StateAsCString (state)); + } + break; + } + + // Remember the previous state reported to us. + m_inferior_prev_state = state; +} + +void +GDBRemoteCommunicationServer::DidExec (NativeProcessProtocol *process) +{ + ClearProcessSpecificData (); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendONotification (const char *buffer, uint32_t len) +{ + if ((buffer == nullptr) || (len == 0)) + { + // Nothing to send. + return PacketResult::Success; + } + + StreamString response; + response.PutChar ('O'); + response.PutBytesAsRawHex8 (buffer, len); + + return SendPacketNoLock (response.GetData (), response.GetSize ()); +} + +lldb_private::Error +GDBRemoteCommunicationServer::SetSTDIOFileDescriptor (int fd) +{ + Error error; + + // Set up the Read Thread for reading/handling process I/O + std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true)); + if (!conn_up) + { + error.SetErrorString ("failed to create ConnectionFileDescriptor"); + return error; + } + + m_stdio_communication.SetConnection (conn_up.release()); + if (!m_stdio_communication.IsConnected ()) + { + error.SetErrorString ("failed to set connection for inferior I/O communication"); + return error; + } + + m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this); + m_stdio_communication.StartReadThread(); + return error; } +void +GDBRemoteCommunicationServer::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len) +{ + GDBRemoteCommunicationServer *server = reinterpret_cast<GDBRemoteCommunicationServer*> (baton); + static_cast<void> (server->SendONotification (static_cast<const char *>(src), src_len)); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *) { @@ -351,6 +1156,7 @@ GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *) return SendPacketNoLock ("", 0); } + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err) { @@ -360,6 +1166,14 @@ GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err) return SendPacketNoLock (packet, packet_len); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendIllFormedResponse (const StringExtractorGDBRemote &failed_packet, const char *message) +{ + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", __FUNCTION__, failed_packet.GetStringRef ().c_str (), message ? message : ""); + return SendErrorResponse (0x03); +} GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendOKResponse () @@ -380,10 +1194,10 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00 - ArchSpec host_arch (Host::GetArchitecture ()); + ArchSpec host_arch(HostInfo::GetArchitecture()); const llvm::Triple &host_triple = host_arch.GetTriple(); response.PutCString("triple:"); - response.PutCStringAsRawHex8(host_triple.getTriple().c_str()); + response.PutCString(host_triple.getTriple().c_str()); response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize()); const char* distribution_id = host_arch.GetDistributionId ().AsCString (); @@ -394,6 +1208,8 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet response.PutCString(";"); } + // Only send out MachO info when lldb-platform/llgs is running on a MachO host. +#if defined(__APPLE__) uint32_t cpu = host_arch.GetMachOCPUType(); uint32_t sub = host_arch.GetMachOCPUSubType(); if (cpu != LLDB_INVALID_CPUTYPE) @@ -405,6 +1221,9 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. else response.Printf("watchpoint_exceptions_received:after;"); +#else + response.Printf("watchpoint_exceptions_received:after;"); +#endif switch (lldb::endian::InlHostByteOrder()) { @@ -417,7 +1236,7 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet uint32_t major = UINT32_MAX; uint32_t minor = UINT32_MAX; uint32_t update = UINT32_MAX; - if (Host::GetOSVersion (major, minor, update)) + if (HostInfo::GetOSVersion(major, minor, update)) { if (major != UINT32_MAX) { @@ -433,39 +1252,41 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet } std::string s; - if (Host::GetOSBuildString (s)) +#if !defined(__linux__) + if (HostInfo::GetOSBuildString(s)) { response.PutCString ("os_build:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } - if (Host::GetOSKernelDescription (s)) + if (HostInfo::GetOSKernelDescription(s)) { response.PutCString ("os_kernel:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } +#endif + #if defined(__APPLE__) -#if defined(__arm__) +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) // For iOS devices, we are connected through a USB Mux so we never pretend // to actually have a hostname as far as the remote lldb that is connecting // to this lldb-platform is concerned response.PutCString ("hostname:"); - response.PutCStringAsRawHex8("localhost"); + response.PutCStringAsRawHex8("127.0.0.1"); response.PutChar(';'); -#else // #if defined(__arm__) - if (Host::GetHostname (s)) +#else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + if (HostInfo::GetHostname(s)) { response.PutCString ("hostname:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } - -#endif // #if defined(__arm__) +#endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) #else // #if defined(__APPLE__) - if (Host::GetHostname (s)) + if (HostInfo::GetHostname(s)) { response.PutCString ("hostname:"); response.PutCStringAsRawHex8(s.c_str()); @@ -494,11 +1315,105 @@ CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &r { const llvm::Triple &proc_triple = proc_arch.GetTriple(); response.PutCString("triple:"); - response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); + response.PutCString(proc_triple.getTriple().c_str()); response.PutChar(';'); } } +static void +CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info, StreamString &response) +{ + response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;", + proc_info.GetProcessID(), + proc_info.GetParentProcessID(), + proc_info.GetUserID(), + proc_info.GetGroupID(), + proc_info.GetEffectiveUserID(), + proc_info.GetEffectiveGroupID()); + + const ArchSpec &proc_arch = proc_info.GetArchitecture(); + if (proc_arch.IsValid()) + { + const llvm::Triple &proc_triple = proc_arch.GetTriple(); +#if defined(__APPLE__) + // We'll send cputype/cpusubtype. + const uint32_t cpu_type = proc_arch.GetMachOCPUType(); + if (cpu_type != 0) + response.Printf ("cputype:%" PRIx32 ";", cpu_type); + + const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType(); + if (cpu_subtype != 0) + response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype); + + + const std::string vendor = proc_triple.getVendorName (); + if (!vendor.empty ()) + response.Printf ("vendor:%s;", vendor.c_str ()); +#else + // We'll send the triple. + response.Printf ("triple:%s;", proc_triple.getTriple().c_str ()); +#endif + std::string ostype = proc_triple.getOSName (); + // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. + if (proc_triple.getVendor () == llvm::Triple::Apple) + { + switch (proc_triple.getArch ()) + { + case llvm::Triple::arm: + case llvm::Triple::aarch64: + ostype = "ios"; + break; + default: + // No change. + break; + } + } + response.Printf ("ostype:%s;", ostype.c_str ()); + + + switch (proc_arch.GetByteOrder ()) + { + case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break; + case lldb::eByteOrderBig: response.PutCString ("endian:big;"); break; + case lldb::eByteOrderPDP: response.PutCString ("endian:pdp;"); break; + default: + // Nothing. + break; + } + + if (proc_triple.isArch64Bit ()) + response.PutCString ("ptrsize:8;"); + else if (proc_triple.isArch32Bit ()) + response.PutCString ("ptrsize:4;"); + else if (proc_triple.isArch16Bit ()) + response.PutCString ("ptrsize:2;"); + } + +} + + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_qProcessInfo (StringExtractorGDBRemote &packet) +{ + // Only the gdb server handles this. + if (!IsGdbServer ()) + return SendUnimplementedResponse (packet.GetStringRef ().c_str ()); + + // Fail if we don't have a current process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse (68); + + ProcessInstanceInfo proc_info; + if (Host::GetProcessInfo (m_debugged_process_sp->GetID (), proc_info)) + { + StreamString response; + CreateProcessInfoResponse_DebugServerStyle(proc_info, response); + return SendPacketNoLock (response.GetData (), response.GetSize ()); + } + + return SendErrorResponse (1); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet) { @@ -635,19 +1550,21 @@ GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &pa GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet) { +#if !defined(LLDB_DISABLE_POSIX) // Packet format: "qUserName:%i" where %i is the uid packet.SetFilePos(::strlen ("qUserName:")); uint32_t uid = packet.GetU32 (UINT32_MAX); if (uid != UINT32_MAX) { std::string name; - if (Host::GetUserName (uid, name)) + if (HostInfo::LookupUserName(uid, name)) { StreamString response; response.PutCStringAsRawHex8 (name.c_str()); return SendPacketNoLock (response.GetData(), response.GetSize()); } } +#endif return SendErrorResponse (5); } @@ -655,19 +1572,21 @@ GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet) { +#if !defined(LLDB_DISABLE_POSIX) // Packet format: "qGroupName:%i" where %i is the gid packet.SetFilePos(::strlen ("qGroupName:")); uint32_t gid = packet.GetU32 (UINT32_MAX); if (gid != UINT32_MAX) { std::string name; - if (Host::GetGroupName (gid, name)) + if (HostInfo::LookupGroupName(gid, name)) { StreamString response; response.PutCStringAsRawHex8 (name.c_str()); return SendPacketNoLock (response.GetData(), response.GetSize()); } } +#endif return SendErrorResponse (6); } @@ -708,27 +1627,6 @@ GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packe return SendErrorResponse (7); } - -static void * -AcceptPortFromInferior (void *arg) -{ - const char *connect_url = (const char *)arg; - ConnectionFileDescriptor file_conn; - Error error; - if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess) - { - char pid_str[256]; - ::memset (pid_str, 0, sizeof(pid_str)); - ConnectionStatus status; - const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), 0, status, NULL); - if (pid_str_len > 0) - { - int pid = atoi (pid_str); - return (void *)(intptr_t)pid; - } - } - return NULL; -} // //static bool //WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds) @@ -772,6 +1670,9 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) // separated hex encoded argument value list, but we will stay true to the // documented version of the 'A' packet here... + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + int actual_arg_index = 0; + packet.SetFilePos(1); // Skip the 'A' bool success = true; while (success && packet.GetBytesLeft() > 0) @@ -788,7 +1689,7 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) success = false; else { - // Decode the argument index. We ignore this really becuase + // Decode the argument index. We ignore this really because // who would really send down the arguments in a random order??? const uint32_t arg_idx = packet.GetU32(UINT32_MAX); if (arg_idx == UINT32_MAX) @@ -804,11 +1705,11 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) // back into a UTF8 string and make sure the length // matches the one supplied in the packet std::string arg; - if (packet.GetHexByteString(arg) != (arg_len / 2)) + if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2)) success = false; else { - // If there are any bytes lft + // If there are any bytes left if (packet.GetBytesLeft()) { if (packet.GetChar() != ',') @@ -820,6 +1721,9 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) if (arg_idx == 0) m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false); m_process_launch_info.GetArguments().AppendArgument(arg.c_str()); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ()); + ++actual_arg_index; } } } @@ -830,15 +1734,20 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) if (success) { - // FIXME: remove linux restriction once eLaunchFlagDebug is supported -#if !defined (__linux__) - m_process_launch_info.GetFlags().Set (eLaunchFlagDebug); -#endif m_process_launch_error = LaunchProcess (); if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { return SendOKResponse (); } + else + { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServer::%s failed to launch exe: %s", + __FUNCTION__, + m_process_launch_error.AsCString()); + + } } return SendErrorResponse (8); } @@ -846,22 +1755,51 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet) { - lldb::pid_t pid = m_process_launch_info.GetProcessID(); StreamString response; - response.Printf("QC%" PRIx64, pid); - if (m_is_platform) + + if (IsGdbServer ()) + { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse (68); + + // Make sure we set the current thread so g and p packets return + // the data the gdb will expect. + lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); + SetCurrentThreadID (tid); + + NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread (); + if (!thread_sp) + return SendErrorResponse (69); + + response.Printf ("QC%" PRIx64, thread_sp->GetID ()); + } + else { - // If we launch a process and this GDB server is acting as a platform, - // then we need to clear the process launch state so we can start - // launching another process. In order to launch a process a bunch or - // packets need to be sent: environment packets, working directory, - // disable ASLR, and many more settings. When we launch a process we - // then need to know when to clear this information. Currently we are - // selecting the 'qC' packet as that packet which seems to make the most - // sense. - if (pid != LLDB_INVALID_PROCESS_ID) + // NOTE: lldb should now be using qProcessInfo for process IDs. This path here + // should not be used. It is reporting process id instead of thread id. The + // correct answer doesn't seem to make much sense for lldb-platform. + // CONSIDER: flip to "unsupported". + lldb::pid_t pid = m_process_launch_info.GetProcessID(); + response.Printf("QC%" PRIx64, pid); + + // this should always be platform here + assert (m_is_platform && "this code path should only be traversed for lldb-platform"); + + if (m_is_platform) { - m_process_launch_info.Clear(); + // If we launch a process and this GDB server is acting as a platform, + // then we need to clear the process launch state so we can start + // launching another process. In order to launch a process a bunch or + // packets need to be sent: environment packets, working directory, + // disable ASLR, and many more settings. When we launch a process we + // then need to know when to clear this information. Currently we are + // selecting the 'qC' packet as that packet which seems to make the most + // sense. + if (pid != LLDB_INVALID_PROCESS_ID) + { + m_process_launch_info.Clear(); + } } } return SendPacketNoLock (response.GetData(), response.GetSize()); @@ -912,17 +1850,21 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote #ifdef _WIN32 return SendErrorResponse(9); #else + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + // Spawn a local debugserver as a platform so we can then attach or launch // a process... if (m_is_platform) { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() called", __FUNCTION__); + // Sleep and wait a bit for debugserver to start to listen... ConnectionFileDescriptor file_conn; - Error error; std::string hostname; // TODO: /tmp/ should not be hardcoded. User might want to override /tmp - // with the TMPDIR environnement variable + // with the TMPDIR environment variable packet.SetFilePos(::strlen ("qLaunchGDBServer;")); std::string name; std::string value; @@ -940,53 +1882,57 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). - if (error.Success()) - { - // Spawn a debugserver and try to get the port it listens to. - ProcessLaunchInfo debugserver_launch_info; - if (hostname.empty()) - hostname = "localhost"; - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port); + // Spawn a debugserver and try to get the port it listens to. + ProcessLaunchInfo debugserver_launch_info; + if (hostname.empty()) + hostname = "127.0.0.1"; + if (log) + log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port); - debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); - - error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(), - port, - debugserver_launch_info, - port); + debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); - lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); + Error error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(), + port, + debugserver_launch_info, + port); + lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - { - Mutex::Locker locker (m_spawned_pids_mutex); - m_spawned_pids.insert(debugserver_pid); - if (port > 0) - AssociatePortWithProcess(port, debugserver_pid); - } - else - { - if (port > 0) - FreePort (port); - } - if (error.Success()) - { - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - assert (response_len < sizeof(response)); - PacketResult packet_result = SendPacketNoLock (response, response_len); + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + { + Mutex::Locker locker (m_spawned_pids_mutex); + m_spawned_pids.insert(debugserver_pid); + if (port > 0) + AssociatePortWithProcess(port, debugserver_pid); + } + else + { + if (port > 0) + FreePort (port); + } - if (packet_result != PacketResult::Success) - { - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill (debugserver_pid, SIGINT); - } - return packet_result; + if (error.Success()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); + + char response[256]; + const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); + assert (response_len < (int)sizeof(response)); + PacketResult packet_result = SendPacketNoLock (response, response_len); + + if (packet_result != PacketResult::Success) + { + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + ::kill (debugserver_pid, SIGINT); } + return packet_result; + } + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); } } return SendErrorResponse (9); @@ -1027,7 +1973,7 @@ GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid) return true; } - // the launched process still lives. Now try killling it again, + // the launched process still lives. Now try killing it again, // this time with an unblockable signal. Host::Kill (pid, SIGKILL); @@ -1107,8 +2053,11 @@ GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet) } } - // TODO figure out how to shut down gracefully at this point - return SendOKResponse (); + FlushInferiorOutput (); + + // No OK response for kill packet. + // return SendOKResponse (); + return PacketResult::Success; } GDBRemoteCommunication::PacketResult @@ -1223,7 +2172,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDIN:")); - ProcessLaunchInfo::FileAction file_action; + FileAction file_action; std::string path; packet.GetHexByteString(path); const bool read = false; @@ -1240,7 +2189,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDOUT:")); - ProcessLaunchInfo::FileAction file_action; + FileAction file_action; std::string path; packet.GetHexByteString(path); const bool read = true; @@ -1257,7 +2206,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDERR:")); - ProcessLaunchInfo::FileAction file_action; + FileAction file_action; std::string path; packet.GetHexByteString(path); const bool read = true; @@ -1271,6 +2220,288 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe } GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_C (StringExtractorGDBRemote &packet) +{ + if (!IsGdbServer ()) + return SendUnimplementedResponse (packet.GetStringRef().c_str()); + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); + + // Ensure we have a native process. + if (!m_debugged_process_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__); + return SendErrorResponse (0x36); + } + + // Pull out the signal number. + packet.SetFilePos (::strlen ("C")); + if (packet.GetBytesLeft () < 1) + { + // Shouldn't be using a C without a signal. + return SendIllFormedResponse (packet, "C packet specified without signal."); + } + const uint32_t signo = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (signo == std::numeric_limits<uint32_t>::max ()) + return SendIllFormedResponse (packet, "failed to parse signal number"); + + // Handle optional continue address. + if (packet.GetBytesLeft () > 0) + { + // FIXME add continue at address support for $C{signo}[;{continue-address}]. + if (*packet.Peek () == ';') + return SendUnimplementedResponse (packet.GetStringRef().c_str()); + else + return SendIllFormedResponse (packet, "unexpected content after $C{signal-number}"); + } + + lldb_private::ResumeActionList resume_actions (StateType::eStateRunning, 0); + Error error; + + // We have two branches: what to do if a continue thread is specified (in which case we target + // sending the signal to that thread), or when we don't have a continue thread set (in which + // case we send a signal to the process). + + // TODO discuss with Greg Clayton, make sure this makes sense. + + lldb::tid_t signal_tid = GetContinueThreadID (); + if (signal_tid != LLDB_INVALID_THREAD_ID) + { + // The resume action for the continue thread (or all threads if a continue thread is not set). + lldb_private::ResumeAction action = { GetContinueThreadID (), StateType::eStateRunning, static_cast<int> (signo) }; + + // Add the action for the continue thread (or all threads when the continue thread isn't present). + resume_actions.Append (action); + } + else + { + // Send the signal to the process since we weren't targeting a specific continue thread with the signal. + error = m_debugged_process_sp->Signal (signo); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to send signal for process %" PRIu64 ": %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + error.AsCString ()); + + return SendErrorResponse (0x52); + } + } + + // Resume the threads. + error = m_debugged_process_sp->Resume (resume_actions); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to resume threads for process %" PRIu64 ": %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + error.AsCString ()); + + return SendErrorResponse (0x38); + } + + // Don't send an "OK" packet; response is the stopped/exited message. + return PacketResult::Success; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment) +{ + if (!IsGdbServer ()) + return SendUnimplementedResponse (packet.GetStringRef().c_str()); + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); + + // We reuse this method in vCont - don't double adjust the file position. + if (!skip_file_pos_adjustment) + packet.SetFilePos (::strlen ("c")); + + // For now just support all continue. + const bool has_continue_address = (packet.GetBytesLeft () > 0); + if (has_continue_address) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s not implemented for c{address} variant [%s remains]", __FUNCTION__, packet.Peek ()); + return SendUnimplementedResponse (packet.GetStringRef().c_str()); + } + + // Ensure we have a native process. + if (!m_debugged_process_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__); + return SendErrorResponse (0x36); + } + + // Build the ResumeActionList + lldb_private::ResumeActionList actions (StateType::eStateRunning, 0); + + Error error = m_debugged_process_sp->Resume (actions); + if (error.Fail ()) + { + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s c failed for process %" PRIu64 ": %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + error.AsCString ()); + } + return SendErrorResponse (GDBRemoteServerError::eErrorResume); + } + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + + // No response required from continue. + return PacketResult::Success; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_vCont_actions (StringExtractorGDBRemote &packet) +{ + if (!IsGdbServer ()) + { + // only llgs supports $vCont. + 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"); + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_vCont (StringExtractorGDBRemote &packet) +{ + if (!IsGdbServer ()) + { + // only llgs supports $vCont + return SendUnimplementedResponse (packet.GetStringRef().c_str()); + } + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s handling vCont packet", __FUNCTION__); + + packet.SetFilePos (::strlen ("vCont")); + + // Check if this is all continue (no options or ";c"). + if (!packet.GetBytesLeft () || (::strcmp (packet.Peek (), ";c") == 0)) + { + // Move the packet past the ";c". + if (packet.GetBytesLeft ()) + packet.SetFilePos (packet.GetFilePos () + ::strlen (";c")); + + const bool skip_file_pos_adjustment = true; + return Handle_c (packet, skip_file_pos_adjustment); + } + else if (::strcmp (packet.Peek (), ";s") == 0) + { + // Move past the ';', then do a simple 's'. + packet.SetFilePos (packet.GetFilePos () + 1); + return Handle_s (packet); + } + + // Ensure we have a native process. + if (!m_debugged_process_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__); + return SendErrorResponse (0x36); + } + + ResumeActionList thread_actions; + + while (packet.GetBytesLeft () && *packet.Peek () == ';') + { + // Skip the semi-colon. + packet.GetChar (); + + // Build up the thread action. + ResumeAction thread_action; + thread_action.tid = LLDB_INVALID_THREAD_ID; + thread_action.state = eStateInvalid; + thread_action.signal = 0; + + const char action = packet.GetChar (); + switch (action) + { + case 'C': + thread_action.signal = packet.GetHexMaxU32 (false, 0); + if (thread_action.signal == 0) + return SendIllFormedResponse (packet, "Could not parse signal in vCont packet C action"); + // Fall through to next case... + + case 'c': + // Continue + thread_action.state = eStateRunning; + break; + + case 'S': + thread_action.signal = packet.GetHexMaxU32 (false, 0); + if (thread_action.signal == 0) + return SendIllFormedResponse (packet, "Could not parse signal in vCont packet S action"); + // Fall through to next case... + + case 's': + // Step + thread_action.state = eStateStepping; + break; + + default: + return SendIllFormedResponse (packet, "Unsupported vCont action"); + break; + } + + // Parse out optional :{thread-id} value. + if (packet.GetBytesLeft () && (*packet.Peek () == ':')) + { + // Consume the separator. + packet.GetChar (); + + thread_action.tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); + if (thread_action.tid == LLDB_INVALID_THREAD_ID) + return SendIllFormedResponse (packet, "Could not parse thread number in vCont packet"); + } + + thread_actions.Append (thread_action); + } + + // If a default action for all other threads wasn't mentioned + // then we should stop the threads. + thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0); + + Error error = m_debugged_process_sp->Resume (thread_actions); + if (error.Fail ()) + { + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s vCont failed for process %" PRIu64 ": %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + error.AsCString ()); + } + return SendErrorResponse (GDBRemoteServerError::eErrorResume); + } + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + + // No response required from vCont. + return PacketResult::Success; +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet) { // Send response first before changing m_send_acks to we ack this packet @@ -1288,7 +2519,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote & { std::string path; packet.GetHexByteString(path); - Error error = Host::MakeDirectory(path.c_str(),mode); + Error error = FileSystem::MakeDirectory(path.c_str(), mode); if (error.Success()) return SendPacketNoLock ("OK", 2); else @@ -1307,7 +2538,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote & { std::string path; packet.GetHexByteString(path); - Error error = Host::SetFilePermissions (path.c_str(), mode); + Error error = FileSystem::SetFilePermissions(path.c_str(), mode); if (error.Success()) return SendPacketNoLock ("OK", 2); else @@ -1457,7 +2688,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packe packet.GetHexByteString(path); if (!path.empty()) { - lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false)); + lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path.c_str(), false)); StreamString response; response.PutChar('F'); response.PutHex64(retcode); @@ -1498,7 +2729,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &pac packet.GetHexByteString(path); if (!path.empty()) { - bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false)); + bool retcode = FileSystem::GetFileExists(FileSpec(path.c_str(), false)); StreamString response; response.PutChar('F'); response.PutChar(','); @@ -1519,7 +2750,7 @@ GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &pa packet.GetHexByteStringTerminatedBy(dst, ','); packet.GetChar(); // Skip ',' char packet.GetHexByteString(src); - Error error = Host::Symlink(src.c_str(), dst.c_str()); + Error error = FileSystem::Symlink(src.c_str(), dst.c_str()); StreamString response; response.Printf("F%u,%u", error.GetError(), error.GetError()); return SendPacketNoLock(response.GetData(), response.GetSize()); @@ -1531,7 +2762,7 @@ GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &pac packet.SetFilePos(::strlen("vFile:unlink:")); std::string path; packet.GetHexByteString(path); - Error error = Host::Unlink(path.c_str()); + Error error = FileSystem::Unlink(path.c_str()); StreamString response; response.Printf("F%u,%u", error.GetError(), error.GetError()); return SendPacketNoLock(response.GetData(), response.GetSize()); @@ -1579,6 +2810,94 @@ GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote & return SendErrorResponse(24); } +void +GDBRemoteCommunicationServer::SetCurrentThreadID (lldb::tid_t tid) +{ + assert (IsGdbServer () && "SetCurrentThreadID() called when not GdbServer code"); + + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s setting current thread id to %" PRIu64, __FUNCTION__, tid); + + m_current_tid = tid; + if (m_debugged_process_sp) + m_debugged_process_sp->SetCurrentThreadID (m_current_tid); +} + +void +GDBRemoteCommunicationServer::SetContinueThreadID (lldb::tid_t tid) +{ + assert (IsGdbServer () && "SetContinueThreadID() called when not GdbServer code"); + + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s setting continue thread id to %" PRIu64, __FUNCTION__, tid); + + m_continue_tid = tid; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_stop_reason (StringExtractorGDBRemote &packet) +{ + // Handle the $? gdbremote command. + if (!IsGdbServer ()) + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_stop_reason() unimplemented"); + + // If no process, indicate error + if (!m_debugged_process_sp) + return SendErrorResponse (02); + + return SendStopReasonForState (m_debugged_process_sp->GetState (), true); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + switch (process_state) + { + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + // NOTE: gdb protocol doc looks like it should return $OK + // when everything is running (i.e. no stopped result). + return PacketResult::Success; // Ignore + + case eStateSuspended: + case eStateStopped: + case eStateCrashed: + { + lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); + // Make sure we set the current thread so g and p packets return + // the data the gdb will expect. + SetCurrentThreadID (tid); + return SendStopReplyPacketForThread (tid); + } + + case eStateInvalid: + case eStateUnloaded: + case eStateExited: + if (flush_on_exit) + FlushInferiorOutput (); + return SendWResponse(m_debugged_process_sp.get()); + + default: + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", current state reporting not handled: %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + StateAsCString (process_state)); + } + break; + } + + return SendErrorResponse (0); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet) { @@ -1595,7 +2914,7 @@ GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet { uint64_t a,b; StreamGDBRemote response; - if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false) + if (FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b) == false) { response.PutCString("F,"); response.PutCString("x"); @@ -1611,3 +2930,1385 @@ GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet return SendErrorResponse(25); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_qRegisterInfo (StringExtractorGDBRemote &packet) +{ + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qRegisterInfo() unimplemented"); + + // Fail if we don't have a current process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse (68); + + // Ensure we have a thread. + NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadAtIndex (0)); + if (!thread_sp) + return SendErrorResponse (69); + + // Get the register context for the first thread. + NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); + if (!reg_context_sp) + return SendErrorResponse (69); + + // Parse out the register number from the request. + packet.SetFilePos (strlen("qRegisterInfo")); + const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (reg_index == std::numeric_limits<uint32_t>::max ()) + return SendErrorResponse (69); + + // Return the end of registers response if we've iterated one past the end of the register set. + if (reg_index >= reg_context_sp->GetRegisterCount ()) + return SendErrorResponse (69); + + const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + return SendErrorResponse (69); + + // Build the reginfos response. + StreamGDBRemote response; + + response.PutCString ("name:"); + response.PutCString (reg_info->name); + response.PutChar (';'); + + if (reg_info->alt_name && reg_info->alt_name[0]) + { + response.PutCString ("alt-name:"); + response.PutCString (reg_info->alt_name); + response.PutChar (';'); + } + + response.Printf ("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset); + + switch (reg_info->encoding) + { + case eEncodingUint: response.PutCString ("encoding:uint;"); break; + case eEncodingSint: response.PutCString ("encoding:sint;"); break; + case eEncodingIEEE754: response.PutCString ("encoding:ieee754;"); break; + case eEncodingVector: response.PutCString ("encoding:vector;"); break; + default: break; + } + + switch (reg_info->format) + { + case eFormatBinary: response.PutCString ("format:binary;"); break; + case eFormatDecimal: response.PutCString ("format:decimal;"); break; + case eFormatHex: response.PutCString ("format:hex;"); break; + case eFormatFloat: response.PutCString ("format:float;"); break; + case eFormatVectorOfSInt8: response.PutCString ("format:vector-sint8;"); break; + case eFormatVectorOfUInt8: response.PutCString ("format:vector-uint8;"); break; + case eFormatVectorOfSInt16: response.PutCString ("format:vector-sint16;"); break; + case eFormatVectorOfUInt16: response.PutCString ("format:vector-uint16;"); break; + case eFormatVectorOfSInt32: response.PutCString ("format:vector-sint32;"); break; + case eFormatVectorOfUInt32: response.PutCString ("format:vector-uint32;"); break; + case eFormatVectorOfFloat32: response.PutCString ("format:vector-float32;"); break; + case eFormatVectorOfUInt128: response.PutCString ("format:vector-uint128;"); break; + default: break; + }; + + const char *const register_set_name = reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index); + if (register_set_name) + { + response.PutCString ("set:"); + response.PutCString (register_set_name); + response.PutChar (';'); + } + + if (reg_info->kinds[RegisterKind::eRegisterKindGCC] != LLDB_INVALID_REGNUM) + response.Printf ("gcc:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindGCC]); + + if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM) + response.Printf ("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]); + + switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric]) + { + case LLDB_REGNUM_GENERIC_PC: response.PutCString("generic:pc;"); break; + case LLDB_REGNUM_GENERIC_SP: response.PutCString("generic:sp;"); break; + case LLDB_REGNUM_GENERIC_FP: response.PutCString("generic:fp;"); break; + case LLDB_REGNUM_GENERIC_RA: response.PutCString("generic:ra;"); break; + case LLDB_REGNUM_GENERIC_FLAGS: response.PutCString("generic:flags;"); break; + case LLDB_REGNUM_GENERIC_ARG1: response.PutCString("generic:arg1;"); break; + case LLDB_REGNUM_GENERIC_ARG2: response.PutCString("generic:arg2;"); break; + case LLDB_REGNUM_GENERIC_ARG3: response.PutCString("generic:arg3;"); break; + case LLDB_REGNUM_GENERIC_ARG4: response.PutCString("generic:arg4;"); break; + case LLDB_REGNUM_GENERIC_ARG5: response.PutCString("generic:arg5;"); break; + case LLDB_REGNUM_GENERIC_ARG6: response.PutCString("generic:arg6;"); break; + case LLDB_REGNUM_GENERIC_ARG7: response.PutCString("generic:arg7;"); break; + case LLDB_REGNUM_GENERIC_ARG8: response.PutCString("generic:arg8;"); break; + default: break; + } + + if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) + { + response.PutCString ("container-regs:"); + int i = 0; + for (const uint32_t *reg_num = reg_info->value_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) + { + if (i > 0) + response.PutChar (','); + response.Printf ("%" PRIx32, *reg_num); + } + response.PutChar (';'); + } + + if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) + { + response.PutCString ("invalidate-regs:"); + int i = 0; + for (const uint32_t *reg_num = reg_info->invalidate_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) + { + if (i > 0) + response.PutChar (','); + response.Printf ("%" PRIx32, *reg_num); + } + response.PutChar (';'); + } + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_qfThreadInfo (StringExtractorGDBRemote &packet) +{ + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qfThreadInfo() unimplemented"); + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // 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() no process (%s), returning OK", __FUNCTION__, m_debugged_process_sp ? "invalid process id" : "null m_debugged_process_sp"); + return SendOKResponse (); + } + + StreamGDBRemote response; + response.PutChar ('m'); + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() starting thread iteration", __FUNCTION__); + + NativeThreadProtocolSP thread_sp; + uint32_t thread_index; + for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); + thread_sp; + ++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() iterated thread %" PRIu32 "(%s, tid=0x%" PRIx64 ")", __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", thread_sp ? thread_sp->GetID () : LLDB_INVALID_THREAD_ID); + if (thread_index > 0) + response.PutChar(','); + response.Printf ("%" PRIx64, thread_sp->GetID ()); + } + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() finished thread iteration", __FUNCTION__); + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_qsThreadInfo (StringExtractorGDBRemote &packet) +{ + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_qsThreadInfo() unimplemented"); + + // FIXME for now we return the full thread list in the initial packet and always do nothing here. + return SendPacketNoLock ("l", 1); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_p (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_p() unimplemented"); + + // Parse out the register number from the request. + packet.SetFilePos (strlen("p")); + const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (reg_index == std::numeric_limits<uint32_t>::max ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); + return SendErrorResponse (0x15); + } + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); + if (!thread_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available", __FUNCTION__); + return SendErrorResponse (0x15); + } + + // Get the thread's register context. + NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); + if (!reg_context_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); + return SendErrorResponse (0x15); + } + + // Return the end of registers response if we've iterated one past the end of the register set. + if (reg_index >= reg_context_sp->GetRegisterCount ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetRegisterCount ()); + return SendErrorResponse (0x15); + } + + const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); + return SendErrorResponse (0x15); + } + + // Build the reginfos response. + StreamGDBRemote response; + + // Retrieve the value + RegisterValue reg_value; + Error error = reg_context_sp->ReadRegister (reg_info, reg_value); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, read of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); + return SendErrorResponse (0x15); + } + + const uint8_t *const data = reinterpret_cast<const uint8_t*> (reg_value.GetBytes ()); + if (!data) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to get data bytes from requested register %" PRIu32, __FUNCTION__, reg_index); + return SendErrorResponse (0x15); + } + + // FIXME flip as needed to get data in big/little endian format for this host. + for (uint32_t i = 0; i < reg_value.GetByteSize (); ++i) + response.PutHex8 (data[i]); + + return SendPacketNoLock (response.GetData (), response.GetSize ()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_P (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_P() unimplemented"); + + // Ensure there is more content. + if (packet.GetBytesLeft () < 1) + return SendIllFormedResponse (packet, "Empty P packet"); + + // Parse out the register number from the request. + packet.SetFilePos (strlen("P")); + const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (reg_index == std::numeric_limits<uint32_t>::max ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); + return SendErrorResponse (0x29); + } + + // Note debugserver would send an E30 here. + if ((packet.GetBytesLeft () < 1) || (packet.GetChar () != '=')) + return SendIllFormedResponse (packet, "P packet missing '=' char after register number"); + + // Get process architecture. + ArchSpec process_arch; + if (!m_debugged_process_sp || !m_debugged_process_sp->GetArchitecture (process_arch)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to retrieve inferior architecture", __FUNCTION__); + return SendErrorResponse (0x49); + } + + // Parse out the value. + const uint64_t raw_value = packet.GetHexMaxU64 (process_arch.GetByteOrder () == lldb::eByteOrderLittle, std::numeric_limits<uint64_t>::max ()); + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); + if (!thread_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available (thread index 0)", __FUNCTION__); + return SendErrorResponse (0x28); + } + + // Get the thread's register context. + NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); + if (!reg_context_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); + return SendErrorResponse (0x15); + } + + const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); + return SendErrorResponse (0x48); + } + + // Return the end of registers response if we've iterated one past the end of the register set. + if (reg_index >= reg_context_sp->GetRegisterCount ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetRegisterCount ()); + return SendErrorResponse (0x47); + } + + + // Build the reginfos response. + StreamGDBRemote response; + + // FIXME Could be suffixed with a thread: parameter. + // That thread then needs to be fed back into the reg context retrieval above. + Error error = reg_context_sp->WriteRegisterFromUnsigned (reg_info, raw_value); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, write of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); + return SendErrorResponse (0x32); + } + + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_H (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_H() unimplemented"); + + // 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); + } + + // Parse out which variant of $H is requested. + packet.SetFilePos (strlen("H")); + if (packet.GetBytesLeft () < 1) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, H command missing {g,c} variant", __FUNCTION__); + return SendIllFormedResponse (packet, "H command missing {g,c} variant"); + } + + const char h_variant = packet.GetChar (); + switch (h_variant) + { + case 'g': + break; + + case 'c': + break; + + default: + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, invalid $H variant %c", __FUNCTION__, h_variant); + return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); + } + + // Parse out the thread number. + // FIXME return a parse success/fail value. All values are valid here. + const lldb::tid_t tid = packet.GetHexMaxU64 (false, std::numeric_limits<lldb::tid_t>::max ()); + + // Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread). + if (tid != LLDB_INVALID_THREAD_ID && tid != 0) + { + NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); + if (!thread_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, tid %" PRIu64 " not found", __FUNCTION__, tid); + return SendErrorResponse (0x15); + } + } + + // Now switch the given thread type. + switch (h_variant) + { + case 'g': + SetCurrentThreadID (tid); + break; + + case 'c': + SetContinueThreadID (tid); + break; + + default: + assert (false && "unsupported $H variant - shouldn't get here"); + return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); + } + + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_interrupt (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + + // Ensure we're llgs. + if (!IsGdbServer()) + { + // Only supported on llgs + return SendUnimplementedResponse (""); + } + + // 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); + } + + // Build the ResumeActionList - stop everything. + lldb_private::ResumeActionList actions (StateType::eStateStopped, 0); + + Error error = m_debugged_process_sp->Resume (actions); + if (error.Fail ()) + { + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s failed for process %" PRIu64 ": %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + error.AsCString ()); + } + return SendErrorResponse (GDBRemoteServerError::eErrorResume); + } + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s stopped process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + + // No response required from stop all. + return PacketResult::Success; +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_m (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Ensure we're llgs. + if (!IsGdbServer()) + { + // Only supported on llgs + return SendUnimplementedResponse (""); + } + + 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); + } + + // Parse out the memory address. + packet.SetFilePos (strlen("m")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short m packet"); + + // Read the address. Punting on validation. + // FIXME replace with Hex U64 read with no default value that fails on failed read. + const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); + + // Validate comma. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) + return SendIllFormedResponse(packet, "Comma sep missing in m packet"); + + // Get # bytes to read. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Length missing in m packet"); + + const uint64_t byte_count = packet.GetHexMaxU64(false, 0); + if (byte_count == 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s nothing to read: zero-length packet", __FUNCTION__); + return PacketResult::Success; + } + + // Allocate the response buffer. + std::string buf(byte_count, '\0'); + if (buf.empty()) + return SendErrorResponse (0x78); + + + // Retrieve the process memory. + lldb::addr_t bytes_read = 0; + lldb_private::Error error = m_debugged_process_sp->ReadMemory (read_addr, &buf[0], byte_count, bytes_read); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, error.AsCString ()); + return SendErrorResponse (0x08); + } + + if (bytes_read == 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, bytes_read, byte_count); + return SendErrorResponse (0x08); + } + + StreamGDBRemote response; + for (lldb::addr_t i = 0; i < bytes_read; ++i) + response.PutHex8(buf[i]); + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("QSetDetachOnError:")); + if (packet.GetU32(0)) + m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError); + else + m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError); + return SendOKResponse (); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_M (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Ensure we're llgs. + if (!IsGdbServer()) + { + // Only supported on llgs + return SendUnimplementedResponse (""); + } + + 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); + } + + // Parse out the memory address. + packet.SetFilePos (strlen("M")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short M packet"); + + // Read the address. Punting on validation. + // FIXME replace with Hex U64 read with no default value that fails on failed read. + const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0); + + // Validate comma. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) + return SendIllFormedResponse(packet, "Comma sep missing in M packet"); + + // Get # bytes to read. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Length missing in M packet"); + + const uint64_t byte_count = packet.GetHexMaxU64(false, 0); + if (byte_count == 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s nothing to write: zero-length packet", __FUNCTION__); + return PacketResult::Success; + } + + // Validate colon. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':')) + return SendIllFormedResponse(packet, "Comma sep missing in M packet after byte length"); + + // Allocate the conversion buffer. + std::vector<uint8_t> buf(byte_count, 0); + if (buf.empty()) + return SendErrorResponse (0x78); + + // Convert the hex memory write contents to bytes. + StreamGDBRemote response; + const uint64_t convert_count = static_cast<uint64_t> (packet.GetHexBytes (&buf[0], byte_count, 0)); + if (convert_count != byte_count) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": asked to write %" PRIu64 " bytes, but only found %" PRIu64 " to convert.", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count, convert_count); + return SendIllFormedResponse (packet, "M content byte length specified did not match hex-encoded content length"); + } + + // Write the process memory. + lldb::addr_t bytes_written = 0; + lldb_private::Error error = m_debugged_process_sp->WriteMemory (write_addr, &buf[0], byte_count, bytes_written); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to write. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, error.AsCString ()); + return SendErrorResponse (0x09); + } + + if (bytes_written == 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": wrote %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, bytes_written, byte_count); + return SendErrorResponse (0x09); + } + + return SendOKResponse (); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse (""); + + // Currently only the NativeProcessProtocol knows if it can handle a qMemoryRegionInfoSupported + // request, but we're not guaranteed to be attached to a process. For now we'll assume the + // client only asks this when a process is being debugged. + + // Ensure we have a process running; otherwise, we can't figure this out + // since we won't have a NativeProcessProtocol. + 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); + } + + // Test if we can get any region back when asking for the region around NULL. + MemoryRegionInfo region_info; + const Error error = m_debugged_process_sp->GetMemoryRegionInfo (0, region_info); + if (error.Fail ()) + { + // We don't support memory region info collection for this NativeProcessProtocol. + return SendUnimplementedResponse (""); + } + + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse (""); + + // Ensure we have a 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); + } + + // Parse out the memory address. + packet.SetFilePos (strlen("qMemoryRegionInfo:")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet"); + + // Read the address. Punting on validation. + const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); + + StreamGDBRemote response; + + // Get the memory region info for the target address. + MemoryRegionInfo region_info; + const Error error = m_debugged_process_sp->GetMemoryRegionInfo (read_addr, region_info); + if (error.Fail ()) + { + // Return the error message. + + response.PutCString ("error:"); + response.PutCStringAsRawHex8 (error.AsCString ()); + response.PutChar (';'); + } + else + { + // Range start and size. + response.Printf ("start:%" PRIx64 ";size:%" PRIx64 ";", region_info.GetRange ().GetRangeBase (), region_info.GetRange ().GetByteSize ()); + + // Permissions. + if (region_info.GetReadable () || + region_info.GetWritable () || + region_info.GetExecutable ()) + { + // Write permissions info. + response.PutCString ("permissions:"); + + if (region_info.GetReadable ()) + response.PutChar ('r'); + if (region_info.GetWritable ()) + response.PutChar('w'); + if (region_info.GetExecutable()) + response.PutChar ('x'); + + response.PutChar (';'); + } + } + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_Z (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse (""); + + // Ensure we have a 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); + } + + // Parse out software or hardware breakpoint requested. + packet.SetFilePos (strlen("Z")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short Z packet, missing software/hardware specifier"); + + bool want_breakpoint = true; + bool want_hardware = false; + + const char breakpoint_type_char = packet.GetChar (); + switch (breakpoint_type_char) + { + case '0': want_hardware = false; want_breakpoint = true; break; + case '1': want_hardware = true; want_breakpoint = true; break; + case '2': want_breakpoint = false; break; + case '3': want_breakpoint = false; break; + default: + return SendIllFormedResponse(packet, "Z packet had invalid software/hardware specifier"); + + } + + if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') + return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after breakpoint type"); + + // FIXME implement watchpoint support. + if (!want_breakpoint) + return SendUnimplementedResponse ("watchpoint support not yet implemented"); + + // Parse out the breakpoint address. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short Z packet, missing address"); + const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0); + + if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') + return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address"); + + // Parse out the breakpoint kind (i.e. size hint for opcode size). + const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (kind == std::numeric_limits<uint32_t>::max ()) + return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse kind argument"); + + if (want_breakpoint) + { + // Try to set the breakpoint. + const Error error = m_debugged_process_sp->SetBreakpoint (breakpoint_addr, kind, want_hardware); + if (error.Success ()) + return SendOKResponse (); + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to set breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); + return SendErrorResponse (0x09); + } + } + + // FIXME fix up after watchpoints are handled. + return SendUnimplementedResponse (""); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse (""); + + // Ensure we have a 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); + } + + // Parse out software or hardware breakpoint requested. + packet.SetFilePos (strlen("Z")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier"); + + bool want_breakpoint = true; + + const char breakpoint_type_char = packet.GetChar (); + switch (breakpoint_type_char) + { + case '0': want_breakpoint = true; break; + case '1': want_breakpoint = true; break; + case '2': want_breakpoint = false; break; + case '3': want_breakpoint = false; break; + default: + return SendIllFormedResponse(packet, "z packet had invalid software/hardware specifier"); + + } + + if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') + return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after breakpoint type"); + + // FIXME implement watchpoint support. + if (!want_breakpoint) + return SendUnimplementedResponse ("watchpoint support not yet implemented"); + + // Parse out the breakpoint address. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short z packet, missing address"); + const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0); + + if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') + return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address"); + + // Parse out the breakpoint kind (i.e. size hint for opcode size). + const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (kind == std::numeric_limits<uint32_t>::max ()) + return SendIllFormedResponse(packet, "Malformed z packet, failed to parse kind argument"); + + if (want_breakpoint) + { + // Try to set the breakpoint. + const Error error = m_debugged_process_sp->RemoveBreakpoint (breakpoint_addr); + if (error.Success ()) + return SendOKResponse (); + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to remove breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); + return SendErrorResponse (0x09); + } + } + + // FIXME fix up after watchpoints are handled. + return SendUnimplementedResponse (""); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_s (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse (""); + + // Ensure we have a 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 (0x32); + } + + // We first try to use a continue thread id. If any one or any all set, use the current thread. + // Bail out if we don't have a thread id. + lldb::tid_t tid = GetContinueThreadID (); + if (tid == 0 || tid == LLDB_INVALID_THREAD_ID) + tid = GetCurrentThreadID (); + if (tid == LLDB_INVALID_THREAD_ID) + return SendErrorResponse (0x33); + + // Double check that we have such a thread. + // TODO investigate: on MacOSX we might need to do an UpdateThreads () here. + NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID (tid); + if (!thread_sp || thread_sp->GetID () != tid) + return SendErrorResponse (0x33); + + // Create the step action for the given thread. + lldb_private::ResumeAction action = { tid, eStateStepping, 0 }; + + // Setup the actions list. + lldb_private::ResumeActionList actions; + actions.Append (action); + + // All other threads stop while we're single stepping a thread. + actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); + Error error = m_debugged_process_sp->Resume (actions); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), tid, error.AsCString ()); + return SendErrorResponse(0x49); + } + + // No response here - the stop or exit will come from the resulting action. + return PacketResult::Success; +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_qSupported (StringExtractorGDBRemote &packet) +{ + StreamGDBRemote response; + + // Features common to lldb-platform and llgs. + uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less + response.Printf ("PacketSize=%x", max_packet_size); + + response.PutCString (";QStartNoAckMode+"); + response.PutCString (";QThreadSuffixSupported+"); + response.PutCString (";QListThreadsInStopReply+"); +#if defined(__linux__) + response.PutCString (";qXfer:auxv:read+"); +#endif + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet) +{ + m_thread_suffix_supported = true; + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet) +{ + m_list_threads_in_stop_reply = true; + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet) +{ + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("only supported for lldb-gdbserver"); + + // *BSD impls should be able to do this too. +#if defined(__linux__) + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Parse out the offset. + packet.SetFilePos (strlen("qXfer:auxv:read::")); + if (packet.GetBytesLeft () < 1) + return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); + + const uint64_t auxv_offset = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ()); + if (auxv_offset == std::numeric_limits<uint64_t>::max ()) + return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); + + // Parse out comma. + if (packet.GetBytesLeft () < 1 || packet.GetChar () != ',') + return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing comma after offset"); + + // Parse out the length. + const uint64_t auxv_length = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ()); + if (auxv_length == std::numeric_limits<uint64_t>::max ()) + return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing length"); + + // Grab the auxv data if we need it. + if (!m_active_auxv_buffer_sp) + { + // Make sure we have a valid 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 (0x10); + } + + // Grab the auxv data. + m_active_auxv_buffer_sp = Host::GetAuxvData (m_debugged_process_sp->GetID ()); + if (!m_active_auxv_buffer_sp || m_active_auxv_buffer_sp->GetByteSize () == 0) + { + // Hmm, no auxv data, call that an error. + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no auxv data retrieved", __FUNCTION__); + m_active_auxv_buffer_sp.reset (); + return SendErrorResponse (0x11); + } + } + + // FIXME find out if/how I lock the stream here. + + StreamGDBRemote response; + bool done_with_buffer = false; + + if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize ()) + { + // We have nothing left to send. Mark the buffer as complete. + response.PutChar ('l'); + done_with_buffer = true; + } + else + { + // Figure out how many bytes are available starting at the given offset. + const uint64_t bytes_remaining = m_active_auxv_buffer_sp->GetByteSize () - auxv_offset; + + // Figure out how many bytes we're going to read. + const uint64_t bytes_to_read = (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length; + + // Mark the response type according to whether we're reading the remainder of the auxv data. + if (bytes_to_read >= bytes_remaining) + { + // There will be nothing left to read after this + response.PutChar ('l'); + done_with_buffer = true; + } + else + { + // There will still be bytes to read after this request. + response.PutChar ('m'); + } + + // Now write the data in encoded binary form. + response.PutEscapedBytes (m_active_auxv_buffer_sp->GetBytes () + auxv_offset, bytes_to_read); + } + + if (done_with_buffer) + m_active_auxv_buffer_sp.reset (); + + return SendPacketNoLock(response.GetData(), response.GetSize()); +#else + return SendUnimplementedResponse ("not implemented on this platform"); +#endif +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_QSaveRegisterState (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"); + + // Move past packet name. + packet.SetFilePos (strlen ("QSaveRegisterState")); + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); + if (!thread_sp) + { + if (m_thread_suffix_supported) + return SendIllFormedResponse (packet, "No thread specified in QSaveRegisterState packet"); + else + return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); + } + + // Grab the register context for the thread. + NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); + if (!reg_context_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); + return SendErrorResponse (0x15); + } + + // Save registers to a buffer. + DataBufferSP register_data_sp; + Error error = reg_context_sp->ReadAllRegisterValues (register_data_sp); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to save all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); + return SendErrorResponse (0x75); + } + + // Allocate a new save id. + const uint32_t save_id = GetNextSavedRegistersID (); + assert ((m_saved_registers_map.find (save_id) == m_saved_registers_map.end ()) && "GetNextRegisterSaveID() returned an existing register save id"); + + // Save the register data buffer under the save id. + { + Mutex::Locker locker (m_saved_registers_mutex); + m_saved_registers_map[save_id] = register_data_sp; + } + + // Write the response. + StreamGDBRemote response; + response.Printf ("%" PRIu32, save_id); + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_QRestoreRegisterState (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"); + + // Parse out save id. + packet.SetFilePos (strlen ("QRestoreRegisterState:")); + if (packet.GetBytesLeft () < 1) + return SendIllFormedResponse (packet, "QRestoreRegisterState packet missing register save id"); + + const uint32_t save_id = packet.GetU32 (0); + if (save_id == 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s QRestoreRegisterState packet has malformed save id, expecting decimal uint32_t", __FUNCTION__); + return SendErrorResponse (0x76); + } + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); + if (!thread_sp) + { + if (m_thread_suffix_supported) + return SendIllFormedResponse (packet, "No thread specified in QRestoreRegisterState packet"); + else + return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); + } + + // Grab the register context for the thread. + NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); + if (!reg_context_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); + return SendErrorResponse (0x15); + } + + // Retrieve register state buffer, then remove from the list. + DataBufferSP register_data_sp; + { + Mutex::Locker locker (m_saved_registers_mutex); + + // Find the register set buffer for the given save id. + auto it = m_saved_registers_map.find (save_id); + if (it == m_saved_registers_map.end ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " does not have a register set save buffer for id %" PRIu32, __FUNCTION__, m_debugged_process_sp->GetID (), save_id); + return SendErrorResponse (0x77); + } + register_data_sp = it->second; + + // Remove it from the map. + m_saved_registers_map.erase (it); + } + + Error error = reg_context_sp->WriteAllRegisterValues (register_data_sp); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to restore all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); + return SendErrorResponse (0x77); + } + + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_vAttach (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"); + + // Consume the ';' after vAttach. + packet.SetFilePos (strlen ("vAttach")); + if (!packet.GetBytesLeft () || packet.GetChar () != ';') + return SendIllFormedResponse (packet, "vAttach missing expected ';'"); + + // Grab the PID to which we will attach (assume hex encoding). + lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendIllFormedResponse (packet, "vAttach failed to parse the process id"); + + // Attempt to attach. + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s attempting to attach to pid %" PRIu64, __FUNCTION__, pid); + + Error error = AttachToProcess (pid); + + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to attach to pid %" PRIu64 ": %s\n", __FUNCTION__, pid, error.AsCString()); + return SendErrorResponse (0x01); + } + + // Notify we attached by sending a stop packet. + return SendStopReasonForState (m_debugged_process_sp->GetState (), true); + + return PacketResult::Success; +} + +void +GDBRemoteCommunicationServer::FlushInferiorOutput () +{ + // If we're not monitoring an inferior's terminal, ignore this. + if (!m_stdio_communication.IsConnected()) + return; + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() called", __FUNCTION__); + + // FIXME implement a timeout on the join. + m_stdio_communication.JoinReadThread(); +} + +void +GDBRemoteCommunicationServer::MaybeCloseInferiorTerminalConnection () +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Tell the stdio connection to shut down. + if (m_stdio_communication.IsConnected()) + { + auto connection = m_stdio_communication.GetConnection(); + if (connection) + { + Error error; + connection->Disconnect (&error); + + if (error.Success ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - SUCCESS", __FUNCTION__); + } + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - FAIL: %s", __FUNCTION__, error.AsCString ()); + } + } + } +} + + +lldb_private::NativeThreadProtocolSP +GDBRemoteCommunicationServer::GetThreadFromSuffix (StringExtractorGDBRemote &packet) +{ + NativeThreadProtocolSP thread_sp; + + // We have no thread if we don't have a process. + if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) + return thread_sp; + + // If the client hasn't asked for thread suffix support, there will not be a thread suffix. + // Use the current thread in that case. + if (!m_thread_suffix_supported) + { + const lldb::tid_t current_tid = GetCurrentThreadID (); + if (current_tid == LLDB_INVALID_THREAD_ID) + return thread_sp; + else if (current_tid == 0) + { + // Pick a thread. + return m_debugged_process_sp->GetThreadAtIndex (0); + } + else + return m_debugged_process_sp->GetThreadByID (current_tid); + } + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Parse out the ';'. + if (packet.GetBytesLeft () < 1 || packet.GetChar () != ';') + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected ';' prior to start of thread suffix: packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); + return thread_sp; + } + + if (!packet.GetBytesLeft ()) + return thread_sp; + + // Parse out thread: portion. + if (strncmp (packet.Peek (), "thread:", strlen("thread:")) != 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected 'thread:' but not found, packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); + return thread_sp; + } + packet.SetFilePos (packet.GetFilePos () + strlen("thread:")); + const lldb::tid_t tid = packet.GetHexMaxU64(false, 0); + if (tid != 0) + return m_debugged_process_sp->GetThreadByID (tid); + + return thread_sp; +} + +lldb::tid_t +GDBRemoteCommunicationServer::GetCurrentThreadID () const +{ + if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID) + { + // Use whatever the debug process says is the current thread id + // since the protocol either didn't specify or specified we want + // any/all threads marked as the current thread. + if (!m_debugged_process_sp) + return LLDB_INVALID_THREAD_ID; + return m_debugged_process_sp->GetCurrentThreadID (); + } + // Use the specific current thread id set by the gdb remote protocol. + return m_current_tid; +} + +uint32_t +GDBRemoteCommunicationServer::GetNextSavedRegistersID () +{ + Mutex::Locker locker (m_saved_registers_mutex); + return m_next_saved_registers_id++; +} + +void +GDBRemoteCommunicationServer::ClearProcessSpecificData () +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|GDBR_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s()", __FUNCTION__); + + // Clear any auxv cached data. + // *BSD impls should be able to do this too. +#if defined(__linux__) + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s clearing auxv buffer (previously %s)", + __FUNCTION__, + m_active_auxv_buffer_sp ? "was set" : "was not set"); + m_active_auxv_buffer_sp.reset (); +#endif +} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 913c6b673cfb..13c037c0287b 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -14,16 +14,23 @@ // C++ Includes #include <vector> #include <set> +#include <unordered_map> // Other libraries and framework includes // Project includes +#include "lldb/lldb-private-forward.h" +#include "lldb/Core/Communication.h" #include "lldb/Host/Mutex.h" #include "lldb/Target/Process.h" #include "GDBRemoteCommunication.h" +#include "../../../Host/common/NativeProcessProtocol.h" + class ProcessGDBRemote; class StringExtractorGDBRemote; -class GDBRemoteCommunicationServer : public GDBRemoteCommunication +class GDBRemoteCommunicationServer : + public GDBRemoteCommunication, + public lldb_private::NativeProcessProtocol::NativeDelegate { public: typedef std::map<uint16_t, lldb::pid_t> PortMap; @@ -38,12 +45,13 @@ public: GDBRemoteCommunicationServer(bool is_platform); GDBRemoteCommunicationServer(bool is_platform, - const lldb::PlatformSP& platform_sp); + const lldb::PlatformSP& platform_sp, + lldb::DebuggerSP& debugger_sp); virtual ~GDBRemoteCommunicationServer(); - bool + PacketResult GetPacketAndSendResponse (uint32_t timeout_usec, lldb_private::Error &error, bool &interrupt, @@ -188,6 +196,31 @@ public: lldb_private::Error LaunchProcess (); + //------------------------------------------------------------------ + /// Attach to a process. + /// + /// This method supports attaching llgs to a process accessible via the + /// configured Platform. + /// + /// @return + /// An Error object indicating the success or failure of the + /// attach operation. + //------------------------------------------------------------------ + lldb_private::Error + AttachToProcess (lldb::pid_t pid); + + //------------------------------------------------------------------ + // NativeProcessProtocol::NativeDelegate overrides + //------------------------------------------------------------------ + void + InitializeDelegate (lldb_private::NativeProcessProtocol *process) override; + + void + ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state) override; + + void + DidExec (lldb_private::NativeProcessProtocol *process) override; + protected: lldb::PlatformSP m_platform_sp; lldb::thread_t m_async_thread; @@ -199,7 +232,20 @@ protected: uint32_t m_proc_infos_index; PortMap m_port_map; uint16_t m_port_offset; - + lldb::tid_t m_current_tid; + lldb::tid_t m_continue_tid; + lldb_private::Mutex m_debugged_process_mutex; + lldb_private::NativeProcessProtocolSP m_debugged_process_sp; + lldb::DebuggerSP m_debugger_sp; + Communication m_stdio_communication; + bool m_exit_now; // use in asynchronous handling to indicate process should exit. + lldb::StateType m_inferior_prev_state; + bool m_thread_suffix_supported; + bool m_list_threads_in_stop_reply; + lldb::DataBufferSP m_active_auxv_buffer_sp; + lldb_private::Mutex m_saved_registers_mutex; + std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map; + uint32_t m_next_saved_registers_id; PacketResult SendUnimplementedResponse (const char *packet); @@ -208,9 +254,24 @@ protected: SendErrorResponse (uint8_t error); PacketResult + SendIllFormedResponse (const StringExtractorGDBRemote &packet, const char *error_message); + + PacketResult SendOKResponse (); PacketResult + SendONotification (const char *buffer, uint32_t len); + + PacketResult + SendWResponse (lldb_private::NativeProcessProtocol *process); + + PacketResult + SendStopReplyPacketForThread (lldb::tid_t tid); + + PacketResult + SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit); + + PacketResult Handle_A (StringExtractorGDBRemote &packet); PacketResult @@ -233,7 +294,10 @@ protected: PacketResult Handle_qPlatform_chmod (StringExtractorGDBRemote &packet); - + + PacketResult + Handle_qProcessInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); @@ -265,6 +329,9 @@ protected: Handle_QSetDisableASLR (StringExtractorGDBRemote &packet); PacketResult + Handle_QSetDetachOnError (StringExtractorGDBRemote &packet); + + PacketResult Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); PacketResult @@ -281,7 +348,22 @@ protected: PacketResult Handle_QSetSTDERR (StringExtractorGDBRemote &packet); - + + PacketResult + Handle_C (StringExtractorGDBRemote &packet); + + PacketResult + Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment = false); + + PacketResult + Handle_vCont (StringExtractorGDBRemote &packet); + + PacketResult + Handle_vCont_actions (StringExtractorGDBRemote &packet); + + PacketResult + Handle_stop_reason (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Open (StringExtractorGDBRemote &packet); @@ -318,6 +400,87 @@ protected: PacketResult Handle_qPlatform_shell (StringExtractorGDBRemote &packet); + PacketResult + Handle_qRegisterInfo (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qfThreadInfo (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qsThreadInfo (StringExtractorGDBRemote &packet); + + PacketResult + Handle_p (StringExtractorGDBRemote &packet); + + PacketResult + Handle_P (StringExtractorGDBRemote &packet); + + PacketResult + Handle_H (StringExtractorGDBRemote &packet); + + PacketResult + Handle_interrupt (StringExtractorGDBRemote &packet); + + PacketResult + Handle_m (StringExtractorGDBRemote &packet); + + PacketResult + Handle_M (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet); + + PacketResult + Handle_Z (StringExtractorGDBRemote &packet); + + PacketResult + Handle_z (StringExtractorGDBRemote &packet); + + PacketResult + Handle_s (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qSupported (StringExtractorGDBRemote &packet); + + PacketResult + Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet); + + PacketResult + Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet); + + PacketResult + Handle_QSaveRegisterState (StringExtractorGDBRemote &packet); + + PacketResult + Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet); + + PacketResult + Handle_vAttach (StringExtractorGDBRemote &packet); + + void + SetCurrentThreadID (lldb::tid_t tid); + + lldb::tid_t + GetCurrentThreadID () const; + + void + SetContinueThreadID (lldb::tid_t tid); + + lldb::tid_t + GetContinueThreadID () const { return m_continue_tid; } + + lldb_private::Error + SetSTDIOFileDescriptor (int fd); + + static void + STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len); + private: bool DebugserverProcessReaped (lldb::pid_t pid); @@ -342,6 +505,41 @@ private: bool KillSpawnedProcess (lldb::pid_t pid); + bool + IsGdbServer () + { + return !m_is_platform; + } + + /// Launch a process from lldb-gdbserver + lldb_private::Error + LaunchDebugServerProcess (); + + /// Launch a process from lldb-platform + lldb_private::Error + LaunchPlatformProcess (); + + void + HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process); + + void + HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process); + + void + FlushInferiorOutput (); + + lldb_private::NativeThreadProtocolSP + GetThreadFromSuffix (StringExtractorGDBRemote &packet); + + uint32_t + GetNextSavedRegistersID (); + + void + MaybeCloseInferiorTerminalConnection (); + + void + ClearProcessSpecificData (); + //------------------------------------------------------------------ // For GDBRemoteCommunicationServer only //------------------------------------------------------------------ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 73b9b3e8267e..6d7eca1a0ced 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -21,6 +21,7 @@ #include "lldb/Interpreter/PythonDataObjects.h" #endif #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" #include "lldb/Utility/Utils.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -199,7 +200,7 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE const uint32_t prim_reg = reg_info->value_regs[idx]; if (prim_reg == LLDB_INVALID_REGNUM) break; - // We have a valid primordial regsiter as our constituent. + // We have a valid primordial register as our constituent. // Grab the corresponding register info. const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); if (prim_reg_info == NULL) @@ -232,11 +233,20 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE if (&data != &m_reg_data) { +#if defined (LLDB_CONFIGURATION_DEBUG) + assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size); +#endif + // If our register context and our register info disagree, which should never happen, don't + // read past the end of the buffer. + if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) + return false; + // If we aren't extracting into our own buffer (which // only happens when this function is called from // ReadRegisterValue(uint32_t, Scalar&)) then // we transfer bytes from our buffer into the data // buffer that was passed in + data.SetByteOrder (m_reg_data.GetByteOrder()); data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size); } @@ -322,6 +332,16 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo * // if (gdb_comm.IsRunning()) // return false; + +#if defined (LLDB_CONFIGURATION_DEBUG) + assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size); +#endif + + // If our register context and our register info disagree, which should never happen, don't + // overwrite past the end of the buffer. + if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) + return false; + // Grab a pointer to where we are going to put this register uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); @@ -389,7 +409,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo * const uint32_t reg = reg_info->value_regs[idx]; if (reg == LLDB_INVALID_REGNUM) break; - // We have a valid primordial regsiter as our constituent. + // We have a valid primordial register as our constituent. // Grab the corresponding register info. const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg); if (value_reg_info == NULL) @@ -502,6 +522,8 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) StringExtractorGDBRemote response; + const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers.")) { @@ -519,29 +541,62 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) + if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsErrorResponse()) - return false; - - std::string &response_str = response.GetStringRef(); - if (isxdigit(response_str[0])) + int packet_len = 0; + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID()); + else + packet_len = ::snprintf (packet, sizeof(packet), "g"); + assert (packet_len < ((int)sizeof(packet) - 1)); + + if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { - response_str.insert(0, 1, 'G'); - if (thread_suffix_supported) + if (response.IsErrorResponse()) + return false; + + std::string &response_str = response.GetStringRef(); + if (isxdigit(response_str[0])) { - char thread_id_cstr[64]; - ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - response_str.append (thread_id_cstr); + response_str.insert(0, 1, 'G'); + if (thread_suffix_supported) + { + char thread_id_cstr[64]; + ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + response_str.append (thread_id_cstr); + } + data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size())); + return true; } - data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size())); - return true; } } + else + { + // For the use_g_packet == false case, we're going to read each register + // individually and store them as binary data in a buffer instead of as ascii + // characters. + const RegisterInfo *reg_info; + + // data_sp will take ownership of this DataBufferHeap pointer soon. + DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0)); + + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) + { + if (reg_info->value_regs) // skip registers that are slices of real registers + continue; + ReadRegisterBytes (reg_info, m_reg_data); + // ReadRegisterBytes saves the contents of the register in to the m_reg_data buffer + } + memcpy (reg_ctx->GetBytes(), m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize()); + + data_sp = reg_ctx; + return true; + } } } else { + Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); if (log) { @@ -575,6 +630,8 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + StringExtractorGDBRemote response; Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers.")) @@ -588,63 +645,126 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data // as well. const char *G_packet = (const char *)data_sp->GetBytes(); size_t G_packet_len = data_sp->GetByteSize(); - if (gdb_comm.SendPacketAndWaitForResponse (G_packet, - G_packet_len, - response, - false) == GDBRemoteCommunication::PacketResult::Success) + if (use_g_packet + && gdb_comm.SendPacketAndWaitForResponse (G_packet, + G_packet_len, + response, + false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsOKResponse()) - return true; - else if (response.IsErrorResponse()) + // The data_sp contains the entire G response packet including the + // G, and if the thread suffix is supported, it has the thread suffix + // as well. + const char *G_packet = (const char *)data_sp->GetBytes(); + size_t G_packet_len = data_sp->GetByteSize(); + if (gdb_comm.SendPacketAndWaitForResponse (G_packet, + G_packet_len, + response, + false) == GDBRemoteCommunication::PacketResult::Success) { - uint32_t num_restored = 0; - // We need to manually go through all of the registers and - // restore them manually - - response.GetStringRef().assign (G_packet, G_packet_len); - response.SetFilePos(1); // Skip the leading 'G' - DataBufferHeap buffer (m_reg_data.GetByteSize(), 0); - DataExtractor restore_data (buffer.GetBytes(), - buffer.GetByteSize(), - m_reg_data.GetByteOrder(), - m_reg_data.GetAddressByteSize()); - - const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(), - restore_data.GetByteSize(), - '\xcc'); - - if (bytes_extracted < restore_data.GetByteSize()) - restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder()); - - //ReadRegisterBytes (const RegisterInfo *reg_info, RegisterValue &value, DataExtractor &data) - const RegisterInfo *reg_info; - // We have to march the offset of each register along in the - // buffer to make sure we get the right offset. - uint32_t reg_byte_offset = 0; - for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, reg_byte_offset += reg_info->byte_size) + if (response.IsOKResponse()) + return true; + else if (response.IsErrorResponse()) { - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - // Skip composite registers. - if (reg_info->value_regs) - continue; + uint32_t num_restored = 0; + // We need to manually go through all of the registers and + // restore them manually + + response.GetStringRef().assign (G_packet, G_packet_len); + response.SetFilePos(1); // Skip the leading 'G' + + // G_packet_len is hex-ascii characters plus prefix 'G' plus suffix thread specifier. + // This means buffer will be a little more than 2x larger than necessary but we resize + // it down once we've extracted all hex ascii chars from the packet. + DataBufferHeap buffer (G_packet_len, 0); + DataExtractor restore_data (buffer.GetBytes(), + buffer.GetByteSize(), + m_reg_data.GetByteOrder(), + m_reg_data.GetAddressByteSize()); + + const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(), + restore_data.GetByteSize(), + '\xcc'); + + if (bytes_extracted < restore_data.GetByteSize()) + restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder()); + + const RegisterInfo *reg_info; + + // The g packet contents may either include the slice registers (registers defined in + // terms of other registers, e.g. eax is a subset of rax) or not. The slice registers + // should NOT be in the g packet, but some implementations may incorrectly include them. + // + // If the slice registers are included in the packet, we must step over the slice registers + // when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect. + // If the slice registers are not included, then using the byte_offset values into the + // data buffer is the best way to find individual register values. + + uint64_t size_including_slice_registers = 0; + uint64_t size_not_including_slice_registers = 0; + uint64_t size_by_highest_offset = 0; + + for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx) + { + size_including_slice_registers += reg_info->byte_size; + if (reg_info->value_regs == NULL) + size_not_including_slice_registers += reg_info->byte_size; + if (reg_info->byte_offset >= size_by_highest_offset) + size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size; + } - // Only write down the registers that need to be written - // if we are going to be doing registers individually. - bool write_reg = true; - const uint32_t reg_byte_size = reg_info->byte_size; + bool use_byte_offset_into_buffer; + if (size_by_highest_offset == restore_data.GetByteSize()) + { + // The size of the packet agrees with the highest offset: + size in the register file + use_byte_offset_into_buffer = true; + } + else if (size_not_including_slice_registers == restore_data.GetByteSize()) + { + // The size of the packet is the same as concatenating all of the registers sequentially, + // skipping the slice registers + use_byte_offset_into_buffer = true; + } + else if (size_including_slice_registers == restore_data.GetByteSize()) + { + // The slice registers are present in the packet (when they shouldn't be). + // Don't try to use the RegisterInfo byte_offset into the restore_data, it will + // point to the wrong place. + use_byte_offset_into_buffer = false; + } + else { + // None of our expected sizes match the actual g packet data we're looking at. + // The most conservative approach here is to use the running total byte offset. + use_byte_offset_into_buffer = false; + } - const char *restore_src = (const char *)restore_data.PeekData(reg_byte_offset, reg_byte_size); - if (restore_src) + // In case our register definitions don't include the correct offsets, + // keep track of the size of each reg & compute offset based on that. + uint32_t running_byte_offset = 0; + for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, running_byte_offset += reg_info->byte_size) { - if (GetRegisterIsValid(reg)) + // Skip composite aka slice registers (e.g. eax is a slice of rax). + if (reg_info->value_regs) + continue; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + uint32_t register_offset; + if (use_byte_offset_into_buffer) { - const char *current_src = (const char *)m_reg_data.PeekData(reg_byte_offset, reg_byte_size); - if (current_src) - write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0; + register_offset = reg_info->byte_offset; + } + else + { + register_offset = running_byte_offset; } - if (write_reg) + // Only write down the registers that need to be written + // if we are going to be doing registers individually. + bool write_reg = true; + const uint32_t reg_byte_size = reg_info->byte_size; + + const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size); + if (restore_src) { StreamString packet; packet.Printf ("P%x=", reg); @@ -662,14 +782,88 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data response, false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsOKResponse()) - ++num_restored; + const char *current_src = (const char *)m_reg_data.PeekData(register_offset, reg_byte_size); + if (current_src) + write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0; + } + + if (write_reg) + { + StreamString packet; + packet.Printf ("P%x=", reg); + packet.PutBytesAsRawHex8 (restore_src, + reg_byte_size, + lldb::endian::InlHostByteOrder(), + lldb::endian::InlHostByteOrder()); + + if (thread_suffix_supported) + packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + + SetRegisterIsValid(reg, false); + if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), + packet.GetString().size(), + response, + false) == GDBRemoteCommunication::PacketResult::Success) + { + if (response.IsOKResponse()) + ++num_restored; + } } } } + return num_restored > 0; + } + } + } + else + { + // For the use_g_packet == false case, we're going to write each register + // individually. The data buffer is binary data in this case, instead of + // ascii characters. + + bool arm64_debugserver = false; + if (m_thread.GetProcess().get()) + { + const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); + if (arch.IsValid() + && arch.GetMachine() == llvm::Triple::aarch64 + && arch.GetTriple().getVendor() == llvm::Triple::Apple + && arch.GetTriple().getOS() == llvm::Triple::IOS) + { + arm64_debugserver = true; + } + } + uint32_t num_restored = 0; + const RegisterInfo *reg_info; + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) + { + if (reg_info->value_regs) // skip registers that are slices of real registers + continue; + // Skip the fpsr and fpcr floating point status/control register writing to + // work around a bug in an older version of debugserver that would lead to + // register context corruption when writing fpsr/fpcr. + if (arm64_debugserver && + (strcmp (reg_info->name, "fpsr") == 0 || strcmp (reg_info->name, "fpcr") == 0)) + { + continue; + } + StreamString packet; + packet.Printf ("P%x=", reg_info->kinds[eRegisterKindLLDB]); + packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder()); + if (thread_suffix_supported) + packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + + SetRegisterIsValid(reg_info, false); + if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), + packet.GetString().size(), + response, + false) == GDBRemoteCommunication::PacketResult::Success) + { + if (response.IsOKResponse()) + ++num_restored; } - return num_restored > 0; } + return num_restored > 0; } } } @@ -693,7 +887,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data uint32_t -GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num); } diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 38f29bbca0de..b77381458914 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -98,7 +98,7 @@ public: WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); protected: friend class ThreadGDBRemote; diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 1172222d62a4..f35d954caa7b 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -56,11 +56,14 @@ #include "lldb/Target/Target.h" #include "lldb/Target/TargetList.h" #include "lldb/Target/ThreadPlanCallFunction.h" +#include "lldb/Target/SystemRuntime.h" #include "lldb/Utility/PseudoTerminal.h" // Project includes #include "lldb/Host/Host.h" +#include "Plugins/Process/Utility/FreeBSDSignals.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" +#include "Plugins/Process/Utility/LinuxSignals.h" #include "Plugins/Process/Utility/StopInfoMachException.h" #include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Utility/StringExtractorGDBRemote.h" @@ -166,8 +169,6 @@ namespace { } // anonymous namespace end -static bool rand_initialized = false; - // TODO Randomly assigning a port is unsafe. We should get an unused // ephemeral port from the kernel and make sure we reserve it before passing // it to debugserver. @@ -180,19 +181,22 @@ static bool rand_initialized = false; #define HIGH_PORT (49151u) #endif +#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) +static bool rand_initialized = false; + static inline uint16_t get_random_port () { if (!rand_initialized) { time_t seed = time(NULL); - + rand_initialized = true; srand(seed); } return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT; } - +#endif lldb_private::ConstString ProcessGDBRemote::GetPluginNameStatic() @@ -243,6 +247,7 @@ ProcessGDBRemote::CanDebug (Target &target, bool plugin_specified_by_name) case ObjectFile::eTypeObjectFile: case ObjectFile::eTypeSharedLibrary: case ObjectFile::eTypeStubLibrary: + case ObjectFile::eTypeJIT: return false; case ObjectFile::eTypeExecutable: case ObjectFile::eTypeDynamicLinker: @@ -275,7 +280,8 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) : m_continue_C_tids (), m_continue_s_tids (), m_continue_S_tids (), - m_max_memory_size (512), + m_max_memory_size (0), + m_remote_stub_max_memory_size (0), m_addr_to_mmap_size (), m_thread_create_bp_sp (), m_waiting_for_attach (false), @@ -624,6 +630,7 @@ ProcessGDBRemote::WillAttachToProcessWithName (const char *process_name, bool wa Error ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) { + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); Error error (WillLaunchOrAttach ()); if (error.Fail()) @@ -674,7 +681,11 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but no stop reply packet was received", pid, remote_url); } - if (error.Success() + if (log) + log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalizing target architecture initial triple: %s (GetTarget().GetArchitecture().IsValid() %s, m_gdb_comm.GetHostArchitecture().IsValid(): %s)", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str (), GetTarget ().GetArchitecture ().IsValid () ? "true" : "false", m_gdb_comm.GetHostArchitecture ().IsValid () ? "true" : "false"); + + + if (error.Success() && !GetTarget().GetArchitecture().IsValid() && m_gdb_comm.GetHostArchitecture().IsValid()) { @@ -685,6 +696,42 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture()); } + if (log) + log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalized target architecture triple: %s", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str ()); + + // Set the Unix signals properly for the target. + // FIXME Add a gdb-remote packet to discover dynamically. + if (error.Success ()) + { + const ArchSpec arch_spec = GetTarget ().GetArchitecture (); + if (arch_spec.IsValid ()) + { + if (log) + log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": determining unix signals type based on architecture %s, triple %s", __FUNCTION__, GetID (), arch_spec.GetArchitectureName () ? arch_spec.GetArchitectureName () : "<null>", arch_spec.GetTriple ().getTriple ().c_str ()); + + switch (arch_spec.GetTriple ().getOS ()) + { + case llvm::Triple::Linux: + SetUnixSignals (UnixSignalsSP (new process_linux::LinuxSignals ())); + if (log) + log->Printf ("ProcessGDBRemote::%s using Linux unix signals type for pid %" PRIu64, __FUNCTION__, GetID ()); + break; + case llvm::Triple::OpenBSD: + case llvm::Triple::FreeBSD: + case llvm::Triple::NetBSD: + SetUnixSignals (UnixSignalsSP (new FreeBSDSignals ())); + if (log) + log->Printf ("ProcessGDBRemote::%s using *BSD unix signals type for pid %" PRIu64, __FUNCTION__, GetID ()); + break; + default: + SetUnixSignals (UnixSignalsSP (new UnixSignals ())); + if (log) + log->Printf ("ProcessGDBRemote::%s using generic unix signals type for pid %" PRIu64, __FUNCTION__, GetID ()); + break; + } + } + } + return error; } @@ -710,23 +757,23 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) const char *stderr_path = NULL; const char *working_dir = launch_info.GetWorkingDirectory(); - const ProcessLaunchInfo::FileAction *file_action; + const FileAction *file_action; file_action = launch_info.GetFileActionForFD (STDIN_FILENO); if (file_action) { - if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen) + if (file_action->GetAction() == FileAction::eFileActionOpen) stdin_path = file_action->GetPath(); } file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); if (file_action) { - if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen) + if (file_action->GetAction() == FileAction::eFileActionOpen) stdout_path = file_action->GetPath(); } file_action = launch_info.GetFileActionForFD (STDERR_FILENO); if (file_action) { - if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen) + if (file_action->GetAction() == FileAction::eFileActionOpen) stderr_path = file_action->GetPath(); } @@ -795,9 +842,14 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) m_gdb_comm.SetSTDERR (stderr_path); m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR); + m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError); m_gdb_comm.SendLaunchArchPacket (m_target.GetArchitecture().GetArchitectureName()); + const char * launch_event_data = launch_info.GetLaunchEventData(); + if (launch_event_data != NULL && *launch_event_data != '\0') + m_gdb_comm.SendLaunchEventDataPacket (launch_event_data); + if (working_dir && working_dir[0]) { m_gdb_comm.SetWorkingDir (working_dir); @@ -958,7 +1010,7 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url) } void -ProcessGDBRemote::DidLaunchOrAttach () +ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) @@ -969,16 +1021,17 @@ ProcessGDBRemote::DidLaunchOrAttach () // See if the GDB server supports the qHostInfo information - ArchSpec gdb_remote_arch = m_gdb_comm.GetHostArchitecture(); // See if the GDB server supports the qProcessInfo packet, if so // prefer that over the Host information as it will be more specific // to our process. if (m_gdb_comm.GetProcessArchitecture().IsValid()) - gdb_remote_arch = m_gdb_comm.GetProcessArchitecture(); + process_arch = m_gdb_comm.GetProcessArchitecture(); + else + process_arch = m_gdb_comm.GetHostArchitecture(); - if (gdb_remote_arch.IsValid()) + if (process_arch.IsValid()) { ArchSpec &target_arch = GetTarget().GetArchitecture(); @@ -991,15 +1044,15 @@ ProcessGDBRemote::DidLaunchOrAttach () // it has, so we really need to take the remote host architecture as our // defacto architecture in this case. - if (gdb_remote_arch.GetMachine() == llvm::Triple::arm && - gdb_remote_arch.GetTriple().getVendor() == llvm::Triple::Apple) + if (process_arch.GetMachine() == llvm::Triple::arm && + process_arch.GetTriple().getVendor() == llvm::Triple::Apple) { - target_arch = gdb_remote_arch; + GetTarget().SetArchitecture (process_arch); } else { // Fill in what is missing in the triple - const llvm::Triple &remote_triple = gdb_remote_arch.GetTriple(); + const llvm::Triple &remote_triple = process_arch.GetTriple(); llvm::Triple &target_triple = target_arch.GetTriple(); if (target_triple.getVendorName().size() == 0) { @@ -1019,7 +1072,7 @@ ProcessGDBRemote::DidLaunchOrAttach () { // The target doesn't have a valid architecture yet, set it from // the architecture we got from the remote GDB server - target_arch = gdb_remote_arch; + GetTarget().SetArchitecture (process_arch); } } } @@ -1028,7 +1081,8 @@ ProcessGDBRemote::DidLaunchOrAttach () void ProcessGDBRemote::DidLaunch () { - DidLaunchOrAttach (); + ArchSpec process_arch; + DidLaunchOrAttach (process_arch); } Error @@ -1063,6 +1117,8 @@ 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); @@ -1100,6 +1156,8 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const Pro { StreamString packet; + m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); + if (attach_info.GetWaitForLaunch()) { if (!m_gdb_comm.GetVAttachOrWaitSupported()) @@ -1135,9 +1193,11 @@ ProcessGDBRemote::SetExitStatus (int exit_status, const char *cstr) } void -ProcessGDBRemote::DidAttach () +ProcessGDBRemote::DidAttach (ArchSpec &process_arch) { - DidLaunchOrAttach (); + // If you can figure out what the architecture is, fill it in here. + process_arch.Clear(); + DidLaunchOrAttach (process_arch); } @@ -1452,8 +1512,7 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) log->Printf( "ProcessGDBRemote::%s Making new thread: %p for thread ID: 0x%" PRIx64 ".\n", - __FUNCTION__, - thread_sp.get(), + __FUNCTION__, static_cast<void*>(thread_sp.get()), thread_sp->GetID()); } else @@ -1461,8 +1520,7 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) log->Printf( "ProcessGDBRemote::%s Found old thread: %p for thread ID: 0x%" PRIx64 ".\n", - __FUNCTION__, - thread_sp.get(), + __FUNCTION__, static_cast<void*>(thread_sp.get()), thread_sp->GetID()); } new_thread_list.AddThread(thread_sp); @@ -1557,9 +1615,9 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) log->Printf ("ProcessGDBRemote::%s Adding new thread: %p for thread ID: 0x%" PRIx64 ".\n", __FUNCTION__, - thread_sp.get(), + static_cast<void*>(thread_sp.get()), thread_sp->GetID()); - + m_thread_list_real.AddThread(thread_sp); } gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get()); @@ -1582,7 +1640,6 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) if (tid != LLDB_INVALID_THREAD_ID) m_thread_ids.push_back (tid); value.erase(0, comma_pos + 1); - } tid = Args::StringToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); if (tid != LLDB_INVALID_THREAD_ID) @@ -1709,7 +1766,6 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) thread_sp->SetStopInfo (invalid_stop_info_sp); } } - } else if (reason.compare("trap") == 0) { @@ -1734,7 +1790,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) handled = true; } } - + if (!handled && signo && did_exec == false) { if (signo == SIGTRAP) @@ -1744,7 +1800,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) handled = true; addr_t pc = thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset; lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - + if (bp_site_sp) { // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, @@ -1776,7 +1832,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) if (!handled) thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo)); } - + if (!description.empty()) { lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ()); @@ -1796,6 +1852,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) break; case 'W': + case 'X': // process exited return eStateExited; @@ -1864,10 +1921,6 @@ ProcessGDBRemote::DoDetach(bool keep_stopped) if (log) log->Printf ("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped); - DisableAllBreakpointSites (); - - m_thread_list.DiscardThreadPlans(); - error = m_gdb_comm.Detach (keep_stopped); if (log) { @@ -1928,7 +1981,7 @@ ProcessGDBRemote::DoDestroy () if (m_destroy_tried_resuming) { if (log) - log->PutCString ("ProcessGDBRemote::DoDestroy()Tried resuming to destroy once already, not doing it again."); + log->PutCString ("ProcessGDBRemote::DoDestroy() - Tried resuming to destroy once already, not doing it again."); } else { @@ -2064,7 +2117,7 @@ ProcessGDBRemote::DoDestroy () else { if (log) - log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet"); + log->Printf ("ProcessGDBRemote::DoDestroy - killed or interrupted while attaching"); exit_string.assign ("killed or interrupted while attaching."); } } @@ -2124,6 +2177,7 @@ ProcessGDBRemote::GetImageInfoAddress() size_t ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error) { + GetMaxMemorySize (); if (size > m_max_memory_size) { // Keep memory read sizes down to a sane limit. This function will be @@ -2133,7 +2187,16 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro } char packet[64]; - const int packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size); + int packet_len; + bool binary_memory_read = m_gdb_comm.GetxPacketSupported(); + if (binary_memory_read) + { + packet_len = ::snprintf (packet, sizeof(packet), "x0x%" PRIx64 ",0x%" PRIx64, (uint64_t)addr, (uint64_t)size); + } + else + { + packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size); + } assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true) == GDBRemoteCommunication::PacketResult::Success) @@ -2141,7 +2204,25 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro if (response.IsNormalResponse()) { error.Clear(); - return response.GetHexBytes(buf, size, '\xdd'); + if (binary_memory_read) + { + // The lower level GDBRemoteCommunication packet receive layer has already de-quoted any + // 0x7d character escaping that was present in the packet + + size_t data_received_size = response.GetBytesLeft(); + if (data_received_size > size) + { + // Don't write past the end of BUF if the remote debug server gave us too + // much data for some reason. + data_received_size = size; + } + memcpy (buf, response.GetStringRef().data(), data_received_size); + return data_received_size; + } + else + { + return response.GetHexBytes(buf, size, '\xdd'); + } } else if (response.IsErrorResponse()) error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr); @@ -2160,6 +2241,7 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro size_t ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error) { + GetMaxMemorySize (); if (size > m_max_memory_size) { // Keep memory read sizes down to a sane limit. This function will be @@ -2196,6 +2278,7 @@ ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Erro lldb::addr_t ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error) { + lldb_private::Log *log (lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_EXPRESSIONS)); addr_t allocated_addr = LLDB_INVALID_ADDRESS; LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory(); @@ -2221,7 +2304,11 @@ ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &er eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) m_addr_to_mmap_size[allocated_addr] = size; else + { allocated_addr = LLDB_INVALID_ADDRESS; + if (log) + log->Printf ("ProcessGDBRemote::%s no direct stub support for memory allocation, and InferiorCallMmap also failed - is stub missing register context save/restore capability?", __FUNCTION__); + } break; } @@ -2393,7 +2480,7 @@ ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site) return error; } - // We will reach here when the stub gives an unsported response to a hardware breakpoint + // We will reach here when the stub gives an unsupported response to a hardware breakpoint if (log) log->Printf("Hardware breakpoints are unsupported"); @@ -2440,8 +2527,16 @@ ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site) break; case BreakpointSite::eExternal: - if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, addr, bp_op_size)) + { + GDBStoppointType stoppoint_type; + if (bp_site->IsHardware()) + stoppoint_type = eBreakpointHardware; + else + stoppoint_type = eBreakpointSoftware; + + if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr, bp_op_size)) error.SetErrorToGenericError(); + } break; } if (error.Success()) @@ -2602,9 +2697,9 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); debugserver_launch_info.SetUserID(process_info.GetUserID()); -#if defined (__APPLE__) && defined (__arm__) +#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) // On iOS, still do a local connection using a random port - const char *hostname = "localhost"; + const char *hostname = "127.0.0.1"; uint16_t port = get_random_port (); #else // Set hostname being NULL to do the reverse connect where debugserver @@ -2918,13 +3013,33 @@ ProcessGDBRemote::AsyncThread (void *arg) break; case eStateExited: + { process->SetLastStopPacket (response); process->ClearThreadIDList(); response.SetFilePos(1); - process->SetExitStatus(response.GetHexU8(), NULL); + + int exit_status = response.GetHexU8(); + const char *desc_cstr = NULL; + StringExtractor extractor; + std::string desc_string; + if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') + { + std::string desc_token; + while (response.GetNameColonValue (desc_token, desc_string)) + { + if (desc_token == "description") + { + extractor.GetStringRef().swap(desc_string); + extractor.SetFilePos(0); + extractor.GetHexByteString (desc_string); + desc_cstr = desc_string.c_str(); + } + } + } + process->SetExitStatus(exit_status, desc_cstr); done = true; break; - + } case eStateInvalid: process->SetExitStatus(-1, "lost connection"); break; @@ -3060,6 +3175,146 @@ ProcessGDBRemote::GetDynamicLoader () return m_dyld_ap.get(); } +Error +ProcessGDBRemote::SendEventData(const char *data) +{ + int return_value; + bool was_supported; + + Error error; + + return_value = m_gdb_comm.SendLaunchEventDataPacket (data, &was_supported); + if (return_value != 0) + { + if (!was_supported) + error.SetErrorString("Sending events is not supported for this process."); + else + error.SetErrorStringWithFormat("Error sending event data: %d.", return_value); + } + return error; +} + +const DataBufferSP +ProcessGDBRemote::GetAuxvData() +{ + DataBufferSP buf; + if (m_gdb_comm.GetQXferAuxvReadSupported()) + { + std::string response_string; + if (m_gdb_comm.SendPacketsAndConcatenateResponses("qXfer:auxv:read::", response_string) == GDBRemoteCommunication::PacketResult::Success) + buf.reset(new DataBufferHeap(response_string.c_str(), response_string.length())); + } + return buf; +} + +StructuredData::ObjectSP +ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid) +{ + StructuredData::ObjectSP object_sp; + + if (m_gdb_comm.GetThreadExtendedInfoSupported()) + { + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + SystemRuntime *runtime = GetSystemRuntime(); + if (runtime) + { + runtime->AddThreadExtendedInfoPacketHints (args_dict); + } + args_dict->GetAsDictionary()->AddIntegerItem ("thread", tid); + + StreamString packet; + packet << "jThreadExtendedInfo:"; + args_dict->Dump (packet); + + // FIXME the final character of a JSON dictionary, '}', is the escape + // character in gdb-remote binary mode. lldb currently doesn't escape + // these characters in its packet output -- so we add the quoted version + // of the } character here manually in case we talk to a debugserver which + // un-escapes the characters at packet read time. + packet << (char) (0x7d ^ 0x20); + + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success) + { + StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) + { + if (!response.Empty()) + { + // The packet has already had the 0x7d xor quoting stripped out at the + // GDBRemoteCommunication packet receive level. + object_sp = StructuredData::ParseJSON (response.GetStringRef()); + } + } + } + } + return object_sp; +} + +// Establish the largest memory read/write payloads we should use. +// If the remote stub has a max packet size, stay under that size. +// +// If the remote stub's max packet size is crazy large, use a +// reasonable largeish default. +// +// If the remote stub doesn't advertise a max packet size, use a +// conservative default. + +void +ProcessGDBRemote::GetMaxMemorySize() +{ + const uint64_t reasonable_largeish_default = 128 * 1024; + const uint64_t conservative_default = 512; + + if (m_max_memory_size == 0) + { + uint64_t stub_max_size = m_gdb_comm.GetRemoteMaxPacketSize(); + if (stub_max_size != UINT64_MAX && stub_max_size != 0) + { + // Save the stub's claimed maximum packet size + m_remote_stub_max_memory_size = stub_max_size; + + // Even if the stub says it can support ginormous packets, + // don't exceed our reasonable largeish default packet size. + if (stub_max_size > reasonable_largeish_default) + { + stub_max_size = reasonable_largeish_default; + } + + m_max_memory_size = stub_max_size; + } + else + { + m_max_memory_size = conservative_default; + } + } +} + +void +ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max) +{ + if (user_specified_max != 0) + { + GetMaxMemorySize (); + + if (m_remote_stub_max_memory_size != 0) + { + if (m_remote_stub_max_memory_size < user_specified_max) + { + m_max_memory_size = m_remote_stub_max_memory_size; // user specified a packet size too big, go as big + // as the remote stub says we can go. + } + else + { + m_max_memory_size = user_specified_max; // user's packet size is good + } + } + else + { + m_max_memory_size = user_specified_max; // user's packet size is probably fine + } + } +} class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed { @@ -3101,6 +3356,53 @@ public: } }; +class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed +{ +private: + +public: + CommandObjectProcessGDBRemotePacketXferSize(CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "process plugin packet xfer-size", + "Maximum size that lldb will try to read/write one one chunk.", + NULL) + { + } + + ~CommandObjectProcessGDBRemotePacketXferSize () + { + } + + bool + DoExecute (Args& command, CommandReturnObject &result) + { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) + { + result.AppendErrorWithFormat ("'%s' takes an argument to specify the max amount to be transferred when reading/writing", m_cmd_name.c_str()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); + if (process) + { + const char *packet_size = command.GetArgumentAtIndex(0); + errno = 0; + uint64_t user_specified_max = strtoul (packet_size, NULL, 10); + if (errno == 0 && user_specified_max != 0) + { + process->SetUserSpecifiedMaxMemoryTransferSize (user_specified_max); + result.SetStatus (eReturnStatusSuccessFinishResult); + return true; + } + } + result.SetStatus (eReturnStatusFailed); + return false; + } +}; + + class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed { private: @@ -3226,6 +3528,7 @@ public: LoadSubCommand ("history", CommandObjectSP (new CommandObjectProcessGDBRemotePacketHistory (interpreter))); LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessGDBRemotePacketSend (interpreter))); LoadSubCommand ("monitor", CommandObjectSP (new CommandObjectProcessGDBRemotePacketMonitor (interpreter))); + LoadSubCommand ("xfer-size", CommandObjectSP (new CommandObjectProcessGDBRemotePacketXferSize (interpreter))); } ~CommandObjectProcessGDBRemotePacket () diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 9331775bb896..942b31c84dde 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -23,7 +23,9 @@ #include "lldb/Core/Error.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/StringList.h" +#include "lldb/Core/StructuredData.h" #include "lldb/Core/ThreadSafeValue.h" +#include "lldb/lldb-private-forward.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" @@ -113,7 +115,7 @@ public: const lldb_private::ProcessAttachInfo &attach_info); virtual void - DidAttach (); + DidAttach (lldb_private::ArchSpec &process_arch); //------------------------------------------------------------------ // PluginInterface protocol @@ -221,12 +223,17 @@ public: return m_gdb_comm; } + virtual lldb_private::Error + SendEventData(const char *data); + //---------------------------------------------------------------------- // Override SetExitStatus so we can disconnect from the remote GDB server //---------------------------------------------------------------------- virtual bool SetExitStatus (int exit_status, const char *cstr); + void + SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max); protected: friend class ThreadGDBRemote; @@ -299,6 +306,15 @@ protected: bool ParseRegisters(lldb_private::ScriptInterpreterObject *registers_array); + const lldb::DataBufferSP + GetAuxvData() override; + + lldb_private::StructuredData::ObjectSP + GetExtendedInfoForThread (lldb::tid_t tid); + + void + GetMaxMemorySize(); + //------------------------------------------------------------------ /// Broadcaster event bits definitions. //------------------------------------------------------------------ @@ -334,14 +350,15 @@ protected: tid_sig_collection m_continue_C_tids; // 'C' for continue with signal tid_collection m_continue_s_tids; // 's' for step tid_sig_collection m_continue_S_tids; // 'S' for step with signal - size_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory + uint64_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory + uint64_t m_remote_stub_max_memory_size; // The maximum memory size the remote gdb stub can handle MMapMap m_addr_to_mmap_size; lldb::BreakpointSP m_thread_create_bp_sp; bool m_waiting_for_attach; bool m_destroy_tried_resuming; lldb::CommandObjectSP m_command_sp; int64_t m_breakpoint_pc_offset; - + bool StartAsyncThread (); @@ -368,7 +385,7 @@ protected: UpdateThreadIDList (); void - DidLaunchOrAttach (); + DidLaunchOrAttach (lldb_private::ArchSpec& process_arch); lldb_private::Error ConnectToDebugserver (const char *host_port); diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index fb524deda813..5c70cb5427cb 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -107,6 +107,58 @@ ThreadGDBRemote::GetQueueID () return LLDB_INVALID_QUEUE_ID; } +QueueSP +ThreadGDBRemote::GetQueue () +{ + queue_id_t queue_id = GetQueueID(); + QueueSP queue; + if (queue_id != LLDB_INVALID_QUEUE_ID) + { + ProcessSP process_sp (GetProcess()); + if (process_sp) + { + queue = process_sp->GetQueueList().FindQueueByID (queue_id); + } + } + return queue; +} + +addr_t +ThreadGDBRemote::GetQueueLibdispatchQueueAddress () +{ + addr_t dispatch_queue_t_addr = LLDB_INVALID_ADDRESS; + if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) + { + ProcessSP process_sp (GetProcess()); + if (process_sp) + { + SystemRuntime *runtime = process_sp->GetSystemRuntime (); + if (runtime) + { + dispatch_queue_t_addr = runtime->GetLibdispatchQueueAddressFromThreadQAddress (m_thread_dispatch_qaddr); + } + } + } + return dispatch_queue_t_addr; +} + +StructuredData::ObjectSP +ThreadGDBRemote::FetchThreadExtendedInfo () +{ + StructuredData::ObjectSP object_sp; + const lldb::user_id_t tid = GetProtocolID(); + Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD)); + if (log) + log->Printf ("Fetching extended information for thread %4.4" PRIx64, tid); + ProcessSP process_sp (GetProcess()); + if (process_sp) + { + ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); + object_sp = gdb_process->GetExtendedInfoForThread (tid); + } + return object_sp; +} + void ThreadGDBRemote::WillResume (StateType resume_state) { diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index dd4cc036ef8b..a204a917ecb3 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -12,6 +12,7 @@ #include <string> +#include "lldb/Core/StructuredData.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" @@ -41,6 +42,12 @@ public: virtual lldb::queue_id_t GetQueueID (); + virtual lldb::QueueSP + GetQueue (); + + lldb::addr_t + GetQueueLibdispatchQueueAddress (); + virtual lldb::RegisterContextSP GetRegisterContext (); @@ -80,6 +87,9 @@ public: m_thread_dispatch_qaddr = thread_dispatch_qaddr; } + lldb_private::StructuredData::ObjectSP + FetchThreadExtendedInfo (); + protected: friend class ProcessGDBRemote; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp index ff2e3762556a..bc2e7a62b76e 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp @@ -92,84 +92,6 @@ DWARFAbbreviationDeclaration::IsValid() } -void -DWARFAbbreviationDeclaration::CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx) -{ - m_code = abbr_decl.Code(); // Invalidate the code since that can't be copied safely. - m_tag = abbr_decl.Tag(); - m_has_children = abbr_decl.HasChildren(); - - const DWARFAttribute::collection& attributes = abbr_decl.Attributes(); - const uint32_t num_abbr_decl_attributes = attributes.size(); - - dw_attr_t attr; - dw_form_t form; - uint32_t i; - - for (i = 0; i < num_abbr_decl_attributes; ++i) - { - attributes[i].get(attr, form); - switch (attr) - { - case DW_AT_location: - case DW_AT_frame_base: - // Only add these if they are location expressions (have a single - // value) and not location lists (have a lists of location - // expressions which are only valid over specific address ranges) - if (DWARFFormValue::IsBlockForm(form)) - m_attributes.push_back(DWARFAttribute(attr, form)); - break; - - case DW_AT_low_pc: - case DW_AT_high_pc: - case DW_AT_ranges: - case DW_AT_entry_pc: - // Don't add these attributes - if (i >= idx) - break; - // Fall through and add attribute - default: - // Add anything that isn't address related - m_attributes.push_back(DWARFAttribute(attr, form)); - break; - } - } -} - -void -DWARFAbbreviationDeclaration::CopyChangingStringToStrp( - const DWARFAbbreviationDeclaration& abbr_decl, - const DWARFDataExtractor& debug_info_data, - dw_offset_t debug_info_offset, - const DWARFCompileUnit* cu, - const uint32_t strp_min_len -) -{ - m_code = InvalidCode; - m_tag = abbr_decl.Tag(); - m_has_children = abbr_decl.HasChildren(); - - const DWARFAttribute::collection& attributes = abbr_decl.Attributes(); - const uint32_t num_abbr_decl_attributes = attributes.size(); - - dw_attr_t attr; - dw_form_t form; - uint32_t i; - lldb::offset_t offset = debug_info_offset; - - for (i = 0; i < num_abbr_decl_attributes; ++i) - { - attributes[i].get(attr, form); - dw_offset_t attr_offset = offset; - DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu); - - if (form == DW_FORM_string && ((offset - attr_offset) >= strp_min_len)) - m_attributes.push_back(DWARFAttribute(attr, DW_FORM_strp)); - else - m_attributes.push_back(DWARFAttribute(attr, form)); - } -} - uint32_t DWARFAbbreviationDeclaration::FindAttributeIndex(dw_attr_t attr) const @@ -193,19 +115,3 @@ DWARFAbbreviationDeclaration::operator == (const DWARFAbbreviationDeclaration& r && Attributes() == rhs.Attributes(); } -#if 0 -DWARFAbbreviationDeclaration::Append(BinaryStreamBuf& out_buff) const -{ - out_buff.Append32_as_ULEB128(Code()); - out_buff.Append32_as_ULEB128(Tag()); - out_buff.Append8(HasChildren()); - const uint32_t kNumAttributes = m_attributes.size(); - for (uint32_t i = 0; i < kNumAttributes; ++i) - { - out_buff.Append32_as_ULEB128(m_attributes[i].attr()); - out_buff.Append32_as_ULEB128(m_attributes[i].form()); - } - out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128) - out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128) -} -#endif // 0 diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h index 48b9ebe37ee7..0ef153a704cd 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h @@ -55,21 +55,12 @@ public: { return m_attributes[idx].get_form(); } - void CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx); - void CopyChangingStringToStrp( - const DWARFAbbreviationDeclaration& abbr_decl, - const lldb_private::DWARFDataExtractor& debug_info_data, - dw_offset_t debug_info_offset, - const DWARFCompileUnit* cu, - const uint32_t strp_min_len); uint32_t FindAttributeIndex(dw_attr_t attr) const; bool Extract(const lldb_private::DWARFDataExtractor& data, lldb::offset_t *offset_ptr); bool Extract(const lldb_private::DWARFDataExtractor& data, lldb::offset_t *offset_ptr, dw_uleb128_t code); -// void Append(BinaryStreamBuf& out_buff) const; bool IsValid(); void Dump(lldb_private::Stream *s) const; bool operator == (const DWARFAbbreviationDeclaration& rhs) const; -// DWARFAttribute::collection& Attributes() { return m_attributes; } const DWARFAttribute::collection& Attributes() const { return m_attributes; } protected: dw_uleb128_t m_code; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index cf664db28acd..b2e64ad9f8c8 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -265,12 +265,16 @@ DWARFCompileUnit::ExtractDIEsIfNeeded (bool cu_die_only) DWARFDebugInfoEntry::collection exact_size_die_array (m_die_array.begin(), m_die_array.end()); exact_size_die_array.swap (m_die_array); } - Log *log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_DEBUG_INFO | DWARF_LOG_VERBOSE)); - if (log) + Log *verbose_log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_DEBUG_INFO | DWARF_LOG_VERBOSE)); + if (verbose_log) { StreamString strm; - DWARFDebugInfoEntry::DumpDIECollection (strm, m_die_array); - log->PutCString (strm.GetString().c_str()); + Dump(&strm); + if (m_die_array.empty()) + strm.Printf("error: no DIE for compile unit"); + else + m_die_array[0].Dump(m_dwarf2Data, this, strm, UINT32_MAX); + verbose_log->PutCString (strm.GetString().c_str()); } return m_die_array.size(); @@ -357,18 +361,43 @@ DWARFCompileUnit::SetDefaultAddressSize(uint8_t addr_size) void DWARFCompileUnit::BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data, - DWARFDebugAranges* debug_aranges, - bool clear_dies_if_already_not_parsed) + DWARFDebugAranges* debug_aranges) { // This function is usually called if there in no .debug_aranges section // in order to produce a compile unit level set of address ranges that - // is accurate. If the DIEs weren't parsed, then we don't want all dies for - // all compile units to stay loaded when they weren't needed. So we can end - // up parsing the DWARF and then throwing them all away to keep memory usage - // down. + // is accurate. + + // First get the compile unit DIE only and check if it has a DW_AT_ranges + const DWARFDebugInfoEntry* die = GetCompileUnitDIEOnly(); + + const dw_offset_t cu_offset = GetOffset(); + if (die) + { + DWARFDebugRanges::RangeList ranges; + const size_t num_ranges = die->GetAttributeAddressRanges(dwarf2Data, this, ranges, false); + if (num_ranges > 0) + { + // This compile unit has DW_AT_ranges, assume this is correct if it + // is present since clang no longer makes .debug_aranges by default + // and it emits DW_AT_ranges for DW_TAG_compile_units. GCC also does + // this with recent GCC builds. + for (size_t i=0; i<num_ranges; ++i) + { + const DWARFDebugRanges::RangeList::Entry &range = ranges.GetEntryRef(i); + debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), range.GetRangeEnd()); + } + + return; // We got all of our ranges from the DW_AT_ranges attribute + } + } + // We don't have a DW_AT_ranges attribute, so we need to parse the DWARF + + // If the DIEs weren't parsed, then we don't want all dies for all compile units + // to stay loaded when they weren't needed. So we can end up parsing the DWARF + // and then throwing them all away to keep memory usage down. const bool clear_dies = ExtractDIEsIfNeeded (false) > 1; - const DWARFDebugInfoEntry* die = DIE(); + die = DIE(); if (die) die->BuildAddressRangeTable(dwarf2Data, this, debug_aranges); @@ -393,7 +422,7 @@ DWARFCompileUnit::BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data, for (uint32_t idx=0; idx<num_ranges; ++idx) { const LineTable::FileAddressRanges::Entry &range = file_ranges.GetEntryRef(idx); - debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), range.GetRangeEnd()); + debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), range.GetRangeEnd()); printf ("0x%8.8x: [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", GetOffset(), range.GetRangeBase(), range.GetRangeEnd()); } } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index 35597f389423..ed1894b8a9f6 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -54,8 +54,7 @@ public: dw_addr_t GetBaseAddress() const { return m_base_addr; } void ClearDIEs(bool keep_compile_unit_die); void BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data, - DWARFDebugAranges* debug_aranges, - bool clear_dies_if_already_not_parsed); + DWARFDebugAranges* debug_aranges); void SetBaseAddress(dw_addr_t base_addr) diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp index d083f8a615c4..b0b71368b800 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp @@ -188,38 +188,74 @@ DWARFDebugArangeSet::Extract(const DWARFDataExtractor &data, lldb::offset_t *off m_header.cu_offset = data.GetDWARFOffset(offset_ptr); m_header.addr_size = data.GetU8(offset_ptr); m_header.seg_size = data.GetU8(offset_ptr); - - - // The first tuple following the header in each set begins at an offset - // that is a multiple of the size of a single tuple (that is, twice the - // size of an address). The header is padded, if necessary, to the - // appropriate boundary. - const uint32_t header_size = *offset_ptr - m_offset; - const uint32_t tuple_size = m_header.addr_size << 1; - uint32_t first_tuple_offset = 0; - while (first_tuple_offset < header_size) - first_tuple_offset += tuple_size; - - *offset_ptr = m_offset + first_tuple_offset; - - Descriptor arangeDescriptor; - - assert(sizeof(arangeDescriptor.address) == sizeof(arangeDescriptor.length)); - assert(sizeof(arangeDescriptor.address) >= m_header.addr_size); - - while (data.ValidOffset(*offset_ptr)) + + // Try to avoid reading invalid arange sets by making sure: + // 1 - the version looks good + // 2 - the address byte size looks plausible + // 3 - the length seems to make sense + // size looks plausible + if ((m_header.version >= 2 && m_header.version <= 5) && + (m_header.addr_size == 4 || m_header.addr_size == 8) && + (m_header.length > 0)) { - arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size); - arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size); - - // Each set of tuples is terminated by a 0 for the address and 0 - // for the length. - if (arangeDescriptor.address || arangeDescriptor.length) - m_arange_descriptors.push_back(arangeDescriptor); + if (data.ValidOffset(m_offset + sizeof(m_header.length) + m_header.length - 1)) + { + // The first tuple following the header in each set begins at an offset + // that is a multiple of the size of a single tuple (that is, twice the + // size of an address). The header is padded, if necessary, to the + // appropriate boundary. + const uint32_t header_size = *offset_ptr - m_offset; + const uint32_t tuple_size = m_header.addr_size << 1; + uint32_t first_tuple_offset = 0; + while (first_tuple_offset < header_size) + first_tuple_offset += tuple_size; + + *offset_ptr = m_offset + first_tuple_offset; + + Descriptor arangeDescriptor; + + static_assert(sizeof(arangeDescriptor.address) == sizeof(arangeDescriptor.length), + "DWARFDebugArangeSet::Descriptor.address and DWARFDebugArangeSet::Descriptor.length must have same size"); + + while (data.ValidOffset(*offset_ptr)) + { + arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size); + arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size); + + // Each set of tuples is terminated by a 0 for the address and 0 + // for the length. + if (arangeDescriptor.address || arangeDescriptor.length) + m_arange_descriptors.push_back(arangeDescriptor); + else + break; // We are done if we get a zero address and length + } + } +#if defined (LLDB_CONFIGURATION_DEBUG) else - break; // We are done if we get a zero address and length + { + printf ("warning: .debug_arange set length is too large arange data at 0x%8.8x: length=0x%8.8x, version=0x%4.4x, cu_offset=0x%8.8x, addr_size=%u, seg_size=%u\n", + m_offset, + m_header.length, + m_header.version, + m_header.cu_offset, + m_header.addr_size, + m_header.seg_size); + } +#endif } - +#if defined (LLDB_CONFIGURATION_DEBUG) + else + { + printf ("warning: .debug_arange set has bad header at 0x%8.8x: length=0x%8.8x, version=0x%4.4x, cu_offset=0x%8.8x, addr_size=%u, seg_size=%u\n", + m_offset, + m_header.length, + m_header.version, + m_header.cu_offset, + m_header.addr_size, + m_header.seg_size); + } +#endif + return !m_arange_descriptors.empty(); } return false; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp index 4f77bff86bdc..60e5c6ed62fe 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -93,14 +93,13 @@ DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data) DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); if (debug_info) { - const bool clear_dies_if_already_not_parsed = true; uint32_t cu_idx = 0; const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); if (cu) - cu->BuildAddressRangeTable(dwarf2Data, this, clear_dies_if_already_not_parsed); + cu->BuildAddressRangeTable(dwarf2Data, this); } } return !IsEmpty(); @@ -136,7 +135,7 @@ void DWARFDebugAranges::Sort (bool minimize) { Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", - __PRETTY_FUNCTION__, this); + __PRETTY_FUNCTION__, static_cast<void*>(this)); Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); size_t orig_arange_size = 0; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index d4db12c17a40..a8c553e2d2ca 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -79,7 +79,6 @@ DWARFDebugInfo::GetCompileUnitAranges () // Manually build arange data for everything that wasn't in the .debug_aranges table. bool printed = false; const size_t num_compile_units = GetNumCompileUnits(); - const bool clear_dies_if_already_not_parsed = true; for (size_t idx = 0; idx < num_compile_units; ++idx) { DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx); @@ -94,7 +93,7 @@ DWARFDebugInfo::GetCompileUnitAranges () m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str()); printed = true; } - cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get(), clear_dies_if_already_not_parsed); + cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get()); } } @@ -214,13 +213,6 @@ DWARFDebugInfo::ContainsCompileUnit (const DWARFCompileUnit *cu) const return false; } - -static bool CompileUnitOffsetLessThan (const DWARFCompileUnitSP& a, const DWARFCompileUnitSP& b) -{ - return a->GetOffset() < b->GetOffset(); -} - - static int CompareDWARFCompileUnitSPOffset (const void *key, const void *arrmem) { @@ -280,15 +272,6 @@ DWARFDebugInfo::GetCompileUnitContainingDIE(dw_offset_t die_offset) } //---------------------------------------------------------------------- -// Compare function DWARFDebugAranges::Range structures -//---------------------------------------------------------------------- -static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2) -{ - return die1.GetOffset() < die2.GetOffset(); -} - - -//---------------------------------------------------------------------- // GetDIE() // // Get the DIE (Debug Information Entry) with the specified offset. @@ -341,40 +324,6 @@ DWARFDebugInfo::GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUn } //---------------------------------------------------------------------- -// DWARFDebugInfo_ParseCallback -// -// A callback function for the static DWARFDebugInfo::Parse() function -// that gets parses all compile units and DIE's into an internate -// representation for further modification. -//---------------------------------------------------------------------- - -static dw_offset_t -DWARFDebugInfo_ParseCallback -( - SymbolFileDWARF* dwarf2Data, - DWARFCompileUnitSP& cu_sp, - DWARFDebugInfoEntry* die, - const dw_offset_t next_offset, - const uint32_t curr_depth, - void* userData -) -{ - DWARFDebugInfo* debug_info = (DWARFDebugInfo*)userData; - DWARFCompileUnit* cu = cu_sp.get(); - if (die) - { - cu->AddDIE(*die); - } - else if (cu) - { - debug_info->AddCompileUnit(cu_sp); - } - - // Just return the current offset to parse the next CU or DIE entry - return next_offset; -} - -//---------------------------------------------------------------------- // AddCompileUnit //---------------------------------------------------------------------- void @@ -563,7 +512,7 @@ static dw_offset_t DumpCallback // We have already found our DIE and are printing it's children. Obey // our recurse depth and return an invalid offset if we get done - // dumping all the the children + // dumping all of the children if (dumpInfo->recurse_depth == UINT32_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth) die->Dump(dwarf2Data, cu, *s, 0); } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 37741eb1da9c..856a7fa7a2ff 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -1485,6 +1485,40 @@ DWARFDebugInfoEntry::GetAttributeAddressRange hi_pc = fail_value; return false; } + +size_t +DWARFDebugInfoEntry::GetAttributeAddressRanges(SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugRanges::RangeList &ranges, + bool check_hi_lo_pc) const +{ + ranges.Clear(); + + dw_offset_t ranges_offset = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET); + if (ranges_offset != DW_INVALID_OFFSET) + { + dw_offset_t debug_ranges_offset = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET); + if (debug_ranges_offset != DW_INVALID_OFFSET) + { + DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges(); + + debug_ranges->FindRanges(debug_ranges_offset, ranges); + ranges.Slide (cu->GetBaseAddress()); + } + } + else if (check_hi_lo_pc) + { + dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; + dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; + if (GetAttributeAddressRange (dwarf2Data, cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS)) + { + if (lo_pc < hi_pc) + ranges.Append(DWARFDebugRanges::RangeList::Entry(lo_pc, hi_pc - lo_pc)); + } + } + return ranges.GetSize(); +} + //---------------------------------------------------------------------- // GetAttributeValueAsLocation // diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index f74057555286..3949ad339dd8 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -86,7 +86,7 @@ public: dw_form_t form; }; - typedef llvm::SmallVector<Info, 32> collection; + typedef llvm::SmallVector<Info, 8> collection; collection m_infos; }; @@ -209,7 +209,13 @@ public: dw_addr_t& lo_pc, dw_addr_t& hi_pc, uint64_t fail_value) const; - + + size_t GetAttributeAddressRanges ( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugRanges::RangeList &ranges, + bool check_hi_lo_pc) const; + dw_offset_t GetAttributeValueAsLocation( SymbolFileDWARF* dwarf2Data, const DWARFCompileUnit* cu, diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp index 0a2f1f749409..6a2649463b54 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp @@ -256,7 +256,13 @@ DWARFDebugLine::DumpStatementOpcodes(Log *log, const DWARFDataExtractor& debug_l prologue.file_names.push_back(fileEntry); } break; - + + case DW_LNE_set_discriminator: + { + uint64_t discriminator = debug_line_data.GetULEB128(&offset); + log->Printf( "0x%8.8x: DW_LNE_set_discriminator (0x%" PRIx64 ")", op_offset, discriminator); + } + break; default: log->Printf( "0x%8.8x: DW_LNE_??? (%2.2x) - Skipping unknown upcode", op_offset, opcode); // Length doesn't include the zero opcode byte or the length itself, but @@ -412,7 +418,7 @@ 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) + if (prologue->version < 2 || prologue->version > 3) return false; prologue->prologue_length = debug_line_data.GetDWARFOffset(offset_ptr); @@ -480,7 +486,7 @@ 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) + if (version < 2 || version > 3) return false; const dw_offset_t end_prologue_offset = debug_line_data.GetDWARFOffset(&offset) + offset; @@ -666,7 +672,7 @@ DWARFDebugLine::ParseStatementTable // The files are numbered, starting at 1, in the order in which they // appear; the names in the prologue come before names defined by // the DW_LNE_define_file instruction. These numbers are used in the - // the file register of the state machine. + // file register of the state machine. { FileNameEntry fileEntry; fileEntry.name = debug_line_data.GetCStr(offset_ptr); @@ -789,7 +795,7 @@ DWARFDebugLine::ParseStatementTable // as a multiple of LEB128 operands for each opcode. { uint8_t i; - assert (opcode - 1 < prologue->standard_opcode_lengths.size()); + assert (static_cast<size_t>(opcode - 1) < prologue->standard_opcode_lengths.size()); const uint8_t opcode_length = prologue->standard_opcode_lengths[opcode - 1]; for (i=0; i<opcode_length; ++i) debug_line_data.Skip_LEB128(offset_ptr); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp index 06ac825e0d4d..488e9820b6fa 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp @@ -66,11 +66,12 @@ DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data) { Timer scoped_timer (__PRETTY_FUNCTION__, "DWARFDebugPubnames::GeneratePubnames (data = %p)", - dwarf2Data); + static_cast<void*>(dwarf2Data)); Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES)); if (log) - log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", dwarf2Data); + log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", + static_cast<void*>(dwarf2Data)); m_sets.clear(); DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp index daa3b0aa6666..0953554ffd7d 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -143,7 +143,7 @@ DWARFDebugRanges::Dump(Stream &s, const DWARFDataExtractor& debug_ranges_data, l { dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); - // Extend 4 byte addresses that consits of 32 bits of 1's to be 64 bits + // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits // of ones if (begin == 0xFFFFFFFFull && addr_size == 4) begin = LLDB_INVALID_ADDRESS; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp index abf69190c93c..5512072529fc 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp @@ -78,7 +78,7 @@ DWARFDeclContext::operator==(const DWARFDeclContext& rhs) const collection::const_iterator rhs_begin = rhs.m_entries.begin(); // The two entry arrays have the same size - // First compare the tags before we do expensize name compares + // First compare the tags before we do expensive name compares for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos) { if (pos->tag != rhs_pos->tag) diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index abd273770ddc..ab8e68ab5516 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -133,7 +133,7 @@ DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* off case DW_FORM_data8: m_value.value.uval = data.GetU64(offset_ptr); break; case DW_FORM_string: m_value.value.cstr = data.GetCStr(offset_ptr); // Set the string value to also be the data for inlined cstr form values only - // so we can tell the differnence between DW_FORM_string and DW_FORM_strp form + // so we can tell the difference between DW_FORM_string and DW_FORM_strp form // values; m_value.data = (uint8_t*)m_value.value.cstr; break; case DW_FORM_exprloc: diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h index 44a24f2756ad..ab0c37beeac9 100644 --- a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h +++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h @@ -169,7 +169,7 @@ struct DWARFMappedHash { if (return_implementation_only_if_available) { - // We found the one true definiton for this class, so + // We found the one true definition for this class, so // only return that die_offsets.clear(); die_offsets.push_back (die_info_array[i].offset); @@ -388,7 +388,7 @@ struct DWARFMappedHash } size_t - GetMinumumHashDataByteSize () const + GetMinimumHashDataByteSize () const { return min_hash_data_byte_size; } @@ -465,7 +465,7 @@ struct DWARFMappedHash break; default: - // We can always skip atomes we don't know about + // We can always skip atoms we don't know about break; } } @@ -651,11 +651,11 @@ struct DWARFMappedHash } const uint32_t count = m_data.GetU32 (hash_data_offset_ptr); - const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize(); + const size_t min_total_hash_data_size = count * m_header.header_data.GetMinimumHashDataByteSize(); if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size)) { // We have at least one HashData entry, and we have enough - // data to parse at leats "count" HashData enties. + // data to parse at least "count" HashData entries. // First make sure the entire C string matches... const bool match = strcmp (name, strp_cstr) == 0; @@ -678,7 +678,7 @@ struct DWARFMappedHash DIEInfo die_info; if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) { - // Only happend the HashData if the string matched... + // Only happened if the HashData of the string matched... if (match) pair.value.push_back (die_info); } @@ -724,7 +724,7 @@ struct DWARFMappedHash return eResultError; const uint32_t count = m_data.GetU32 (hash_data_offset_ptr); - const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize(); + const size_t min_total_hash_data_size = count * m_header.header_data.GetMinimumHashDataByteSize(); if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size)) { const bool match = regex.Execute(strp_cstr); @@ -747,7 +747,7 @@ struct DWARFMappedHash DIEInfo die_info; if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) { - // Only happend the HashData if the string matched... + // Only happened if the HashData of the string matched... if (match) pair.value.push_back (die_info); } diff --git a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp index c9ffa9ec781f..fbbc03c94625 100644 --- a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp @@ -18,7 +18,7 @@ using namespace lldb; using namespace lldb_private; -// when the one and only logging channel is abled, then this will be non NULL. +// when the one and only logging channel is enabled, then this will be non NULL. static LogChannelDWARF* g_log_channel = NULL; LogChannelDWARF::LogChannelDWARF () : @@ -103,6 +103,7 @@ LogChannelDWARF::Disable (const char **categories, Stream *feedback_strm) else if (::strcasecmp (arg, "lookups") == 0) flag_bits &= ~DWARF_LOG_LOOKUPS; else if (::strcasecmp (arg, "map") == 0) flag_bits &= ~DWARF_LOG_DEBUG_MAP; else if (::strcasecmp (arg, "default") == 0) flag_bits &= ~DWARF_LOG_DEFAULT; + else if (::strcasecmp (arg, "verbose") == 0) flag_bits &= ~DWARF_LOG_VERBOSE; else if (::strncasecmp(arg, "comp", 4) == 0) flag_bits &= ~DWARF_LOG_TYPE_COMPLETION; else { @@ -151,6 +152,7 @@ LogChannelDWARF::Enable else if (::strcasecmp (arg, "lookups") == 0) flag_bits |= DWARF_LOG_LOOKUPS; else if (::strcasecmp (arg, "map") == 0) flag_bits |= DWARF_LOG_DEBUG_MAP; else if (::strcasecmp (arg, "default") == 0) flag_bits |= DWARF_LOG_DEFAULT; + else if (::strcasecmp (arg, "verbose") == 0) flag_bits |= DWARF_LOG_VERBOSE; else if (::strncasecmp(arg, "comp", 4) == 0) flag_bits |= DWARF_LOG_TYPE_COMPLETION; else { diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index c1aecfe8eb62..842260dbc3ba 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -66,6 +66,9 @@ #include <map> +#include <ctype.h> +#include <string.h> + //#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF @@ -110,7 +113,35 @@ DW_ACCESS_to_AccessType (uint32_t dwarf_accessibility) return eAccessNone; } -#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE) +static const char* +removeHostnameFromPathname(const char* path_from_dwarf) +{ + if (!path_from_dwarf || !path_from_dwarf[0]) + { + return path_from_dwarf; + } + + const char *colon_pos = strchr(path_from_dwarf, ':'); + if (!colon_pos) + { + return path_from_dwarf; + } + + // check whether we have a windows path, and so the first character + // is a drive-letter not a hostname. + if ( + colon_pos == path_from_dwarf + 1 && + isalpha(*path_from_dwarf) && + strlen(path_from_dwarf) > 2 && + '\\' == path_from_dwarf[2]) + { + return path_from_dwarf; + } + + return colon_pos + 1; +} + +#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) class DIEStack { @@ -525,7 +556,7 @@ SymbolFileDWARF::GetClangASTContext () if (!m_is_external_ast_source) { m_is_external_ast_source = true; - llvm::OwningPtr<clang::ExternalASTSource> ast_source_ap ( + llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source_ap ( new ClangExternalASTSourceCallbacks (SymbolFileDWARF::CompleteTagDecl, SymbolFileDWARF::CompleteObjCInterfaceDecl, SymbolFileDWARF::FindExternalVisibleDeclsByName, @@ -829,7 +860,8 @@ SymbolFileDWARF::DebugInfo() { if (m_info.get() == NULL) { - Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this); + Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", + __PRETTY_FUNCTION__, static_cast<void*>(this)); if (get_debug_info_data().GetByteSize() > 0) { m_info.reset(new DWARFDebugInfo()); @@ -879,7 +911,8 @@ SymbolFileDWARF::DebugRanges() { if (m_ranges.get() == NULL) { - Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this); + Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", + __PRETTY_FUNCTION__, static_cast<void*>(this)); if (get_debug_ranges_data().GetByteSize() > 0) { m_ranges.reset(new DWARFDebugRanges()); @@ -943,7 +976,11 @@ SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx) } else { + // DWARF2/3 suggests the form hostname:pathname for compilation directory. + // Remove the host part if present. + cu_comp_dir = removeHostnameFromPathname(cu_comp_dir); std::string fullpath(cu_comp_dir); + if (*fullpath.rbegin() != '/') fullpath += '/'; fullpath += cu_die_name; @@ -1170,6 +1207,11 @@ SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpec if (cu_die) { const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, NULL); + + // DWARF2/3 suggests the form hostname:pathname for compilation directory. + // Remove the host part if present. + cu_comp_dir = removeHostnameFromPathname(cu_comp_dir); + dw_offset_t stmt_list = cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_stmt_list, DW_INVALID_OFFSET); // All file indexes in DWARF are one based and a file of index zero is @@ -1983,7 +2025,7 @@ SymbolFileDWARF::ParseChildMembers const uint64_t word_width = 32; // Objective-C has invalid DW_AT_bit_offset values in older versions - // of clang, so we have to be careful and only insert unnammed bitfields + // of clang, so we have to be careful and only insert unnamed bitfields // if we have a new enough clang. bool detect_unnamed_bitfields = true; @@ -2380,7 +2422,6 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) // The type will get resolved when all of the calls to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition // are done. m_forward_decl_clang_type_to_die.erase (clang_type_no_qualifiers.GetOpaqueQualType()); - // Disable external storage for this type so we don't get anymore // clang::ExternalASTSource queries for this type. @@ -2395,14 +2436,11 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION)); if (log) - { GetObjectFile()->GetModule()->LogMessageVerboseBacktrace (log, "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type->GetName().AsCString()); - - } assert (clang_type); DWARFDebugInfoEntry::Attributes attributes; @@ -2413,11 +2451,10 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) case DW_TAG_class_type: { LayoutInfo layout_info; - + { if (die->HasChildren()) { - LanguageType class_language = eLanguageTypeUnknown; if (clang_type.IsObjCObjectOrInterfaceType()) { @@ -2426,7 +2463,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) // the class is created. clang_type.StartTagDeclarationDefinition (); } - + int tag_decl_kind = -1; AccessType default_accessibility = eAccessNone; if (tag == DW_TAG_structure_type) @@ -2444,14 +2481,14 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) tag_decl_kind = clang::TTK_Class; default_accessibility = eAccessPrivate; } - + SymbolContext sc(GetCompUnitForDWARFCompUnit(dwarf_cu)); std::vector<clang::CXXBaseSpecifier *> base_classes; std::vector<int> member_accessibilities; bool is_a_class = false; // Parse members and base classes first DWARFDIECollection member_function_dies; - + DelayedPropertyList delayed_properties; ParseChildMembers (sc, dwarf_cu, @@ -2465,7 +2502,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) default_accessibility, is_a_class, layout_info); - + // Now parse any methods if there were any... size_t num_functions = member_function_dies.Size(); if (num_functions > 0) @@ -2475,13 +2512,12 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) ResolveType(dwarf_cu, member_function_dies.GetDIEPtrAtIndex(i)); } } - + if (class_language == eLanguageTypeObjC) { ConstString class_name (clang_type.GetTypeName()); if (class_name) { - DIEArray method_die_offsets; if (m_using_apple_tables) { @@ -2492,21 +2528,21 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) { if (!m_indexed) Index (); - + m_objc_class_selectors_index.Find (class_name, method_die_offsets); } - + if (!method_die_offsets.empty()) { DWARFDebugInfo* debug_info = DebugInfo(); - + DWARFCompileUnit* method_cu = NULL; const size_t num_matches = method_die_offsets.size(); for (size_t i=0; i<num_matches; ++i) { const dw_offset_t die_offset = method_die_offsets[i]; DWARFDebugInfoEntry *method_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &method_cu); - + if (method_die) ResolveType (method_cu, method_die); else @@ -2519,14 +2555,14 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) } } } - + for (DelayedPropertyList::iterator pi = delayed_properties.begin(), pe = delayed_properties.end(); pi != pe; ++pi) pi->Finalize(); } } - + // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we // need to tell the clang type it is actually a class. if (class_language != eLanguageTypeObjC) @@ -2534,7 +2570,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) if (is_a_class && tag_decl_kind != clang::TTK_Class) clang_type.SetTagTypeKind (clang::TTK_Class); } - + // Since DW_TAG_structure_type gets used for both classes // and structures, we may need to set any DW_TAG_member // fields to have a "private" access if none was specified. @@ -2553,7 +2589,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) &member_accessibilities.front(), member_accessibilities.size()); } - + if (!base_classes.empty()) { // Make sure all base classes refer to complete types and not @@ -2580,7 +2616,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) // is complete. If we don't do this, clang will crash when we // call setBases() inside of "clang_type.SetBaseClassesForClassType()" // below. Since we provide layout assistance, all ivars in this - // class and other classe will be fine, this is the best we can do + // class and other classes will be fine, this is the best we can do // short of crashing. base_class_type.StartTagDeclarationDefinition (); base_class_type.CompleteTagDeclarationDefinition (); @@ -2589,7 +2625,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) } clang_type.SetBaseClassesForClassType (&base_classes.front(), base_classes.size()); - + // Clang will copy each CXXBaseSpecifier in "base_classes" // so we have to free them all. ClangASTType::DeleteBaseClassSpecifiers (&base_classes.front(), @@ -2597,10 +2633,10 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) } } } - + clang_type.BuildIndirectFields (); clang_type.CompleteTagDeclarationDefinition (); - + if (!layout_info.field_offsets.empty() || !layout_info.base_offsets.empty() || !layout_info.vbase_offsets.empty() ) @@ -2609,7 +2645,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) layout_info.bit_size = type->GetByteSize() * 8; if (layout_info.bit_size == 0) layout_info.bit_size = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_byte_size, 0) * 8; - + clang::CXXRecordDecl *record_decl = clang_type.GetAsCXXRecordDecl(); if (record_decl) { @@ -2617,14 +2653,14 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) { GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) caching layout info for record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u], base_offsets[%u], vbase_offsets[%u])", - clang_type.GetOpaqueQualType(), - record_decl, + static_cast<void*>(clang_type.GetOpaqueQualType()), + static_cast<void*>(record_decl), layout_info.bit_size, layout_info.alignment, - (uint32_t)layout_info.field_offsets.size(), - (uint32_t)layout_info.base_offsets.size(), - (uint32_t)layout_info.vbase_offsets.size()); - + static_cast<uint32_t>(layout_info.field_offsets.size()), + static_cast<uint32_t>(layout_info.base_offsets.size()), + static_cast<uint32_t>(layout_info.vbase_offsets.size())); + uint32_t idx; { llvm::DenseMap <const clang::FieldDecl *, uint64_t>::const_iterator pos, end = layout_info.field_offsets.end(); @@ -2632,13 +2668,13 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) { GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) field[%u] = { bit_offset=%u, name='%s' }", - clang_type.GetOpaqueQualType(), + static_cast<void*>(clang_type.GetOpaqueQualType()), idx, - (uint32_t)pos->second, + static_cast<uint32_t>(pos->second), pos->first->getNameAsString().c_str()); } } - + { llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator base_pos, base_end = layout_info.base_offsets.end(); for (idx = 0, base_pos = layout_info.base_offsets.begin(); base_pos != base_end; ++base_pos, ++idx) @@ -2657,9 +2693,9 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) { GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) vbase[%u] = { byte_offset=%u, name='%s' }", - clang_type.GetOpaqueQualType(), + static_cast<void*>(clang_type.GetOpaqueQualType()), idx, - (uint32_t)vbase_pos->second.getQuantity(), + static_cast<uint32_t>(vbase_pos->second.getQuantity()), vbase_pos->first->getNameAsString().c_str()); } } @@ -2755,9 +2791,8 @@ SymbolFileDWARF::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_ { Timer scoped_timer(__PRETTY_FUNCTION__, "SymbolFileDWARF::ResolveSymbolContext (so_addr = { section = %p, offset = 0x%" PRIx64 " }, resolve_scope = 0x%8.8x)", - so_addr.GetSection().get(), - so_addr.GetOffset(), - resolve_scope); + static_cast<void*>(so_addr.GetSection().get()), + so_addr.GetOffset(), resolve_scope); uint32_t resolved = 0; if (resolve_scope & ( eSymbolContextCompUnit | eSymbolContextFunction | @@ -3086,7 +3121,7 @@ SymbolFileDWARF::DIEIsInNamespace (const ClangNamespaceDecl *namespace_decl, DWARFCompileUnit* cu, const DWARFDebugInfoEntry* die) { - // No namespace specified, so the answesr i + // No namespace specified, so the answer is if (namespace_decl == NULL) return true; @@ -3116,7 +3151,7 @@ SymbolFileDWARF::DIEIsInNamespace (const ClangNamespaceDecl *namespace_decl, { // We have a namespace_decl that was not NULL but it contained // a NULL "clang::NamespaceDecl", so this means the global namespace - // So as long the the contained decl context DIE isn't a namespace + // So as long the contained decl context DIE isn't a namespace // we should be ok. if (decl_ctx_die->Tag() != DW_TAG_namespace) return true; @@ -3134,18 +3169,15 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); if (log) - { GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables)", name.GetCString(), - namespace_decl, - append, - max_matches); - } - + static_cast<const void*>(namespace_decl), + append, max_matches); + if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl)) return 0; - + DWARFDebugInfo* info = DebugInfo(); if (info == NULL) return 0; @@ -3159,7 +3191,7 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat const uint32_t original_size = variables.GetSize(); DIEArray die_offsets; - + if (m_using_apple_tables) { if (m_apple_names_ap.get()) @@ -3167,10 +3199,10 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat const char *name_cstr = name.GetCString(); const char *base_name_start; const char *base_name_end = NULL; - + if (!CPPLanguageRuntime::StripNamespacesFromVariableName(name_cstr, base_name_start, base_name_end)) base_name_start = name_cstr; - + m_apple_names_ap->FindByName (base_name_start, die_offsets); } } @@ -3182,14 +3214,14 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat m_global_index.Find (name, die_offsets); } - + const size_t num_die_matches = die_offsets.size(); if (num_die_matches) { SymbolContext sc; sc.module_sp = m_obj_file->GetModule(); assert (sc.module_sp); - + DWARFDebugInfo* debug_info = DebugInfo(); DWARFCompileUnit* dwarf_cu = NULL; const DWARFDebugInfoEntry* die = NULL; @@ -3209,11 +3241,11 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat case DW_TAG_try_block: case DW_TAG_catch_block: break; - + case DW_TAG_variable: { sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX); - + if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) continue; @@ -3242,10 +3274,9 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_privat { GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables) => %u", - name.GetCString(), - namespace_decl, - append, - max_matches, + name.GetCString(), + static_cast<const void*>(namespace_decl), + append, max_matches, num_matches); } return num_matches; @@ -3255,13 +3286,12 @@ uint32_t SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables) { Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); - + if (log) { GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", append=%u, max_matches=%u, variables)", - regex.GetText(), - append, + regex.GetText(), append, max_matches); } @@ -3959,38 +3989,32 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc, return 0; Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); - + if (log) { if (namespace_decl) - { GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list)", name.GetCString(), - namespace_decl->GetNamespaceDecl(), + static_cast<void*>(namespace_decl->GetNamespaceDecl()), namespace_decl->GetQualifiedName().c_str(), - append, - max_matches); - } + append, max_matches); else - { GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list)", - name.GetCString(), - append, + name.GetCString(), append, max_matches); - } } // If we aren't appending the results to this list, then clear the list if (!append) types.Clear(); - + if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl)) return 0; DIEArray die_offsets; - + if (m_using_apple_tables) { if (m_apple_types_ap.get()) @@ -4003,10 +4027,10 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc, { if (!m_indexed) Index (); - + m_type_index.Find (name, die_offsets); } - + const size_t num_die_matches = die_offsets.size(); if (num_die_matches) @@ -4024,7 +4048,7 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc, { if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) continue; - + Type *matching_type = ResolveType (dwarf_cu, die); if (matching_type) { @@ -4052,10 +4076,9 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc, GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list) => %u", name.GetCString(), - namespace_decl->GetNamespaceDecl(), + static_cast<void*>(namespace_decl->GetNamespaceDecl()), namespace_decl->GetQualifiedName().c_str(), - append, - max_matches, + append, max_matches, num_matches); } else @@ -4063,8 +4086,7 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc, GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list) => %u", name.GetCString(), - append, - max_matches, + append, max_matches, num_matches); } } @@ -4156,7 +4178,7 @@ SymbolFileDWARF::FindNamespace (const SymbolContext& sc, GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::FindNamespace (sc, name=\"%s\") => clang::NamespaceDecl(%p) \"%s\"", name.GetCString(), - namespace_decl.GetNamespaceDecl(), + static_cast<const void*>(namespace_decl.GetNamespaceDecl()), namespace_decl.GetQualifiedName().c_str()); } @@ -4203,8 +4225,8 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc, TypeList* type_list, std::vector<ClangASTType>& function_param_types, std::vector<clang::ParmVarDecl*>& function_param_decls, - unsigned &type_quals, - ClangASTContext::TemplateParameterInfos &template_param_infos) + unsigned &type_quals) // , + // ClangASTContext::TemplateParameterInfos &template_param_infos)) { if (parent_die == NULL) return 0; @@ -4357,7 +4379,11 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc, case DW_TAG_template_type_parameter: case DW_TAG_template_value_parameter: - ParseTemplateDIE (dwarf_cu, die,template_param_infos); + // The one caller of this was never using the template_param_infos, + // and the local variable was taking up a large amount of stack space + // in SymbolFileDWARF::ParseType() so this was removed. If we ever need + // the template params back, we can add them back. + // ParseTemplateDIE (dwarf_cu, die, template_param_infos); break; default: @@ -4618,20 +4644,20 @@ SymbolFileDWARF::ResolveNamespaceDIE (DWARFCompileUnit *dwarf_cu, const DWARFDeb { GetObjectFile()->GetModule()->LogMessage (log, "ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace with DW_AT_name(\"%s\") => clang::NamespaceDecl *%p (original = %p)", - GetClangASTContext().getASTContext(), + static_cast<void*>(GetClangASTContext().getASTContext()), MakeUserID(die->GetOffset()), namespace_name, - namespace_decl, - namespace_decl->getOriginalNamespace()); + static_cast<void*>(namespace_decl), + static_cast<void*>(namespace_decl->getOriginalNamespace())); } else { GetObjectFile()->GetModule()->LogMessage (log, "ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace (anonymous) => clang::NamespaceDecl *%p (original = %p)", - GetClangASTContext().getASTContext(), + static_cast<void*>(GetClangASTContext().getASTContext()), MakeUserID(die->GetOffset()), - namespace_decl, - namespace_decl->getOriginalNamespace()); + static_cast<void*>(namespace_decl), + static_cast<void*>(namespace_decl->getOriginalNamespace())); } } @@ -4982,7 +5008,7 @@ SymbolFileDWARF::DIEDeclContextsMatch (DWARFCompileUnit* cu1, const DWARFDebugIn if (count1 != count2) return false; - // Make sure the DW_TAG values match all the way back up the the + // Make sure the DW_TAG values match all the way back up the // compile unit. If they don't, then we are done. const DWARFDebugInfoEntry *decl_ctx_die1; const DWARFDebugInfoEntry *decl_ctx_die2; @@ -5084,7 +5110,7 @@ SymbolFileDWARF::FindDefinitionTypeForDIE (DWARFCompileUnit* cu, GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTagAndQualifiedNameHash()"); m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash (type_name.GetCString(), die->Tag(), qualified_name_hash, die_offsets); } - else if (has_tag > 1) + else if (has_tag) { if (log) GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTag()"); @@ -5388,7 +5414,7 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, const DWARFDebugInfoEntry *src_class_die, DWARFCompileUnit* dst_cu, const DWARFDebugInfoEntry *dst_class_die, - llvm::SmallVectorImpl <const DWARFDebugInfoEntry *> &failures) + DWARFDIECollection &failures) { if (!class_type || !src_cu || !src_class_die || !dst_cu || !dst_class_die) return false; @@ -5456,7 +5482,7 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, // Is everything kosher so we can go through the members at top speed? bool fast_path = true; - + if (src_size != dst_size) { if (src_size != 0 && dst_size != 0) @@ -5468,12 +5494,12 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, src_size, dst_size); } - + fast_path = false; } uint32_t idx; - + if (fast_path) { for (idx = 0; idx < src_size; ++idx) @@ -5493,10 +5519,10 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, DW_TAG_value_to_name(src_die->Tag())); fast_path = false; } - + const char *src_name = src_die->GetMangledName (src_symfile, src_cu); const char *dst_name = dst_die->GetMangledName (this, dst_cu); - + // Make sure the names match if (src_name == dst_name || (strcmp (src_name, dst_name) == 0)) continue; @@ -5509,7 +5535,7 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, src_name, dst_die->GetOffset(), dst_name); - + fast_path = false; } } @@ -5523,25 +5549,31 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, { src_die = src_name_to_die.GetValueAtIndexUnchecked (idx); dst_die = dst_name_to_die.GetValueAtIndexUnchecked (idx); - + clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die]; if (src_decl_ctx) { if (log) - log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset()); + log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", + static_cast<void*>(src_decl_ctx), + src_die->GetOffset(), dst_die->GetOffset()); LinkDeclContextToDIE (src_decl_ctx, dst_die); } else { if (log) - log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); + log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", + src_die->GetOffset(), dst_die->GetOffset()); } - + Type *src_child_type = m_die_to_type[src_die]; if (src_child_type) { if (log) - log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset()); + log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", + static_cast<void*>(src_child_type), + src_child_type->GetID(), + src_die->GetOffset(), dst_die->GetOffset()); m_die_to_type[dst_die] = src_child_type; } else @@ -5556,24 +5588,27 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, // We must do this slowly. For each member of the destination, look // up a member in the source with the same name, check its tag, and // unique them if everything matches up. Report failures. - + if (!src_name_to_die.IsEmpty() && !dst_name_to_die.IsEmpty()) { src_name_to_die.Sort(); - + for (idx = 0; idx < dst_size; ++idx) { const char *dst_name = dst_name_to_die.GetCStringAtIndex(idx); dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx); src_die = src_name_to_die.Find(dst_name, NULL); - + if (src_die && (src_die->Tag() == dst_die->Tag())) { clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die]; if (src_decl_ctx) { if (log) - log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset()); + log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", + static_cast<void*>(src_decl_ctx), + src_die->GetOffset(), + dst_die->GetOffset()); LinkDeclContextToDIE (src_decl_ctx, dst_die); } else @@ -5581,12 +5616,16 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, if (log) log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); } - + Type *src_child_type = m_die_to_type[src_die]; if (src_child_type) { if (log) - log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset()); + log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", + static_cast<void*>(src_child_type), + src_child_type->GetID(), + src_die->GetOffset(), + dst_die->GetOffset()); m_die_to_type[dst_die] = src_child_type; } else @@ -5600,7 +5639,7 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, if (log) log->Printf ("warning: couldn't find a match for 0x%8.8x", dst_die->GetOffset()); - failures.push_back(dst_die); + failures.Append(dst_die); } } } @@ -5614,13 +5653,13 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, if (src_size_artificial && dst_size_artificial) { dst_name_to_die_artificial.Sort(); - + for (idx = 0; idx < src_size_artificial; ++idx) { const char *src_name_artificial = src_name_to_die_artificial.GetCStringAtIndex(idx); src_die = src_name_to_die_artificial.GetValueAtIndexUnchecked (idx); dst_die = dst_name_to_die_artificial.Find(src_name_artificial, NULL); - + if (dst_die) { // Both classes have the artificial types, link them @@ -5628,7 +5667,9 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, if (src_decl_ctx) { if (log) - log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset()); + log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", + static_cast<void*>(src_decl_ctx), + src_die->GetOffset(), dst_die->GetOffset()); LinkDeclContextToDIE (src_decl_ctx, dst_die); } else @@ -5636,12 +5677,15 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, if (log) log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); } - + Type *src_child_type = m_die_to_type[src_die]; if (src_child_type) { if (log) - log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset()); + log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", + static_cast<void*>(src_child_type), + src_child_type->GetID(), + src_die->GetOffset(), dst_die->GetOffset()); m_die_to_type[dst_die] = src_child_type; } else @@ -5662,11 +5706,11 @@ SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, if (log) log->Printf ("warning: need to create artificial method for 0x%8.8x for method '%s'", dst_die->GetOffset(), dst_name_artificial); - failures.push_back(dst_die); + failures.Append(dst_die); } } - return (failures.size() != 0); + return (failures.Size() != 0); } TypeSP @@ -5677,7 +5721,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, if (type_is_new_ptr) *type_is_new_ptr = false; -#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE) +#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) static DIEStack g_die_stack; DIEStack::ScopedPopper scoped_die_logger(g_die_stack); #endif @@ -5690,15 +5734,15 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, { const DWARFDebugInfoEntry *context_die; clang::DeclContext *context = GetClangDeclContextContainingDIE (dwarf_cu, die, &context_die); - + GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x, decl_ctx = %p (die 0x%8.8x)) %s name = '%s')", - die->GetOffset(), - context, - context_die->GetOffset(), - DW_TAG_value_to_name(die->Tag()), - die->GetName(this, dwarf_cu)); - -#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE) + die->GetOffset(), + static_cast<void*>(context), + context_die->GetOffset(), + DW_TAG_value_to_name(die->Tag()), + die->GetName(this, dwarf_cu)); + +#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) scoped_die_logger.Push (dwarf_cu, die); g_die_stack.LogDIEs(log, this); #endif @@ -5712,7 +5756,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, // GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDwarf::%s %s", __FUNCTION__, s.GetData()); // // } - + Type *type_ptr = m_die_to_type.lookup (die); TypeList* type_list = GetTypeList(); if (type_ptr == NULL) @@ -5733,7 +5777,8 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; ClangASTType clang_type; - + DWARFFormValue form_value; + dw_attr_t attr; switch (tag) @@ -5761,7 +5806,6 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, for (i=0; i<num_attributes; ++i) { attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; if (attributes.ExtractFormValueAtIndex(this, i, form_value)) { switch (attr) @@ -5770,7 +5814,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, 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: - + type_name_cstr = form_value.AsCString(&get_debug_str_data()); // Work around a bug in llvm-gcc where they give a name to a reference type which doesn't // include the "&"... @@ -5829,7 +5873,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || encoding_data_type == Type::eEncodingIsTypedefUID) && sc.comp_unit != NULL) { bool translation_unit_is_objc = (sc.comp_unit->GetLanguage() == eLanguageTypeObjC || sc.comp_unit->GetLanguage() == eLanguageTypeObjC_plus_plus); - + if (translation_unit_is_objc) { if (type_name_cstr != NULL) @@ -5837,7 +5881,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, static ConstString g_objc_type_name_id("id"); static ConstString g_objc_type_name_Class("Class"); static ConstString g_objc_type_name_selector("SEL"); - + if (type_name_const_str == g_objc_type_name_id) { if (log) @@ -5879,11 +5923,11 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, else if (encoding_data_type == Type::eEncodingIsPointerUID && encoding_uid != LLDB_INVALID_UID) { // Clang sometimes erroneously emits id as objc_object*. In that case we fix up the type to "id". - + DWARFDebugInfoEntry* encoding_die = dwarf_cu->GetDIEPtr(encoding_uid); - + if (encoding_die && encoding_die->Tag() == DW_TAG_structure_type) - { + { if (const char *struct_name = encoding_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_name, NULL)) { if (!strcmp(struct_name, "objc_object")) @@ -5903,7 +5947,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, } } } - + type_sp.reset( new Type (MakeUserID(die->GetOffset()), this, type_name_const_str, @@ -5914,7 +5958,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, &decl, clang_type, resolve_state)); - + m_die_to_type[die] = type_sp.get(); // Type* encoding_type = GetUniquedTypeForDIEOffset(encoding_uid, type_sp, NULL, 0, 0, false); @@ -5946,7 +5990,6 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, for (i=0; i<num_attributes; ++i) { attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; if (attributes.ExtractFormValueAtIndex(this, i, form_value)) { switch (attr) @@ -5996,7 +6039,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, case DW_AT_APPLE_objc_complete_type: is_complete_objc_class = form_value.Signed(); break; - + case DW_AT_allocated: case DW_AT_associated: case DW_AT_data_location: @@ -6010,8 +6053,11 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, } } } - - UniqueDWARFASTType unique_ast_entry; + + // UniqueDWARFASTType is large, so don't create a local variables on the + // stack, put it on the heap. This function is often called recursively + // and clang isn't good and sharing the stack space for variables in different blocks. + std::unique_ptr<UniqueDWARFASTType> unique_ast_entry_ap(new UniqueDWARFASTType()); // Only try and unique the type if it has a name. if (type_name_const_str && @@ -6021,21 +6067,21 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, die, decl, byte_size_valid ? byte_size : -1, - unique_ast_entry)) + *unique_ast_entry_ap)) { // We have already parsed this type or from another // compile unit. GCC loves to use the "one definition // rule" which can result in multiple definitions // of the same class over and over in each compile // unit. - type_sp = unique_ast_entry.m_type_sp; + type_sp = unique_ast_entry_ap->m_type_sp; if (type_sp) { m_die_to_type[die] = type_sp.get(); return type_sp; } } - + DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr); int tag_decl_kind = -1; @@ -6055,7 +6101,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, tag_decl_kind = clang::TTK_Class; default_accessibility = eAccessPrivate; } - + if (byte_size_valid && byte_size == 0 && type_name_cstr && die->HasChildren() == false && sc.comp_unit->GetLanguage() == eLanguageTypeObjC) @@ -6093,20 +6139,20 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, // else... type_sp = m_debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE (die, type_name_const_str, true); } - + if (type_sp) { if (log) { GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is an incomplete objc type, complete type is 0x%8.8" PRIx64, - this, + static_cast<void*>(this), die->GetOffset(), DW_TAG_value_to_name(tag), type_name_cstr, type_sp->GetID()); } - + // We found a real definition for this type elsewhere // so lets use it and cache the fact that we found // a complete type for this die @@ -6115,7 +6161,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, } } } - + if (is_forward_declaration) { @@ -6128,12 +6174,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, { GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, trying to find complete type", - this, + static_cast<void*>(this), die->GetOffset(), DW_TAG_value_to_name(tag), type_name_cstr); } - + DWARFDeclContext die_decl_ctx; die->GetDWARFDeclContext(this, dwarf_cu, die_decl_ctx); @@ -6154,7 +6200,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, { GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, complete type is 0x%8.8" PRIx64, - this, + static_cast<void*>(this), die->GetOffset(), DW_TAG_value_to_name(tag), type_name_cstr, @@ -6174,12 +6220,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, if (!clang_type) { const DWARFDebugInfoEntry *decl_ctx_die; - + clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die); if (accessibility == eAccessNone && decl_ctx) { // Check the decl context that contains this class/struct/union. - // If it is a class we must give it an accessability. + // If it is a class we must give it an accessibility. const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind(); if (DeclKindIsCXXClass (containing_decl_kind)) accessibility = default_accessibility; @@ -6199,14 +6245,14 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, type_name_cstr, tag_decl_kind, template_param_infos); - + clang::ClassTemplateSpecializationDecl *class_specialization_decl = ast.CreateClassTemplateSpecializationDecl (decl_ctx, class_template_decl, tag_decl_kind, template_param_infos); clang_type = ast.CreateClassTemplateSpecializationType (class_specialization_decl); clang_type_was_created = true; - + GetClangASTContext().SetMetadata (class_template_decl, metadata); GetClangASTContext().SetMetadata (class_specialization_decl, metadata); } @@ -6238,22 +6284,22 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, &decl, clang_type, Type::eResolveStateForward)); - + type_sp->SetIsCompleteObjCClass(is_complete_objc_class); // Add our type to the unique type map so we don't // end up creating many copies of the same type over // and over in the ASTContext for our module - unique_ast_entry.m_type_sp = type_sp; - unique_ast_entry.m_symfile = this; - unique_ast_entry.m_cu = dwarf_cu; - unique_ast_entry.m_die = die; - unique_ast_entry.m_declaration = decl; - unique_ast_entry.m_byte_size = byte_size; + unique_ast_entry_ap->m_type_sp = type_sp; + unique_ast_entry_ap->m_symfile = this; + unique_ast_entry_ap->m_cu = dwarf_cu; + unique_ast_entry_ap->m_die = die; + unique_ast_entry_ap->m_declaration = decl; + unique_ast_entry_ap->m_byte_size = byte_size; GetUniqueDWARFASTTypeMap().Insert (type_name_const_str, - unique_ast_entry); - + *unique_ast_entry_ap); + if (is_forward_declaration && die->HasChildren()) { // Check to see if the DIE actually has a definition, some version of GCC will @@ -6294,32 +6340,25 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, // No children for this struct/union/class, lets finish it clang_type.StartTagDeclarationDefinition (); clang_type.CompleteTagDeclarationDefinition (); - + if (tag == DW_TAG_structure_type) // this only applies in C { clang::RecordDecl *record_decl = clang_type.GetAsRecordDecl(); - + if (record_decl) - { - LayoutInfo layout_info; - - layout_info.alignment = 0; - layout_info.bit_size = 0; - - m_record_decl_to_layout_map.insert(std::make_pair(record_decl, layout_info)); - } + m_record_decl_to_layout_map.insert(std::make_pair(record_decl, LayoutInfo())); } } else if (clang_type_was_created) { // Start the definition if the class is not objective C since // the underlying decls respond to isCompleteDefinition(). Objective - // C decls dont' respond to isCompleteDefinition() so we can't - // start the declaration definition right away. For C++ classs/union/structs + // C decls don't respond to isCompleteDefinition() so we can't + // start the declaration definition right away. For C++ class/union/structs // we want to start the definition in case the class is needed as the // declaration context for a contained class or type without the need // to complete that type.. - + if (class_language != eLanguageTypeObjC && class_language != eLanguageTypeObjC_plus_plus) clang_type.StartTagDeclarationDefinition (); @@ -6334,7 +6373,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, clang_type.SetHasExternalStorage (true); } } - + } break; @@ -6353,7 +6392,6 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, for (i=0; i<num_attributes; ++i) { attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; if (attributes.ExtractFormValueAtIndex(this, i, form_value)) { switch (attr) @@ -6397,12 +6435,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, if (enumerator_type) enumerator_clang_type = enumerator_type->GetClangFullType(); } - + if (!enumerator_clang_type) enumerator_clang_type = ast.GetBuiltinTypeForDWARFEncodingAndBitSize (NULL, DW_ATE_signed, byte_size * 8); - + clang_type = ast.CreateEnumerationType (type_name_cstr, GetClangDeclContextContainingDIE (dwarf_cu, die, NULL), decl, @@ -6414,7 +6452,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, } LinkDeclContextToDIE(clang_type.GetDeclContextForType(), die); - + type_sp.reset( new Type (MakeUserID(die->GetOffset()), this, type_name_const_str, @@ -6469,7 +6507,6 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, for (i=0; i<num_attributes; ++i) { attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; if (attributes.ExtractFormValueAtIndex(this, i, form_value)) { switch (attr) @@ -6491,7 +6528,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, case DW_AT_virtuality: is_virtual = form_value.Boolean(); break; case DW_AT_explicit: is_explicit = form_value.Boolean(); break; case DW_AT_artificial: is_artificial = form_value.Boolean(); break; - + case DW_AT_external: if (form_value.Unsigned()) @@ -6554,12 +6591,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, object_pointer_name.assign(s.GetData()); } } - + DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr); ClangASTType return_clang_type; Type *func_type = NULL; - + if (type_die_offset != DW_INVALID_OFFSET) func_type = ResolveTypeUID(type_die_offset); @@ -6573,18 +6610,17 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, std::vector<clang::ParmVarDecl*> function_param_decls; // Parse the function children for the parameters - + const DWARFDebugInfoEntry *decl_ctx_die = NULL; clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die); const clang::Decl::Kind containing_decl_kind = containing_decl_ctx->getDeclKind(); const bool is_cxx_method = DeclKindIsCXXClass (containing_decl_kind); // Start off static. This will be set to false in ParseChildParameters(...) - // if we find a "this" paramters as the first parameter + // if we find a "this" parameters as the first parameter if (is_cxx_method) is_static = true; - ClangASTContext::TemplateParameterInfos template_param_infos; - + if (die->HasChildren()) { bool skip_artificial = true; @@ -6598,8 +6634,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, type_list, function_param_types, function_param_decls, - type_quals, - template_param_infos); + type_quals); } // clang_type will get the function prototype clang type after this call @@ -6608,9 +6643,9 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, function_param_types.size(), is_variadic, type_quals); - + bool ignore_containing_context = false; - + if (type_name_cstr) { bool type_handled = false; @@ -6619,12 +6654,10 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, ObjCLanguageRuntime::MethodName objc_method (type_name_cstr, true); if (objc_method.IsValid(true)) { - SymbolContext empty_sc; ClangASTType class_opaque_type; ConstString class_name(objc_method.GetClassName()); if (class_name) { - TypeList types; TypeSP complete_objc_class_type_sp (FindCompleteObjCDefinitionTypeForDIE (NULL, class_name, false)); if (complete_objc_class_type_sp) @@ -6677,7 +6710,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, SymbolFileDWARF *class_symfile = NULL; DWARFCompileUnitSP class_type_cu_sp; const DWARFDebugInfoEntry *class_type_die = NULL; - + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); if (debug_map_symfile) { @@ -6691,8 +6724,8 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, } if (class_type_die) { - llvm::SmallVector<const DWARFDebugInfoEntry *, 0> failures; - + DWARFDIECollection failures; + CopyUniqueClassMethodTypes (class_symfile, class_type, class_type_cu_sp.get(), @@ -6700,12 +6733,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, dwarf_cu, decl_ctx_die, failures); - + // FIXME do something with these failures that's smarter than // just dropping them on the ground. Unfortunately classes don't // like having stuff added to them after their definitions are // complete... - + type_ptr = m_die_to_type[die]; if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { @@ -6714,7 +6747,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, } } } - + if (specification_die_offset != DW_INVALID_OFFSET) { // We have a specification which we are going to base our function @@ -6773,7 +6806,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, // in the DWARF for C++ methods... Default to public for now... if (accessibility == eAccessNone) accessibility = eAccessPublic; - + if (!is_static && !die->HasChildren()) { // We have a C++ member function with no children (this pointer!) @@ -6792,7 +6825,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, m_obj_file->GetFileSpec().GetPath().c_str()); const bool is_attr_used = false; - + cxx_method_decl = class_opaque_type.AddMethodToCXXRecordType (type_name_cstr, clang_type, accessibility, @@ -6802,7 +6835,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, is_explicit, is_attr_used, is_artificial); - + type_handled = cxx_method_decl != NULL; if (type_handled) @@ -6811,17 +6844,17 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, Host::SetCrashDescription (NULL); - + ClangASTMetadata metadata; metadata.SetUserID(MakeUserID(die->GetOffset())); - + if (!object_pointer_name.empty()) { metadata.SetObjectPtrName(object_pointer_name.c_str()); if (log) log->Printf ("Setting object pointer name: %s on method object %p.\n", object_pointer_name.c_str(), - cxx_method_decl); + static_cast<void*>(cxx_method_decl)); } GetClangASTContext().SetMetadata (cxx_method_decl, metadata); } @@ -6841,7 +6874,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, // we need to modify the m_die_to_type so it doesn't think we are // trying to parse this DIE anymore... m_die_to_type[die] = NULL; - + // Now we get the full type to force our class type to complete itself // using the clang::ExternalASTSource protocol which will parse all // base classes and all methods (including the method for this DIE). @@ -6854,7 +6887,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, type_sp = type_ptr->shared_from_this(); break; } - + // FIXME This is fixing some even uglier behavior but we really need to // uniq the methods of each class as well as the class itself. // <rdar://problem/11240464> @@ -6865,7 +6898,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, } } } - + if (!type_handled) { // We just have a function that isn't part of a class @@ -6893,17 +6926,17 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, ast.SetFunctionParameters (function_decl, &function_param_decls.front(), function_param_decls.size()); - + ClangASTMetadata metadata; metadata.SetUserID(MakeUserID(die->GetOffset())); - + if (!object_pointer_name.empty()) { metadata.SetObjectPtrName(object_pointer_name.c_str()); if (log) log->Printf ("Setting object pointer name: %s on function object %p.", object_pointer_name.c_str(), - function_decl); + static_cast<void*>(function_decl)); } GetClangASTContext().SetMetadata (function_decl, metadata); } @@ -6940,7 +6973,6 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, for (i=0; i<num_attributes; ++i) { attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; if (attributes.ExtractFormValueAtIndex(this, i, form_value)) { switch (attr) @@ -7022,13 +7054,12 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, dw_offset_t containing_type_die_offset = DW_INVALID_OFFSET; const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes); - + if (num_attributes > 0) { uint32_t i; for (i=0; i<num_attributes; ++i) { attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; if (attributes.ExtractFormValueAtIndex(this, i, form_value)) { switch (attr) @@ -7040,10 +7071,10 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, } } } - + Type *pointee_type = ResolveTypeUID(type_die_offset); Type *class_type = ResolveTypeUID(containing_type_die_offset); - + ClangASTType pointee_clang_type = pointee_type->GetClangForwardType(); ClangASTType class_clang_type = class_type->GetClangLayoutType(); @@ -7062,7 +7093,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, clang_type, Type::eResolveStateForward)); } - + break; } default: @@ -7342,6 +7373,7 @@ SymbolFileDWARF::ParseVariableDIE bool is_artificial = false; bool location_is_const_value_data = false; bool has_explicit_location = false; + DWARFFormValue const_value; //AccessType accessibility = eAccessNone; for (i=0; i<num_attributes; ++i) @@ -7380,7 +7412,21 @@ SymbolFileDWARF::ParseVariableDIE const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); 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); + if (data_length == 0) + { + const uint8_t *data_pointer = form_value.BlockData(); + if (data_pointer) + { + data_length = form_value.Unsigned(); + } + else if (DWARFFormValue::IsDataForm(form_value.Form())) + { + // we need to get the byte size of the type later after we create the variable + const_value = form_value; + } + } + else + location.CopyOpcodeData(module, debug_info_data, data_offset, data_length); } else { @@ -7455,7 +7501,7 @@ SymbolFileDWARF::ParseVariableDIE // DWARF doesn't specify if a DW_TAG_variable is a local, global // or static variable, so we have to do a little digging by - // looking at the location of a varaible to see if it contains + // looking at the location of a variable to see if it contains // a DW_OP_addr opcode _somewhere_ in the definition. I say // somewhere because clang likes to combine small global variables // into the same symbol and have locations like: @@ -7592,10 +7638,15 @@ SymbolFileDWARF::ParseVariableDIE if (symbol_context_scope) { + SymbolFileTypeSP type_sp(new SymbolFileType(*this, type_uid)); + + if (const_value.Form() && type_sp && type_sp->GetType()) + location.CopyOpcodeData(const_value.Unsigned(), type_sp->GetType()->GetByteSize(), dwarf_cu->GetAddressByteSize()); + var_sp.reset (new Variable (MakeUserID(die->GetOffset()), name, mangled, - SymbolFileTypeSP (new SymbolFileType(*this, type_uid)), + type_sp, scope, symbol_context_scope, &decl, @@ -7763,7 +7814,7 @@ SymbolFileDWARF::ParseVariables if (block == NULL) { // This must be a specification or abstract origin with - // a concrete block couterpart in the current function. We need + // a concrete block counterpart in the current function. We need // to find the concrete block so we can correctly add the // variable to it DWARFCompileUnit *concrete_block_die_cu = dwarf_cu; @@ -8011,12 +8062,11 @@ SymbolFileDWARF::LayoutRecordType (const clang::RecordDecl *record_decl, if (log) GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::LayoutRecordType (record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u],base_offsets[%u], vbase_offsets[%u]) success = %i", - record_decl, - bit_size, - alignment, - (uint32_t)field_offsets.size(), - (uint32_t)base_offsets.size(), - (uint32_t)vbase_offsets.size(), + static_cast<const void*>(record_decl), + bit_size, alignment, + static_cast<uint32_t>(field_offsets.size()), + static_cast<uint32_t>(base_offsets.size()), + static_cast<uint32_t>(vbase_offsets.size()), success); return success; } diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 8dac209361ed..178e5142d94b 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -368,9 +368,10 @@ protected: lldb_private::TypeList* type_list, std::vector<lldb_private::ClangASTType>& function_args, std::vector<clang::ParmVarDecl*>& function_param_decls, - unsigned &type_quals, - lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); - + unsigned &type_quals); + // lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); // not currently needed + + size_t ParseChildEnumerators( const lldb_private::SymbolContext& sc, lldb_private::ClangASTType &clang_type, @@ -546,7 +547,7 @@ protected: const DWARFDebugInfoEntry *src_class_die, DWARFCompileUnit* dst_cu, const DWARFDebugInfoEntry *dst_class_die, - llvm::SmallVectorImpl <const DWARFDebugInfoEntry *> &failures); + DWARFDIECollection &failures); bool FixupAddress (lldb_private::Address &addr); diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 856c42c2c9a6..af16c03a8c07 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -55,20 +55,19 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa Module *oso_module = exe_symfile->GetModuleByCompUnitInfo (this); if (!oso_module) return file_range_map; - + ObjectFile *oso_objfile = oso_module->GetObjectFile(); if (!oso_objfile) return file_range_map; - + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_MAP)); if (log) { ConstString object_name (oso_module->GetObjectName()); log->Printf("%p: SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap ('%s')", - this, + static_cast<void*>(this), oso_module->GetSpecificationDescription().c_str()); } - std::vector<SymbolFileDWARFDebugMap::CompileUnitInfo *> cu_infos; if (exe_symfile->GetCompUnitInfosForModule(oso_module, cu_infos)) @@ -78,12 +77,12 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa Symtab *exe_symtab = exe_symfile->GetObjectFile()->GetSymtab(); ModuleSP oso_module_sp (oso_objfile->GetModule()); Symtab *oso_symtab = oso_objfile->GetSymtab(); - + ///const uint32_t fun_resolve_flags = SymbolContext::Module | eSymbolContextCompUnit | eSymbolContextFunction; //SectionList *oso_sections = oso_objfile->Sections(); // Now we need to make sections that map from zero based object - // file addresses to where things eneded up in the main executable. - + // file addresses to where things ended up in the main executable. + assert (comp_unit_info->first_symbol_index != UINT32_MAX); // End index is one past the last valid symbol index const uint32_t oso_end_idx = comp_unit_info->last_symbol_index + 1; @@ -96,12 +95,12 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa { if (exe_symbol->IsDebug() == false) continue; - + switch (exe_symbol->GetType()) { default: break; - + case eSymbolTypeCode: { // For each N_FUN, or function that we run into in the debug map @@ -112,7 +111,7 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa // before we parse any dwarf info so that when it goes get parsed // all section/offset addresses that get registered will resolve // correctly to the new addresses in the main executable. - + // First we find the original symbol in the .o file's symbol table Symbol *oso_fun_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(Mangled::ePreferMangled), eSymbolTypeCode, @@ -125,11 +124,11 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa exe_symbol->GetAddress().GetFileAddress(), oso_fun_symbol->GetAddress().GetFileAddress(), std::min<addr_t>(exe_symbol->GetByteSize(), oso_fun_symbol->GetByteSize())); - + } } break; - + case eSymbolTypeData: { // For each N_GSYM we remap the address for the global by making @@ -144,13 +143,12 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa // fix up these addresses further after all globals have been // parsed to span the gaps, or we can find the global variable // sizes from the DWARF info as we are parsing. - + // Next we find the non-stab entry that corresponds to the N_GSYM in the .o file Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(Mangled::ePreferMangled), eSymbolTypeData, Symtab::eDebugNo, Symtab::eVisibilityAny); - if (exe_symbol && oso_gsym_symbol && exe_symbol->ValueIsAddress() && oso_gsym_symbol->ValueIsAddress()) @@ -166,7 +164,7 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa } } } - + exe_symfile->FinalizeOSOFileRanges (this); // We don't need the symbols anymore for the .o files oso_objfile->ClearSymtab(); @@ -216,7 +214,7 @@ public: SymbolVendor* symbol_vendor = Module::GetSymbolVendor(can_create, feedback_strm); if (symbol_vendor) { - // Set a a pointer to this class to set our OSO DWARF file know + // Set a pointer to this class to set our OSO DWARF file know // that the DWARF is being used along with a debug map and that // it will have the remapped sections that we do below. SymbolFileDWARF *oso_symfile = SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF(symbol_vendor->GetSymbolFile()); @@ -308,7 +306,7 @@ void SymbolFileDWARFDebugMap::InitializeObject() { // Install our external AST source callbacks so we can complete Clang types. - llvm::OwningPtr<clang::ExternalASTSource> ast_source_ap ( + llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source_ap ( new ClangExternalASTSourceCallbacks (SymbolFileDWARFDebugMap::CompleteTagDecl, SymbolFileDWARFDebugMap::CompleteObjCInterfaceDecl, NULL, @@ -341,6 +339,7 @@ SymbolFileDWARFDebugMap::InitOSO() case ObjectFile::eTypeObjectFile: case ObjectFile::eTypeStubLibrary: case ObjectFile::eTypeUnknown: + case ObjectFile::eTypeJIT: return; case ObjectFile::eTypeExecutable: @@ -505,10 +504,16 @@ SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo (CompileUnitInfo *comp_unit_inf // use the debug map, to add new sections to each .o file and // even though a .o file might not have changed, the sections // that get added to the .o file can change. + ArchSpec oso_arch; + // Only adopt the architecture from the module (not the vendor or OS) + // since .o files for "i386-apple-ios" will historically show up as "i386-apple-macosx" + // due to the lack of a LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS + // load command... + oso_arch.SetTriple(m_obj_file->GetModule()->GetArchitecture().GetTriple().getArchName().str().c_str()); comp_unit_info->oso_sp->module_sp.reset (new DebugMapModule (obj_file->GetModule(), GetCompUnitInfoIndex(comp_unit_info), oso_file, - m_obj_file->GetModule()->GetArchitecture(), + oso_arch, oso_object ? &oso_object : NULL, 0, oso_object ? &comp_unit_info->oso_mod_time : NULL)); diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 06330b98dc19..1493292d4b9b 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -393,7 +393,7 @@ protected: LinkOSOFileAddress (SymbolFileDWARF *oso_symfile, lldb::addr_t oso_file_addr); //------------------------------------------------------------------ - /// Given a line table full of lines with "file adresses" that are + /// Given a line table full of lines with "file addresses" that are /// for a .o file represented by \a oso_symfile, link a new line table /// and return it. /// @@ -405,7 +405,7 @@ protected: /// /// @return /// Returns a valid line table full of linked addresses, or NULL - /// if none of the line table adresses exist in the main + /// if none of the line table addresses exist in the main /// executable. //------------------------------------------------------------------ lldb_private::LineTable * diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index 9beba517ec83..8e85d4825281 100644 --- a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -145,7 +145,7 @@ SymbolFileSymtab::GetNumCompileUnits() if (m_source_indexes.empty()) return 0; - // If we have any source file symbols we will logically orgnize the object symbols + // If we have any source file symbols we will logically organize the object symbols // using these. return m_source_indexes.size(); } @@ -366,20 +366,6 @@ SymbolFileSymtab::FindFunctions(const RegularExpression& regex, bool include_inl return 0; } -static int CountMethodArgs(const char *method_signature) -{ - int num_args = 0; - - for (const char *colon_pos = strchr(method_signature, ':'); - colon_pos != NULL; - colon_pos = strchr(colon_pos + 1, ':')) - { - num_args++; - } - - return num_args; -} - uint32_t SymbolFileSymtab::FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index 8ddc1cd2ee84..b8d56d3909e9 100644 --- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -42,7 +42,7 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& m_inst_emulator_ap.get()) { - // The the instruction emulation subclass setup the unwind plan for the + // The instruction emulation subclass setup the unwind plan for the // first instruction. m_inst_emulator_ap->CreateFunctionEntryUnwind (unwind_plan); @@ -83,7 +83,7 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& // Initialize the CFA with a known value. In the 32 bit case // it will be 0x80000000, and in the 64 bit case 0x8000000000000000. - // We use the address byte size to be safe for any future addresss sizes + // We use the address byte size to be safe for any future address sizes m_initial_sp = (1ull << ((addr_byte_size * 8) - 1)); RegisterValue cfa_reg_value; cfa_reg_value.SetUInt (m_initial_sp, m_cfa_reg_info.byte_size); @@ -182,7 +182,7 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& // While parsing the instructions of this function, if we've ever // seen the return address register (aka lr on arm) in a non-IsSame() state, - // it has been saved on the stack. If it's evern back to IsSame(), we've + // it has been saved on the stack. If it's ever back to IsSame(), we've // executed an epilogue. if (ra_reg_num != LLDB_INVALID_REGNUM && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc) @@ -285,6 +285,14 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& } bool +UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite (AddressRange& func, + Thread& thread, + UnwindPlan& unwind_plan) +{ + return false; +} + +bool UnwindAssemblyInstEmulation::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan) @@ -358,7 +366,8 @@ UnwindAssemblyInstEmulation::GetPluginDescriptionStatic() uint64_t UnwindAssemblyInstEmulation::MakeRegisterKindValuePair (const RegisterInfo ®_info) { - uint32_t reg_kind, reg_num; + lldb::RegisterKind reg_kind; + uint32_t reg_num; if (EmulateInstruction::GetBestRegisterKindAndNumber (®_info, reg_kind, reg_num)) return (uint64_t)reg_kind << 24 | reg_num; return 0ull; diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h index 6a02f0a55104..758c3ce2e28b 100644 --- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h +++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h @@ -31,6 +31,11 @@ public: lldb_private::UnwindPlan& unwind_plan); virtual bool + AugmentUnwindPlanFromCallSite (lldb_private::AddressRange& func, + lldb_private::Thread& thread, + lldb_private::UnwindPlan& unwind_plan); + + virtual bool GetFastUnwindPlan (lldb_private::AddressRange& func, lldb_private::Thread& thread, lldb_private::UnwindPlan &unwind_plan); diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp index 1768798f71d4..32a21d2b8bb8 100644 --- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp +++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp @@ -27,12 +27,14 @@ using namespace lldb; using namespace lldb_private; -enum CPU { +enum CPU +{ k_i386, k_x86_64 }; -enum i386_register_numbers { +enum i386_register_numbers +{ k_machine_eax = 0, k_machine_ecx = 1, k_machine_edx = 2, @@ -44,7 +46,8 @@ enum i386_register_numbers { k_machine_eip = 8 }; -enum x86_64_register_numbers { +enum x86_64_register_numbers +{ k_machine_rax = 0, k_machine_rcx = 1, k_machine_rdx = 2, @@ -64,13 +67,15 @@ enum x86_64_register_numbers { k_machine_rip = 16 }; -struct regmap_ent { +struct regmap_ent +{ const char *name; int machine_regno; int lldb_regno; }; -static struct regmap_ent i386_register_map[] = { +static struct regmap_ent i386_register_map[] = +{ {"eax", k_machine_eax, -1}, {"ecx", k_machine_ecx, -1}, {"edx", k_machine_edx, -1}, @@ -82,11 +87,12 @@ static struct regmap_ent i386_register_map[] = { {"eip", k_machine_eip, -1} }; -const int size_of_i386_register_map = sizeof (i386_register_map) / sizeof (struct regmap_ent); +const int size_of_i386_register_map = llvm::array_lengthof (i386_register_map); static int i386_register_map_initialized = 0; -static struct regmap_ent x86_64_register_map[] = { +static struct regmap_ent x86_64_register_map[] = +{ {"rax", k_machine_rax, -1}, {"rcx", k_machine_rcx, -1}, {"rdx", k_machine_rdx, -1}, @@ -106,7 +112,7 @@ static struct regmap_ent x86_64_register_map[] = { {"rip", k_machine_rip, -1} }; -const int size_of_x86_64_register_map = sizeof (x86_64_register_map) / sizeof (struct regmap_ent); +const int size_of_x86_64_register_map = llvm::array_lengthof (x86_64_register_map); static int x86_64_register_map_initialized = 0; @@ -114,7 +120,8 @@ static int x86_64_register_map_initialized = 0; // AssemblyParse_x86 local-file class definition & implementation functions //----------------------------------------------------------------------------------------------- -class AssemblyParse_x86 { +class AssemblyParse_x86 +{ public: AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func); @@ -123,6 +130,8 @@ public: bool get_non_call_site_unwind_plan (UnwindPlan &unwind_plan); + bool augment_unwind_plan_from_call_site (AddressRange& func, UnwindPlan &unwind_plan); + bool get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan); bool find_first_non_prologue_insn (Address &address); @@ -135,9 +144,14 @@ private: bool push_0_pattern_p (); bool mov_rsp_rbp_pattern_p (); bool sub_rsp_pattern_p (int& amount); + bool add_rsp_pattern_p (int& amount); bool push_reg_p (int& regno); + bool pop_reg_p (int& regno); + bool push_imm_pattern_p (); bool mov_reg_to_local_stack_frame_p (int& regno, int& fp_offset); bool ret_pattern_p (); + bool pop_rbp_pattern_p (); + bool call_next_insn_pattern_p(); uint32_t extract_4 (uint8_t *b); bool machine_regno_to_lldb_regno (int machine_regno, uint32_t& lldb_regno); bool instruction_length (Address addr, int &length); @@ -149,13 +163,13 @@ private: Address m_cur_insn; uint8_t m_cur_insn_bytes[kMaxInstructionByteSize]; - int m_machine_ip_regnum; - int m_machine_sp_regnum; - int m_machine_fp_regnum; + uint32_t m_machine_ip_regnum; + uint32_t m_machine_sp_regnum; + uint32_t m_machine_fp_regnum; - int m_lldb_ip_regnum; - int m_lldb_sp_regnum; - int m_lldb_fp_regnum; + uint32_t m_lldb_ip_regnum; + uint32_t m_lldb_sp_regnum; + uint32_t m_lldb_fp_regnum; int m_wordsize; int m_cpu; @@ -166,16 +180,16 @@ private: }; AssemblyParse_x86::AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func) : - m_exe_ctx (exe_ctx), - m_func_bounds(func), + m_exe_ctx (exe_ctx), + m_func_bounds(func), m_cur_insn (), m_machine_ip_regnum (LLDB_INVALID_REGNUM), m_machine_sp_regnum (LLDB_INVALID_REGNUM), m_machine_fp_regnum (LLDB_INVALID_REGNUM), - m_lldb_ip_regnum (LLDB_INVALID_REGNUM), + m_lldb_ip_regnum (LLDB_INVALID_REGNUM), m_lldb_sp_regnum (LLDB_INVALID_REGNUM), m_lldb_fp_regnum (LLDB_INVALID_REGNUM), - m_wordsize (-1), + m_wordsize (-1), m_cpu(cpu), m_arch(arch) { @@ -242,8 +256,8 @@ AssemblyParse_x86::AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu, m_lldb_ip_regnum = lldb_regno; } - m_disasm_context = ::LLVMCreateDisasm(m_arch.GetTriple().getTriple().c_str(), - (void*)this, + m_disasm_context = ::LLVMCreateDisasm(m_arch.GetTriple().getTriple().c_str(), + (void*)this, /*TagType=*/1, NULL, NULL); @@ -254,7 +268,7 @@ AssemblyParse_x86::~AssemblyParse_x86 () ::LLVMDisasmDispose(m_disasm_context); } -// This function expects an x86 native register number (i.e. the bits stripped out of the +// This function expects an x86 native register number (i.e. the bits stripped out of the // actual instruction), not an lldb register number. bool @@ -262,7 +276,8 @@ AssemblyParse_x86::nonvolatile_reg_p (int machine_regno) { if (m_cpu == k_i386) { - switch (machine_regno) { + switch (machine_regno) + { case k_machine_ebx: case k_machine_ebp: // not actually a nonvolatile but often treated as such by convention case k_machine_esi: @@ -275,7 +290,8 @@ AssemblyParse_x86::nonvolatile_reg_p (int machine_regno) } if (m_cpu == k_x86_64) { - switch (machine_regno) { + switch (machine_regno) + { case k_machine_rbx: case k_machine_rsp: case k_machine_rbp: // not actually a nonvolatile but often treated as such by convention @@ -292,7 +308,7 @@ AssemblyParse_x86::nonvolatile_reg_p (int machine_regno) } -// Macro to detect if this is a REX mode prefix byte. +// Macro to detect if this is a REX mode prefix byte. #define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48) // The high bit which should be added to the source register number (the "R" bit) @@ -302,7 +318,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) return true; @@ -318,9 +335,20 @@ bool AssemblyParse_x86::push_0_pattern_p () return false; } +// pushq $0 +// pushl $0 +bool AssemblyParse_x86::push_imm_pattern_p () +{ + uint8_t *p = m_cur_insn_bytes; + if (*p == 0x68 || *p == 0x6a) + return true; + return false; +} + // 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) p++; @@ -331,57 +359,127 @@ bool AssemblyParse_x86::mov_rsp_rbp_pattern_p () { return false; } -// subq $0x20, %rsp -bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount) { +// subq $0x20, %rsp +bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount) +{ uint8_t *p = m_cur_insn_bytes; if (m_wordsize == 8 && *p == 0x48) p++; // 8-bit immediate operand - if (*p == 0x83 && *(p + 1) == 0xec) { + if (*p == 0x83 && *(p + 1) == 0xec) + { amount = (int8_t) *(p + 2); return true; } // 32-bit immediate operand - if (*p == 0x81 && *(p + 1) == 0xec) { + if (*p == 0x81 && *(p + 1) == 0xec) + { + amount = (int32_t) extract_4 (p + 2); + return true; + } + return false; +} + +// addq $0x20, %rsp +bool AssemblyParse_x86::add_rsp_pattern_p (int& amount) +{ + uint8_t *p = m_cur_insn_bytes; + if (m_wordsize == 8 && *p == 0x48) + p++; + // 8-bit immediate operand + if (*p == 0x83 && *(p + 1) == 0xc4) + { + amount = (int8_t) *(p + 2); + return true; + } + // 32-bit immediate operand + if (*p == 0x81 && *(p + 1) == 0xc4) + { amount = (int32_t) extract_4 (p + 2); return true; } - // Not handled: [0x83 0xc4] for imm8 with neg values - // [0x81 0xc4] for imm32 with neg values return false; } // pushq %rbx -// pushl $ebx -bool AssemblyParse_x86::push_reg_p (int& regno) { +// pushl %ebx +bool AssemblyParse_x86::push_reg_p (int& regno) +{ uint8_t *p = m_cur_insn_bytes; int regno_prefix_bit = 0; // If we have a rex prefix byte, check to see if a B bit is set - if (m_wordsize == 8 && *p == 0x41) { + if (m_wordsize == 8 && *p == 0x41) + { regno_prefix_bit = 1 << 3; p++; } - if (*p >= 0x50 && *p <= 0x57) { + if (*p >= 0x50 && *p <= 0x57) + { regno = (*p - 0x50) | regno_prefix_bit; return true; } return false; } +// popq %rbx +// popl %ebx +bool AssemblyParse_x86::pop_reg_p (int& regno) +{ + uint8_t *p = m_cur_insn_bytes; + int regno_prefix_bit = 0; + // If we have a rex prefix byte, check to see if a B bit is set + if (m_wordsize == 8 && *p == 0x41) + { + regno_prefix_bit = 1 << 3; + p++; + } + if (*p >= 0x58 && *p <= 0x5f) + { + regno = (*p - 0x58) | regno_prefix_bit; + return true; + } + return false; +} + +// popq %rbp [0x5d] +// popl %ebp [0x5d] +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 () +{ + uint8_t *p = m_cur_insn_bytes; + return (*p == 0xe8) && (*(p+1) == 0x0) && (*(p+2) == 0x0) + && (*(p+3) == 0x0) && (*(p+4) == 0x0); +} + // Look for an instruction sequence storing a nonvolatile register // on to the stack frame. // movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0] // movl %eax, -0xc(%ebp) [0x89 0x45 0xf4] -bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset) { + +// The offset value returned in rbp_offset will be positive -- +// but it must be subtraced from the frame base register to get +// 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) +{ uint8_t *p = m_cur_insn_bytes; int src_reg_prefix_bit = 0; int target_reg_prefix_bit = 0; - if (m_wordsize == 8 && REX_W_PREFIX_P (*p)) { + if (m_wordsize == 8 && REX_W_PREFIX_P (*p)) + { src_reg_prefix_bit = REX_W_SRCREG (*p) << 3; target_reg_prefix_bit = REX_W_DSTREG (*p) << 3; - if (target_reg_prefix_bit == 1) { + if (target_reg_prefix_bit == 1) + { // rbp/ebp don't need a prefix bit - we know this isn't the // reg we care about. return false; @@ -389,12 +487,13 @@ bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_off p++; } - if (*p == 0x89) { + if (*p == 0x89) + { /* Mask off the 3-5 bits which indicate the destination register if this is a ModR/M byte. */ int opcode_destreg_masked_out = *(p + 1) & (~0x38); - /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101 + /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101 and three bits between them, e.g. 01nnn101 We're looking for a destination of ebp-disp8 or ebp-disp32. */ int immsize; @@ -421,8 +520,8 @@ bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_off } // ret [0xc9] or [0xc2 imm8] or [0xca imm8] -bool -AssemblyParse_x86::ret_pattern_p () +bool +AssemblyParse_x86::ret_pattern_p () { uint8_t *p = m_cur_insn_bytes; if (*p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3) @@ -439,7 +538,7 @@ AssemblyParse_x86::extract_4 (uint8_t *b) return v; } -bool +bool AssemblyParse_x86::machine_regno_to_lldb_regno (int machine_regno, uint32_t &lldb_regno) { struct regmap_ent *ent; @@ -479,11 +578,12 @@ AssemblyParse_x86::instruction_length (Address addr, int &length) const bool prefer_file_cache = true; Error error; Target *target = m_exe_ctx.GetTargetPtr(); - if (target->ReadMemory (addr, prefer_file_cache, opcode_data.data(), max_op_byte_size, error) == -1) + if (target->ReadMemory (addr, prefer_file_cache, opcode_data.data(), + max_op_byte_size, error) == static_cast<size_t>(-1)) { return false; } - + char out_string[512]; const addr_t pc = addr.GetFileAddress(); const size_t inst_size = ::LLVMDisasmInstruction (m_disasm_context, @@ -498,7 +598,7 @@ AssemblyParse_x86::instruction_length (Address addr, int &length) } -bool +bool AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan) { UnwindPlan::RowSP row(new UnwindPlan::Row); @@ -552,7 +652,8 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan) // An unrecognized/junk instruction break; } - if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, insn_len, error) == -1) + if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, + insn_len, error) == static_cast<size_t>(-1)) { // Error reading the instruction out of the file, stop scanning break; @@ -631,7 +732,13 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan) { row->SetOffset (current_func_text_offset + insn_len); UnwindPlan::Row::RegisterLocation regloc; - regloc.SetAtCFAPlusOffset (-row->GetCFAOffset()); + + // 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())); + row->SetRegisterInfo (lldb_regno, regloc); unwind_plan.AppendRow (row); // Allocate a new Row, populate it with the existing Row contents. @@ -679,45 +786,65 @@ loopnext: m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len); current_func_text_offset += insn_len; } - + // 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 - // [ 0x5d ] mov %rbp, %rsp + // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp) + // [ 0xc3 ] ret + + // or + + // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp) + // [ 0xe9 xx xx xx xx ] jmp objc_retainAutoreleaseReturnValue (this is sometimes the final insn in the function) + + // or + + // [ 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) // 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) 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()); - + 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) != -1) + if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7, + error) != static_cast<size_t>(-1)) { - if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov, ret + if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov & ret { ret_insn_offset = m_func_bounds.GetByteSize() - 1; } - else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov, ret, call + 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 { ret_insn_offset = m_func_bounds.GetByteSize() - 6; } } - } else if (m_func_bounds.GetByteSize() > 2) + } + 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) != -1) + if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2, + error) != static_cast<size_t>(-1)) { - if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov, ret + if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov & ret { ret_insn_offset = m_func_bounds.GetByteSize() - 1; } @@ -734,7 +861,7 @@ loopnext: epi_row->SetOffset (ret_insn_offset); epi_row->SetCFARegister (m_lldb_sp_regnum); epi_row->SetCFAOffset (m_wordsize); - + // 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); @@ -745,7 +872,7 @@ loopnext: unwind_plan.AppendRow (epi_row); } - + unwind_plan.SetSourceName ("assembly insn profiling"); unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes); @@ -753,13 +880,211 @@ loopnext: return true; } -/* The "fast unwind plan" is valid for functions that follow the usual convention of +bool +AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, UnwindPlan &unwind_plan) +{ + // Is func address valid? + Address addr_start = func.GetBaseAddress(); + if (!addr_start.IsValid()) + return false; + + // Is original unwind_plan valid? + // unwind_plan should have at least one row which is ABI-default (CFA register is sp), + // and another row in mid-function. + if (unwind_plan.GetRowCount() < 2) + return false; + UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex (0); + if (first_row->GetOffset() != 0) + return false; + uint32_t cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext() + ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(), + first_row->GetCFARegister()); + if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAOffset() != m_wordsize) + return false; + + 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)); + while (func.ContainsFileAddress (m_cur_insn)) + { + int insn_len; + if (!instruction_length (m_cur_insn, insn_len) + || insn_len == 0 || insn_len > kMaxInstructionByteSize) + { + // An unrecognized/junk instruction. + break; + } + const bool prefer_file_cache = true; + Error error; + if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, + insn_len, error) == static_cast<size_t>(-1)) + { + // Error reading the instruction out of the file, stop scanning. + break; + } + + // Advance offsets. + offset += insn_len; + m_cur_insn.SetOffset(m_cur_insn.GetOffset() + insn_len); + + // 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) + { + *row = *original_row; + continue; + } + + if (row_id == 0) + { + // If we are here, compiler didn't generate CFI for prologue. + // This won't happen to GCC or clang. + // In this case, bail out directly. + return false; + } + + // Inspect the instruction to check if we need a new row for it. + cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext() + ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(), + row->GetCFARegister()); + if (cfa_reg == m_lldb_sp_regnum) + { + // CFA register is sp. + + // call next instruction + // call 0 + // => pop %ebx + if (call_next_insn_pattern_p ()) + { + row->SetOffset (offset); + row->SetCFAOffset (m_wordsize + row->GetCFAOffset()); + + UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); + unwind_plan.InsertRow (new_row); + unwind_plan_updated = true; + continue; + } + + // push/pop register + int regno; + if (push_reg_p (regno)) + { + row->SetOffset (offset); + row->SetCFAOffset (m_wordsize + row->GetCFAOffset()); + + UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); + unwind_plan.InsertRow (new_row); + unwind_plan_updated = true; + continue; + } + if (pop_reg_p (regno)) + { + // Technically, this might be a nonvolatile register recover in epilogue. + // We should reset RegisterInfo for the register. + // But in practice, previous rule for the register is still valid... + // So we ignore this case. + + row->SetOffset (offset); + row->SetCFAOffset (-m_wordsize + row->GetCFAOffset()); + + UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); + unwind_plan.InsertRow (new_row); + unwind_plan_updated = true; + continue; + } + + // push imm + if (push_imm_pattern_p ()) + { + row->SetOffset (offset); + row->SetCFAOffset (m_wordsize + row->GetCFAOffset()); + UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); + unwind_plan.InsertRow (new_row); + unwind_plan_updated = true; + continue; + } + + // add/sub %rsp/%esp + int amount; + if (add_rsp_pattern_p (amount)) + { + row->SetOffset (offset); + row->SetCFAOffset (-amount + row->GetCFAOffset()); + + UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); + unwind_plan.InsertRow (new_row); + unwind_plan_updated = true; + continue; + } + if (sub_rsp_pattern_p (amount)) + { + row->SetOffset (offset); + row->SetCFAOffset (amount + row->GetCFAOffset()); + + UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); + unwind_plan.InsertRow (new_row); + unwind_plan_updated = true; + continue; + } + } + else if (cfa_reg == m_lldb_fp_regnum) + { + // CFA register is fp. + + // The only case we care about is epilogue: + // [0x5d] pop %rbp/%ebp + // => [0xc3] ret + if (pop_rbp_pattern_p ()) + { + if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, + 1, error) != static_cast<size_t>(-1) + && ret_pattern_p ()) + { + row->SetOffset (offset); + row->SetCFARegister (first_row->GetCFARegister()); + row->SetCFAOffset (m_wordsize); + + UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); + unwind_plan.InsertRow (new_row); + unwind_plan_updated = true; + continue; + } + } + } + else + { + // CFA register is not sp or fp. + + // This must be hand-written assembly. + // Just trust eh_frame and assume we have finished. + break; + } + } + + unwind_plan.SetPlanValidAddressRange (func); + if (unwind_plan_updated) + { + std::string unwind_plan_source (unwind_plan.GetSourceName().AsCString()); + unwind_plan_source += " plus augmentation from assembly parsing"; + unwind_plan.SetSourceName (unwind_plan_source.c_str()); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + } + return true; +} + +/* The "fast unwind plan" is valid for functions that follow the usual convention of using the frame pointer register (ebp, rbp), i.e. the function prologue looks like push %rbp [0x55] mov %rsp,%rbp [0x48 0x89 0xe5] (this is a 2-byte insn seq on i386) */ -bool +bool AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan) { UnwindPlan::RowSP row(new UnwindPlan::Row); @@ -776,7 +1101,8 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_ uint8_t bytebuf[4]; Error error; const bool prefer_file_cache = true; - if (target->ReadMemory (func.GetBaseAddress(), prefer_file_cache, bytebuf, sizeof (bytebuf), error) == -1) + if (target->ReadMemory (func.GetBaseAddress(), prefer_file_cache, bytebuf, + sizeof (bytebuf), error) == static_cast<size_t>(-1)) return false; uint8_t i386_prologue[] = {0x55, 0x89, 0xe5}; @@ -821,7 +1147,7 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_ newrow = new UnwindPlan::Row; *newrow = *row.get(); row.reset(newrow); - + // mov %rsp, %rbp has executed row->SetCFARegister (m_lldb_fp_regnum); row->SetCFAOffset (2 * m_wordsize); @@ -839,7 +1165,7 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_ return true; } -bool +bool AssemblyParse_x86::find_first_non_prologue_insn (Address &address) { m_cur_insn = m_func_bounds.GetBaseAddress (); @@ -859,7 +1185,8 @@ AssemblyParse_x86::find_first_non_prologue_insn (Address &address) // An error parsing the instruction, i.e. probably data/garbage - stop scanning break; } - if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, insn_len, error) == -1) + if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, + insn_len, error) == static_cast<size_t>(-1)) { // Error reading the instruction out of the file, stop scanning break; @@ -886,11 +1213,11 @@ AssemblyParse_x86::find_first_non_prologue_insn (Address &address) //----------------------------------------------------------------------------------------------- -// UnwindAssemblyParser_x86 method definitions +// UnwindAssemblyParser_x86 method definitions //----------------------------------------------------------------------------------------------- -UnwindAssembly_x86::UnwindAssembly_x86 (const ArchSpec &arch, int cpu) : - lldb_private::UnwindAssembly(arch), +UnwindAssembly_x86::UnwindAssembly_x86 (const ArchSpec &arch, int cpu) : + lldb_private::UnwindAssembly(arch), m_cpu(cpu), m_arch(arch) { @@ -910,6 +1237,14 @@ 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 UnwindAssembly_x86::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan) { ExecutionContext exe_ctx (thread.shared_from_this()); diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h index eebaa7b6c803..8a4fe7c09800 100644 --- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h +++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h @@ -27,6 +27,11 @@ public: lldb_private::UnwindPlan& unwind_plan); virtual bool + AugmentUnwindPlanFromCallSite (lldb_private::AddressRange& func, + lldb_private::Thread& thread, + lldb_private::UnwindPlan& unwind_plan); + + virtual bool GetFastUnwindPlan (lldb_private::AddressRange& func, lldb_private::Thread& thread, lldb_private::UnwindPlan &unwind_plan); |