diff options
author | Ed Maste <emaste@FreeBSD.org> | 2014-11-25 21:00:58 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2014-11-25 21:00:58 +0000 |
commit | 0cac4ca3916ac24ab6139d03cbfd18db9e715bfe (patch) | |
tree | c94307da318be46e5aeea1a325c1e91749506e4f /source/Plugins | |
parent | 03b99097822ca3ac69252d9afae716a584ed56c4 (diff) | |
download | src-0cac4ca3916ac24ab6139d03cbfd18db9e715bfe.tar.gz src-0cac4ca3916ac24ab6139d03cbfd18db9e715bfe.zip |
Import LLDB as of upstream SVN r216948 (git 50f7fe44)vendor/lldb/lldb-r216948
This corresponds with the branchpoint for the 3.5 release.
A number of files not required for the FreeBSD build have been removed.
Sponsored by: DARPA, AFRL
Notes
Notes:
svn path=/vendor/lldb/dist/; revision=275072
svn path=/vendor/lldb/lldb-r216948/; revision=275074; tag=vendor/lldb/lldb-r216948
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 |