Adds Register Context Linux/POSIX for ARM Architecture

This patch is major step towards supporting lldb on ARM.
This adds all the required bits to support register manipulation on Linux Arm.
Also adds utility enumerations, definitions and register context classes for arm.

llvm-svn: 234870
This commit is contained in:
Omair Javaid 2015-04-14 07:30:20 +00:00
parent ff499469e0
commit 3f57216ca4
20 changed files with 2302 additions and 0 deletions

View File

@ -7,6 +7,7 @@ include_directories(../Utility)
add_lldb_library(lldbPluginProcessLinux add_lldb_library(lldbPluginProcessLinux
LinuxThread.cpp LinuxThread.cpp
NativeProcessLinux.cpp NativeProcessLinux.cpp
NativeRegisterContextLinux_arm.cpp
NativeRegisterContextLinux_arm64.cpp NativeRegisterContextLinux_arm64.cpp
NativeRegisterContextLinux_x86_64.cpp NativeRegisterContextLinux_x86_64.cpp
NativeRegisterContextLinux_mips64.cpp NativeRegisterContextLinux_mips64.cpp

View File

@ -0,0 +1,520 @@
//===-- NativeRegisterContextLinux_arm.cpp --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "NativeRegisterContextLinux_arm.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
#include "Plugins/Process/Linux/NativeProcessLinux.h"
#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr))
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_linux;
// arm general purpose registers.
static const uint32_t g_gpr_regnums_arm[] =
{
gpr_r0_arm,
gpr_r1_arm,
gpr_r2_arm,
gpr_r3_arm,
gpr_r4_arm,
gpr_r5_arm,
gpr_r6_arm,
gpr_r7_arm,
gpr_r8_arm,
gpr_r9_arm,
gpr_r10_arm,
gpr_r11_arm,
gpr_r12_arm,
gpr_sp_arm,
gpr_lr_arm,
gpr_pc_arm,
gpr_cpsr_arm,
LLDB_INVALID_REGNUM // register sets need to end with this flag
};
static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == k_num_gpr_registers_arm, \
"g_gpr_regnums_arm has wrong number of register infos");
// arm floating point registers.
static const uint32_t g_fpu_regnums_arm[] =
{
fpu_s0_arm,
fpu_s1_arm,
fpu_s2_arm,
fpu_s3_arm,
fpu_s4_arm,
fpu_s5_arm,
fpu_s6_arm,
fpu_s7_arm,
fpu_s8_arm,
fpu_s9_arm,
fpu_s10_arm,
fpu_s11_arm,
fpu_s12_arm,
fpu_s13_arm,
fpu_s14_arm,
fpu_s15_arm,
fpu_s16_arm,
fpu_s17_arm,
fpu_s18_arm,
fpu_s19_arm,
fpu_s20_arm,
fpu_s21_arm,
fpu_s22_arm,
fpu_s23_arm,
fpu_s24_arm,
fpu_s25_arm,
fpu_s26_arm,
fpu_s27_arm,
fpu_s28_arm,
fpu_s29_arm,
fpu_s30_arm,
fpu_s31_arm,
fpu_fpscr_arm,
LLDB_INVALID_REGNUM // register sets need to end with this flag
};
static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \
"g_fpu_regnums_arm has wrong number of register infos");
namespace {
// Number of register sets provided by this context.
enum
{
k_num_register_sets = 2
};
}
// Register sets for arm.
static const RegisterSet
g_reg_sets_arm[k_num_register_sets] =
{
{ "General Purpose Registers", "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm },
{ "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm }
};
NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm (
NativeThreadProtocol &native_thread,
uint32_t concrete_frame_idx,
RegisterInfoInterface *reg_info_interface_p) :
NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p)
{
switch (reg_info_interface_p->m_target_arch.GetMachine())
{
case llvm::Triple::arm:
m_reg_info.num_registers = k_num_registers_arm;
m_reg_info.num_gpr_registers = k_num_gpr_registers_arm;
m_reg_info.num_fpr_registers = k_num_fpr_registers_arm;
m_reg_info.last_gpr = k_last_gpr_arm;
m_reg_info.first_fpr = k_first_fpr_arm;
m_reg_info.last_fpr = k_last_fpr_arm;
m_reg_info.first_fpr_v = fpu_s0_arm;
m_reg_info.last_fpr_v = fpu_s31_arm;
m_reg_info.gpr_flags = gpr_cpsr_arm;
break;
default:
assert(false && "Unhandled target architecture.");
break;
}
::memset(&m_fpr, 0, sizeof (m_fpr));
::memset(&m_gpr_arm, 0, sizeof (m_gpr_arm));
}
uint32_t
NativeRegisterContextLinux_arm::GetRegisterSetCount () const
{
return k_num_register_sets;
}
const RegisterSet *
NativeRegisterContextLinux_arm::GetRegisterSet (uint32_t set_index) const
{
if (set_index < k_num_register_sets)
return &g_reg_sets_arm[set_index];
return nullptr;
}
Error
NativeRegisterContextLinux_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
{
Error error;
if (!reg_info)
{
error.SetErrorString ("reg_info NULL");
return error;
}
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
if (IsFPR(reg))
{
if (!ReadFPR())
{
error.SetErrorString ("failed to read floating point register");
return error;
}
}
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];
}
error = ReadRegisterRaw(full_reg, reg_value);
if (error.Success ())
{
// If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
if (is_subreg && (reg_info->byte_offset & 0x1))
reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
// If our return byte size was greater than the return value reg size, then
// use the type specified by reg_info rather than the uint64_t default
if (reg_value.GetByteSize() > reg_info->byte_size)
reg_value.SetType(reg_info);
}
return error;
}
// 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:
reg_value.SetUInt16(*(uint16_t *)src);
break;
case 4:
reg_value.SetUInt32(*(uint32_t *)src);
break;
case 8:
reg_value.SetUInt64(*(uint64_t *)src);
break;
default:
assert(false && "Unhandled data size.");
error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
break;
}
return error;
}
Error
NativeRegisterContextLinux_arm::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
{
if (!reg_info)
return Error ("reg_info NULL");
const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
if (reg_index == LLDB_INVALID_REGNUM)
return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
if (IsGPR(reg_index))
return WriteRegisterRaw(reg_index, reg_value);
if (IsFPR(reg_index))
{
// Get pointer to m_fpr variable and set the data to it.
assert (reg_info->byte_offset < sizeof(m_fpr));
uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
switch (reg_info->byte_size)
{
case 2:
*(uint16_t *)dst = reg_value.GetAsUInt16();
break;
case 4:
*(uint32_t *)dst = reg_value.GetAsUInt32();
break;
case 8:
*(uint64_t *)dst = reg_value.GetAsUInt64();
break;
default:
assert(false && "Unhandled data size.");
return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
}
if (!WriteFPR())
{
return Error ("NativeRegisterContextLinux_arm::WriteRegister: WriteFPR failed");
}
return Error ();
}
return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
}
Error
NativeRegisterContextLinux_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
{
Error error;
data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
if (!data_sp)
return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
if (!ReadGPR ())
{
error.SetErrorString ("ReadGPR() failed");
return error;
}
if (!ReadFPR ())
{
error.SetErrorString ("ReadFPR() failed");
return error;
}
uint8_t *dst = data_sp->GetBytes ();
if (dst == nullptr)
{
error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
return error;
}
::memcpy (dst, &m_gpr_arm, GetGPRSize());
dst += GetGPRSize();
::memcpy (dst, &m_fpr, sizeof(m_fpr));
return error;
}
Error
NativeRegisterContextLinux_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
{
Error error;
if (!data_sp)
{
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
return error;
}
if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
{
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
return error;
}
uint8_t *src = data_sp->GetBytes ();
if (src == nullptr)
{
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
return error;
}
::memcpy (&m_gpr_arm, src, GetRegisterInfoInterface ().GetGPRSize ());
if (!WriteGPR ())
{
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__);
return error;
}
src += GetRegisterInfoInterface ().GetGPRSize ();
::memcpy (&m_fpr, src, sizeof(m_fpr));
if (!WriteFPR ())
{
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__);
return error;
}
return error;
}
Error
NativeRegisterContextLinux_arm::WriteRegisterRaw (uint32_t reg_index, const RegisterValue &reg_value)
{
Error error;
uint32_t reg_to_write = reg_index;
RegisterValue value_to_write = reg_value;
// Check if this is a subregister of a full register.
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
{
RegisterValue full_value;
uint32_t full_reg = reg_info->invalidate_regs[0];
const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
// Read the full register.
error = ReadRegister(full_reg_info, full_value);
if (error.Fail ())
return error;
lldb::ByteOrder byte_order = GetByteOrder();
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the full register.
const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
dst,
sizeof(dst),
byte_order,
error);
if (error.Success() && dest_size)
{
uint8_t src[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the source data.
const uint32_t src_size = reg_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;
}
}
}
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
if (!process_sp)
{
error.SetErrorString ("NativeProcessProtocol is NULL");
return error;
}
const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write);
assert (register_to_write_info_p && "register to write does not have valid RegisterInfo");
if (!register_to_write_info_p)
{
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_arm::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
return error;
}
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
return process_p->WriteRegisterValue(m_thread.GetID(),
register_to_write_info_p->byte_offset,
register_to_write_info_p->name,
value_to_write);
}
Error
NativeRegisterContextLinux_arm::ReadRegisterRaw (uint32_t reg_index, RegisterValue &reg_value)
{
Error error;
const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index);
if (!reg_info)
{
error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index);
return error;
}
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
if (!process_sp)
{
error.SetErrorString ("NativeProcessProtocol is NULL");
return error;
}
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
return process_p->ReadRegisterValue(m_thread.GetID(),
reg_info->byte_offset,
reg_info->name,
reg_info->byte_size,
reg_value);
}
bool
NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const
{
return reg <= m_reg_info.last_gpr; // GPR's come first.
}
bool
NativeRegisterContextLinux_arm::ReadGPR()
{
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
if (!process_sp)
return false;
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
return process_p->ReadGPR (m_thread.GetID (), &m_gpr_arm, GetRegisterInfoInterface ().GetGPRSize ()).Success();
}
bool
NativeRegisterContextLinux_arm::WriteGPR()
{
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
if (!process_sp)
return false;
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
return process_p->WriteGPR (m_thread.GetID (), &m_gpr_arm, GetRegisterInfoInterface ().GetGPRSize ()).Success();
}
bool
NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const
{
return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
}
bool
NativeRegisterContextLinux_arm::ReadFPR ()
{
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
if (!process_sp)
return false;
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
return process_p->ReadFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
}
bool
NativeRegisterContextLinux_arm::WriteFPR ()
{
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
if (!process_sp)
return false;
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
return process_p->WriteFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
}
lldb::ByteOrder
NativeRegisterContextLinux_arm::GetByteOrder() const
{
// Get the target process whose privileged thread was used for the register read.
lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
if (!process_sp)
return byte_order;
if (!process_sp->GetByteOrder (byte_order))
{
// FIXME log here
}
return byte_order;
}
size_t
NativeRegisterContextLinux_arm::GetGPRSize() const
{
return GetRegisterInfoInterface().GetGPRSize();
}

View File

@ -0,0 +1,116 @@
//===-- NativeRegisterContextLinux_arm.h ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef lldb_NativeRegisterContextLinux_arm_h
#define lldb_NativeRegisterContextLinux_arm_h
#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h"
#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
namespace lldb_private {
namespace process_linux {
class NativeProcessLinux;
class NativeRegisterContextLinux_arm : public NativeRegisterContextRegisterInfo
{
public:
NativeRegisterContextLinux_arm (NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p);
uint32_t
GetRegisterSetCount () const override;
const RegisterSet *
GetRegisterSet (uint32_t set_index) const override;
Error
ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value) override;
Error
WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
Error
ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override;
Error
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
private:
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;
};
struct QReg
{
uint8_t bytes[16];
};
struct FPU
{
union {
uint32_t s[32];
uint64_t d[32];
QReg q[16]; // the 128-bit NEON registers
} floats;
uint32_t fpscr;
};
uint32_t m_gpr_arm[k_num_gpr_registers_arm];
RegInfo m_reg_info;
FPU m_fpr;
bool
IsGPR(unsigned reg) const;
bool
ReadGPR ();
bool
WriteGPR ();
bool
IsFPR(unsigned reg) const;
bool
ReadFPR ();
bool
WriteFPR ();
Error
ReadRegisterRaw (uint32_t reg_index, RegisterValue &reg_value);
Error
WriteRegisterRaw (uint32_t reg_index, const RegisterValue &reg_value);
lldb::ByteOrder
GetByteOrder() const;
size_t
GetGPRSize() const;
};
} // namespace process_linux
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextLinux_arm_h

View File

@ -13,6 +13,7 @@
#include <sstream> #include <sstream>
#include "NativeProcessLinux.h" #include "NativeProcessLinux.h"
#include "NativeRegisterContextLinux_arm.h"
#include "NativeRegisterContextLinux_arm64.h" #include "NativeRegisterContextLinux_arm64.h"
#include "NativeRegisterContextLinux_x86_64.h" #include "NativeRegisterContextLinux_x86_64.h"
#include "NativeRegisterContextLinux_mips64.h" #include "NativeRegisterContextLinux_mips64.h"
@ -29,6 +30,7 @@
#include "Plugins/Process/POSIX/CrashReason.h" #include "Plugins/Process/POSIX/CrashReason.h"
#include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
#include "Plugins/Process/Utility/RegisterContextLinux_i386.h" #include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
@ -184,6 +186,10 @@ NativeThreadLinux::GetRegisterContext ()
assert((HostInfo::GetArchitecture ().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); 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)); reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm64(target_arch));
break; break;
case llvm::Triple::arm:
assert(HostInfo::GetArchitecture ().GetAddressByteSize() == 4);
reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm(target_arch));
break;
case llvm::Triple::x86: case llvm::Triple::x86:
case llvm::Triple::x86_64: case llvm::Triple::x86_64:
if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) if (HostInfo::GetArchitecture().GetAddressByteSize() == 4)
@ -242,6 +248,12 @@ NativeThreadLinux::GetRegisterContext ()
m_reg_context_sp.reset (new NativeRegisterContextLinux_arm64(*this, concrete_frame_idx, reg_interface)); m_reg_context_sp.reset (new NativeRegisterContextLinux_arm64(*this, concrete_frame_idx, reg_interface));
break; break;
} }
case llvm::Triple::arm:
{
const uint32_t concrete_frame_idx = 0;
m_reg_context_sp.reset (new NativeRegisterContextLinux_arm(*this, concrete_frame_idx, reg_interface));
break;
}
case llvm::Triple::x86: case llvm::Triple::x86:
case llvm::Triple::x86_64: case llvm::Triple::x86_64:
{ {

View File

@ -11,6 +11,7 @@ add_lldb_library(lldbPluginProcessPOSIX
ProcessMessage.cpp ProcessMessage.cpp
ProcessPOSIX.cpp ProcessPOSIX.cpp
ProcessPOSIXLog.cpp ProcessPOSIXLog.cpp
RegisterContextPOSIXProcessMonitor_arm.cpp
RegisterContextPOSIXProcessMonitor_arm64.cpp RegisterContextPOSIXProcessMonitor_arm64.cpp
RegisterContextPOSIXProcessMonitor_mips64.cpp RegisterContextPOSIXProcessMonitor_mips64.cpp
RegisterContextPOSIXProcessMonitor_powerpc.cpp RegisterContextPOSIXProcessMonitor_powerpc.cpp

View File

@ -32,10 +32,12 @@
#include "ProcessPOSIX.h" #include "ProcessPOSIX.h"
#include "ProcessPOSIXLog.h" #include "ProcessPOSIXLog.h"
#include "Plugins/Process/Linux/ProcessMonitor.h" #include "Plugins/Process/Linux/ProcessMonitor.h"
#include "RegisterContextPOSIXProcessMonitor_arm.h"
#include "RegisterContextPOSIXProcessMonitor_arm64.h" #include "RegisterContextPOSIXProcessMonitor_arm64.h"
#include "RegisterContextPOSIXProcessMonitor_mips64.h" #include "RegisterContextPOSIXProcessMonitor_mips64.h"
#include "RegisterContextPOSIXProcessMonitor_powerpc.h" #include "RegisterContextPOSIXProcessMonitor_powerpc.h"
#include "RegisterContextPOSIXProcessMonitor_x86.h" #include "RegisterContextPOSIXProcessMonitor_x86.h"
#include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
#include "Plugins/Process/Utility/RegisterContextLinux_i386.h" #include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
@ -198,6 +200,10 @@ POSIXThread::GetRegisterContext()
assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); 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)); reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm64(target_arch));
break; break;
case llvm::Triple::arm:
assert(HostInfo::GetArchitecture().GetAddressByteSize() == 4);
reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm(target_arch));
break;
case llvm::Triple::x86: case llvm::Triple::x86:
case llvm::Triple::x86_64: case llvm::Triple::x86_64:
if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) if (HostInfo::GetArchitecture().GetAddressByteSize() == 4)
@ -232,6 +238,13 @@ POSIXThread::GetRegisterContext()
m_reg_context_sp.reset(reg_ctx); m_reg_context_sp.reset(reg_ctx);
break; break;
} }
case llvm::Triple::arm:
{
RegisterContextPOSIXProcessMonitor_arm *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm(*this, 0, reg_interface);
m_posix_thread = reg_ctx;
m_reg_context_sp.reset(reg_ctx);
break;
}
case llvm::Triple::mips64: case llvm::Triple::mips64:
{ {
RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface); RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface);
@ -644,6 +657,7 @@ POSIXThread::GetRegisterIndexFromOffset(unsigned offset)
break; break;
case llvm::Triple::aarch64: case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::mips64: case llvm::Triple::mips64:
case llvm::Triple::ppc: case llvm::Triple::ppc:
case llvm::Triple::ppc64: case llvm::Triple::ppc64:
@ -677,6 +691,7 @@ POSIXThread::GetRegisterName(unsigned reg)
break; break;
case llvm::Triple::aarch64: case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::mips64: case llvm::Triple::mips64:
case llvm::Triple::ppc: case llvm::Triple::ppc:
case llvm::Triple::ppc64: case llvm::Triple::ppc64:

View File

@ -14,6 +14,7 @@
// C++ Includes // C++ Includes
// Other libraries and framework includes // Other libraries and framework includes
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/Module.h" #include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ModuleSpec.h"
@ -638,6 +639,33 @@ ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
assert(false && "CPU type not supported!"); assert(false && "CPU type not supported!");
break; break;
case llvm::Triple::arm:
{
// The ARM reference recommends the use of 0xe7fddefe and 0xdefe
// but the linux kernel does otherwise.
static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 };
static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde };
lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0));
AddressClass addr_class = eAddressClassUnknown;
if (bp_loc_sp)
addr_class = bp_loc_sp->GetAddress ().GetAddressClass ();
if (addr_class == eAddressClassCodeAlternateISA
|| (addr_class == eAddressClassUnknown
&& bp_loc_sp->GetAddress().GetOffset() & 1))
{
opcode = g_thumb_breakpoint_opcode;
opcode_size = sizeof(g_thumb_breakpoint_opcode);
}
else
{
opcode = g_arm_breakpoint_opcode;
opcode_size = sizeof(g_arm_breakpoint_opcode);
}
}
break;
case llvm::Triple::aarch64: case llvm::Triple::aarch64:
opcode = g_aarch64_opcode; opcode = g_aarch64_opcode;
opcode_size = sizeof(g_aarch64_opcode); opcode_size = sizeof(g_aarch64_opcode);

View File

@ -0,0 +1,322 @@
//===-- RegisterContextPOSIXProcessMonitor_arm.cpp -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===---------------------------------------------------------------------===//
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
#include "RegisterContextPOSIX_arm.h"
#include "ProcessPOSIX.h"
#include "RegisterContextPOSIXProcessMonitor_arm.h"
#include "ProcessMonitor.h"
using namespace lldb_private;
using namespace lldb;
#define REG_CONTEXT_SIZE (GetGPRSize())
RegisterContextPOSIXProcessMonitor_arm::RegisterContextPOSIXProcessMonitor_arm(Thread &thread,
uint32_t concrete_frame_idx,
lldb_private::RegisterInfoInterface *register_info)
: RegisterContextPOSIX_arm(thread, concrete_frame_idx, register_info)
{
}
ProcessMonitor &
RegisterContextPOSIXProcessMonitor_arm::GetMonitor()
{
ProcessSP base = CalculateProcess();
ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
return process->GetMonitor();
}
bool
RegisterContextPOSIXProcessMonitor_arm::ReadGPR()
{
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize());
}
bool
RegisterContextPOSIXProcessMonitor_arm::ReadFPR()
{
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr));
}
bool
RegisterContextPOSIXProcessMonitor_arm::WriteGPR()
{
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize());
}
bool
RegisterContextPOSIXProcessMonitor_arm::WriteFPR()
{
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr));
}
bool
RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const unsigned reg,
RegisterValue &value)
{
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadRegisterValue(m_thread.GetID(),
GetRegisterOffset(reg),
GetRegisterName(reg),
GetRegisterSize(reg),
value);
}
bool
RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const unsigned reg,
const RegisterValue &value)
{
unsigned reg_to_write = reg;
RegisterValue value_to_write = value;
// Check if this is a subregister of a full register.
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
{
RegisterValue full_value;
uint32_t full_reg = reg_info->invalidate_regs[0];
const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
// Read the full register.
if (ReadRegister(full_reg_info, full_value))
{
Error error;
ByteOrder byte_order = GetByteOrder();
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the full register.
const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
dst,
sizeof(dst),
byte_order,
error);
if (error.Success() && dest_size)
{
uint8_t src[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the source data.
const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
if (error.Success() && src_size && (src_size < dest_size))
{
// Copy the src bytes to the destination.
memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
// Set this full register as the value to write.
value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
value_to_write.SetType(full_reg_info);
reg_to_write = full_reg;
}
}
}
}
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteRegisterValue(m_thread.GetID(),
GetRegisterOffset(reg_to_write),
GetRegisterName(reg_to_write),
value_to_write);
}
bool
RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
{
if (!reg_info)
return false;
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
if (IsFPR(reg))
{
if (!ReadFPR())
return false;
}
else
{
return ReadRegister(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_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
{
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
if (IsGPR(reg))
{
return WriteRegister(reg, value);
}
else if (IsFPR(reg))
{
return WriteFPR();
}
return false;
}
bool
RegisterContextPOSIXProcessMonitor_arm::ReadAllRegisterValues(DataBufferSP &data_sp)
{
bool success = false;
data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
if (data_sp && ReadGPR () && ReadFPR ())
{
uint8_t *dst = data_sp->GetBytes();
success = dst != 0;
if (success)
{
::memcpy (dst, &m_gpr_arm, GetGPRSize());
dst += GetGPRSize();
::memcpy (dst, &m_fpr, sizeof(m_fpr));
}
}
return success;
}
bool
RegisterContextPOSIXProcessMonitor_arm::WriteAllRegisterValues(const DataBufferSP &data_sp)
{
bool success = false;
if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
{
uint8_t *src = data_sp->GetBytes();
if (src)
{
::memcpy (&m_gpr_arm, src, GetGPRSize());
if (WriteGPR())
{
src += GetGPRSize();
::memcpy (&m_fpr, src, sizeof(m_fpr));
success = WriteFPR();
}
}
}
return success;
}
uint32_t
RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpoint(addr_t addr, size_t size,
bool read, bool write)
{
const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
uint32_t hw_index;
for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
{
if (IsWatchpointVacant(hw_index))
return SetHardwareWatchpointWithIndex(addr, size,
read, write,
hw_index);
}
return LLDB_INVALID_INDEX32;
}
bool
RegisterContextPOSIXProcessMonitor_arm::ClearHardwareWatchpoint(uint32_t hw_index)
{
return false;
}
bool
RegisterContextPOSIXProcessMonitor_arm::HardwareSingleStep(bool enable)
{
return false;
}
bool
RegisterContextPOSIXProcessMonitor_arm::UpdateAfterBreakpoint()
{
lldb::addr_t pc;
if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
return false;
return true;
}
unsigned
RegisterContextPOSIXProcessMonitor_arm::GetRegisterIndexFromOffset(unsigned offset)
{
unsigned reg;
for (reg = 0; reg < k_num_registers_arm; reg++)
{
if (GetRegisterInfo()[reg].byte_offset == offset)
break;
}
assert(reg < k_num_registers_arm && "Invalid register offset.");
return reg;
}
bool
RegisterContextPOSIXProcessMonitor_arm::IsWatchpointHit(uint32_t hw_index)
{
return false;
}
bool
RegisterContextPOSIXProcessMonitor_arm::ClearWatchpointHits()
{
return false;
}
addr_t
RegisterContextPOSIXProcessMonitor_arm::GetWatchpointAddress(uint32_t hw_index)
{
return LLDB_INVALID_ADDRESS;
}
bool
RegisterContextPOSIXProcessMonitor_arm::IsWatchpointVacant(uint32_t hw_index)
{
return false;
}
bool
RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
bool read, bool write,
uint32_t hw_index)
{
return false;
}
uint32_t
RegisterContextPOSIXProcessMonitor_arm::NumSupportedHardwareWatchpoints()
{
return 0;
}

View File

@ -0,0 +1,95 @@
//===-- RegisterContextPOSIXProcessMonitor_arm.h --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm_H_
#define liblldb_RegisterContextPOSIXProcessMonitor_arm_H_
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
class RegisterContextPOSIXProcessMonitor_arm:
public RegisterContextPOSIX_arm,
public POSIXBreakpointProtocol
{
public:
RegisterContextPOSIXProcessMonitor_arm(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

View File

@ -21,6 +21,7 @@ add_lldb_library(lldbPluginProcessUtility
RegisterContextFreeBSD_powerpc.cpp RegisterContextFreeBSD_powerpc.cpp
RegisterContextFreeBSD_x86_64.cpp RegisterContextFreeBSD_x86_64.cpp
RegisterContextHistory.cpp RegisterContextHistory.cpp
RegisterContextLinux_arm.cpp
RegisterContextLinux_arm64.cpp RegisterContextLinux_arm64.cpp
RegisterContextLinux_i386.cpp RegisterContextLinux_i386.cpp
RegisterContextLinux_x86_64.cpp RegisterContextLinux_x86_64.cpp
@ -31,6 +32,7 @@ add_lldb_library(lldbPluginProcessUtility
RegisterContextMach_i386.cpp RegisterContextMach_i386.cpp
RegisterContextMach_x86_64.cpp RegisterContextMach_x86_64.cpp
RegisterContextMemory.cpp RegisterContextMemory.cpp
RegisterContextPOSIX_arm.cpp
RegisterContextPOSIX_arm64.cpp RegisterContextPOSIX_arm64.cpp
RegisterContextPOSIX_mips64.cpp RegisterContextPOSIX_mips64.cpp
RegisterContextPOSIX_powerpc.cpp RegisterContextPOSIX_powerpc.cpp

View File

@ -0,0 +1,87 @@
//===-- RegisterContextLinux_arm.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_arm.h"
using namespace lldb;
using namespace lldb_private;
// Based on RegisterContextDarwin_arm.cpp
#define GPR_OFFSET(idx) ((idx) * 4)
#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR))
#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU))
#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextLinux_arm::DBG, reg) + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC)))
#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(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 (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC))
//-----------------------------------------------------------------------------
// Include RegisterInfos_arm to declare our g_register_infos_arm structure.
//-----------------------------------------------------------------------------
#define DECLARE_REGISTER_INFOS_ARM_STRUCT
#include "RegisterInfos_arm.h"
#undef DECLARE_REGISTER_INFOS_ARM_STRUCT
static const lldb_private::RegisterInfo *
GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch)
{
switch (target_arch.GetMachine())
{
case llvm::Triple::arm:
return g_register_infos_arm;
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::arm:
return static_cast<uint32_t>(sizeof(g_register_infos_arm) / sizeof(g_register_infos_arm[0]));
default:
assert(false && "Unhandled target architecture.");
return 0;
}
}
RegisterContextLinux_arm::RegisterContextLinux_arm(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_arm::GetGPRSize() const
{
return sizeof(struct RegisterContextLinux_arm::GPR);
}
const lldb_private::RegisterInfo *
RegisterContextLinux_arm::GetRegisterInfo() const
{
return m_register_info_p;
}
uint32_t
RegisterContextLinux_arm::GetRegisterCount() const
{
return m_register_info_count;
}

View File

@ -0,0 +1,76 @@
//===-- RegisterContextLinux_arm.h -----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_RegisterContextLinux_arm_h_
#define liblldb_RegisterContextLinux_arm_h_
#include "lldb/lldb-private.h"
#include "lldb/Target/RegisterContext.h"
#include "RegisterContextPOSIX.h"
#include "RegisterInfoInterface.h"
class RegisterContextLinux_arm
: public lldb_private::RegisterInfoInterface
{
public:
struct GPR
{
uint32_t r[16]; // R0-R15
uint32_t cpsr; // CPSR
};
struct QReg
{
uint8_t bytes[16];
};
struct FPU
{
union {
uint32_t s[32];
uint64_t d[32];
QReg q[16]; // the 128-bit NEON registers
} floats;
uint32_t fpscr;
};
struct EXC
{
uint32_t exception;
uint32_t fsr; /* Fault status */
uint32_t far; /* Virtual Fault Address */
};
struct DBG
{
uint32_t bvr[16];
uint32_t bcr[16];
uint32_t wvr[16];
uint32_t wcr[16];
};
RegisterContextLinux_arm(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 // liblldb_RegisterContextLinux_arm_h_

View File

@ -0,0 +1,287 @@
//===-- RegisterContextPOSIX_arm.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_arm.h"
#include "Plugins/Process/elf-core/ProcessElfCore.h"
using namespace lldb;
using namespace lldb_private;
// arm general purpose registers.
const uint32_t g_gpr_regnums_arm[] =
{
gpr_r0_arm,
gpr_r1_arm,
gpr_r2_arm,
gpr_r3_arm,
gpr_r4_arm,
gpr_r5_arm,
gpr_r6_arm,
gpr_r7_arm,
gpr_r8_arm,
gpr_r9_arm,
gpr_r10_arm,
gpr_r11_arm,
gpr_r12_arm,
gpr_sp_arm,
gpr_lr_arm,
gpr_pc_arm,
gpr_cpsr_arm,
LLDB_INVALID_REGNUM // register sets need to end with this flag
};
static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == k_num_gpr_registers_arm, \
"g_gpr_regnums_arm has wrong number of register infos");
// arm floating point registers.
static const uint32_t g_fpu_regnums_arm[] =
{
fpu_s0_arm,
fpu_s1_arm,
fpu_s2_arm,
fpu_s3_arm,
fpu_s4_arm,
fpu_s5_arm,
fpu_s6_arm,
fpu_s7_arm,
fpu_s8_arm,
fpu_s9_arm,
fpu_s10_arm,
fpu_s11_arm,
fpu_s12_arm,
fpu_s13_arm,
fpu_s14_arm,
fpu_s15_arm,
fpu_s16_arm,
fpu_s17_arm,
fpu_s18_arm,
fpu_s19_arm,
fpu_s20_arm,
fpu_s21_arm,
fpu_s22_arm,
fpu_s23_arm,
fpu_s24_arm,
fpu_s25_arm,
fpu_s26_arm,
fpu_s27_arm,
fpu_s28_arm,
fpu_s29_arm,
fpu_s30_arm,
fpu_s31_arm,
fpu_fpscr_arm,
LLDB_INVALID_REGNUM // register sets need to end with this flag
};
static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \
"g_fpu_regnums_arm has wrong number of register infos");
// Number of register sets provided by this context.
enum
{
k_num_register_sets = 2
};
// Register sets for arm.
static const lldb_private::RegisterSet
g_reg_sets_arm[k_num_register_sets] =
{
{ "General Purpose Registers", "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm },
{ "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm }
};
bool RegisterContextPOSIX_arm::IsGPR(unsigned reg)
{
return reg <= m_reg_info.last_gpr; // GPR's come first.
}
bool RegisterContextPOSIX_arm::IsFPR(unsigned reg)
{
return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
}
RegisterContextPOSIX_arm::RegisterContextPOSIX_arm(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::arm:
m_reg_info.num_registers = k_num_registers_arm;
m_reg_info.num_gpr_registers = k_num_gpr_registers_arm;
m_reg_info.num_fpr_registers = k_num_fpr_registers_arm;
m_reg_info.last_gpr = k_last_gpr_arm;
m_reg_info.first_fpr = k_first_fpr_arm;
m_reg_info.last_fpr = k_last_fpr_arm;
m_reg_info.first_fpr_v = fpu_s0_arm;
m_reg_info.last_fpr_v = fpu_s31_arm;
m_reg_info.gpr_flags = gpr_cpsr_arm;
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_arm::~RegisterContextPOSIX_arm()
{
}
void
RegisterContextPOSIX_arm::Invalidate()
{
}
void
RegisterContextPOSIX_arm::InvalidateAllRegisters()
{
}
unsigned
RegisterContextPOSIX_arm::GetRegisterOffset(unsigned reg)
{
assert(reg < m_reg_info.num_registers && "Invalid register number.");
return GetRegisterInfo()[reg].byte_offset;
}
unsigned
RegisterContextPOSIX_arm::GetRegisterSize(unsigned reg)
{
assert(reg < m_reg_info.num_registers && "Invalid register number.");
return GetRegisterInfo()[reg].byte_size;
}
size_t
RegisterContextPOSIX_arm::GetRegisterCount()
{
size_t num_registers = m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers;
return num_registers;
}
size_t
RegisterContextPOSIX_arm::GetGPRSize()
{
return m_register_info_ap->GetGPRSize ();
}
const lldb_private::RegisterInfo *
RegisterContextPOSIX_arm::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_arm::GetRegisterInfoAtIndex(size_t reg)
{
if (reg < m_reg_info.num_registers)
return &GetRegisterInfo()[reg];
else
return NULL;
}
size_t
RegisterContextPOSIX_arm::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_arm::GetRegisterSet(size_t set)
{
if (IsRegisterSetAvailable(set))
{
switch (m_register_info_ap->m_target_arch.GetMachine())
{
case llvm::Triple::aarch64:
return &g_reg_sets_arm[set];
default:
assert(false && "Unhandled target architecture.");
return NULL;
}
}
return NULL;
}
const char *
RegisterContextPOSIX_arm::GetRegisterName(unsigned reg)
{
assert(reg < m_reg_info.num_registers && "Invalid register offset.");
return GetRegisterInfo()[reg].name;
}
lldb::ByteOrder
RegisterContextPOSIX_arm::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_arm::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_arm::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;
}

View File

@ -0,0 +1,121 @@
//===-- RegisterContextPOSIX_arm.h ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_RegisterContextPOSIX_arm_H_
#define liblldb_RegisterContextPOSIX_arm_H_
#include "lldb/Core/Log.h"
#include "lldb-arm-register-enums.h"
#include "RegisterContextPOSIX.h"
class ProcessMonitor;
class RegisterContextPOSIX_arm
: public lldb_private::RegisterContext
{
public:
RegisterContextPOSIX_arm (lldb_private::Thread &thread,
uint32_t concrete_frame_idx,
lldb_private::RegisterInfoInterface *register_info);
~RegisterContextPOSIX_arm();
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;
};
struct QReg
{
uint8_t bytes[16];
};
struct FPU
{
union {
uint32_t s[32];
uint64_t d[32];
QReg q[16]; // the 128-bit NEON registers
} floats;
uint32_t fpscr;
};
uint32_t m_gpr_arm[lldb_private::k_num_gpr_registers_arm]; // 32-bit general purpose registers.
RegInfo m_reg_info;
struct RegisterContextPOSIX_arm::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_arm_H_

View File

@ -0,0 +1,303 @@
//===-- RegisterInfos_arm.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_ARM_STRUCT
#include <stddef.h>
#include "lldb/lldb-private.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-enumerations.h"
#include "Utility/ARM_GCC_Registers.h"
#include "Utility/ARM_DWARF_Registers.h"
using namespace lldb;
using namespace lldb_private;
#ifndef GPR_OFFSET
#error GPR_OFFSET 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 EXC_OFFSET
#error EXC_OFFSET_NAME must be defined before including this header file
#endif
#ifndef DBG_OFFSET
#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_r0 = 0,
gpr_r1,
gpr_r2,
gpr_r3,
gpr_r4,
gpr_r5,
gpr_r6,
gpr_r7,
gpr_r8,
gpr_r9,
gpr_r10,
gpr_r11,
gpr_r12,
gpr_r13, gpr_sp = gpr_r13,
gpr_r14, gpr_lr = gpr_r14,
gpr_r15, gpr_pc = gpr_r15,
gpr_cpsr,
fpu_s0,
fpu_s1,
fpu_s2,
fpu_s3,
fpu_s4,
fpu_s5,
fpu_s6,
fpu_s7,
fpu_s8,
fpu_s9,
fpu_s10,
fpu_s11,
fpu_s12,
fpu_s13,
fpu_s14,
fpu_s15,
fpu_s16,
fpu_s17,
fpu_s18,
fpu_s19,
fpu_s20,
fpu_s21,
fpu_s22,
fpu_s23,
fpu_s24,
fpu_s25,
fpu_s26,
fpu_s27,
fpu_s28,
fpu_s29,
fpu_s30,
fpu_s31,
fpu_fpscr,
exc_exception,
exc_fsr,
exc_far,
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 RegisterInfo g_register_infos_arm[] = {
// General purpose registers
// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== ===============
{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1, gdb_arm_r0, gpr_r0 }, NULL, NULL},
{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2, gdb_arm_r1, gpr_r1 }, NULL, NULL},
{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3, gdb_arm_r2, gpr_r2 }, NULL, NULL},
{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4, gdb_arm_r3, gpr_r3 }, NULL, NULL},
{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, gpr_r4 }, NULL, NULL},
{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, gpr_r5 }, NULL, NULL},
{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, gpr_r6 }, NULL, NULL},
{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_INVALID_REGNUM, gdb_arm_r7, gpr_r7 }, NULL, NULL},
{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, gpr_r8 }, NULL, NULL},
{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, gpr_r9 }, NULL, NULL},
{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, gpr_r10 }, NULL, NULL},
{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, gdb_arm_r11, gpr_r11 }, NULL, NULL},
{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, gpr_r12 }, NULL, NULL},
{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, gpr_sp }, NULL, NULL},
{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, gpr_lr }, NULL, NULL},
{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, gpr_pc }, NULL, NULL},
{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, gpr_cpsr }, NULL, NULL},
{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, fpu_s0 }, NULL, NULL},
{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, fpu_s1 }, NULL, NULL},
{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, fpu_s2 }, NULL, NULL},
{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, fpu_s3 }, NULL, NULL},
{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, fpu_s4 }, NULL, NULL},
{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, fpu_s5 }, NULL, NULL},
{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, fpu_s6 }, NULL, NULL},
{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, fpu_s7 }, NULL, NULL},
{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, fpu_s8 }, NULL, NULL},
{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, fpu_s9 }, NULL, NULL},
{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, fpu_s10 }, NULL, NULL},
{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, fpu_s11 }, NULL, NULL},
{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, fpu_s12 }, NULL, NULL},
{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, fpu_s13 }, NULL, NULL},
{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, fpu_s14 }, NULL, NULL},
{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, fpu_s15 }, NULL, NULL},
{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, fpu_s16 }, NULL, NULL},
{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, fpu_s17 }, NULL, NULL},
{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, fpu_s18 }, NULL, NULL},
{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, fpu_s19 }, NULL, NULL},
{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, fpu_s20 }, NULL, NULL},
{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, fpu_s21 }, NULL, NULL},
{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, fpu_s22 }, NULL, NULL},
{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, fpu_s23 }, NULL, NULL},
{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, fpu_s24 }, NULL, NULL},
{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, fpu_s25 }, NULL, NULL},
{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, fpu_s26 }, NULL, NULL},
{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, fpu_s27 }, NULL, NULL},
{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, fpu_s28 }, NULL, NULL},
{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, fpu_s29 }, NULL, NULL},
{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, fpu_s30 }, NULL, NULL},
{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, fpu_s31 }, NULL, NULL},
{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, fpu_fpscr }, NULL, NULL},
{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL},
{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, NULL, NULL},
{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, 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_ARM_STRUCT

View File

@ -0,0 +1,153 @@
//===-- lldb-arm-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_arm_register_enums_h
#define lldb_arm_register_enums_h
namespace lldb_private
{
// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
//---------------------------------------------------------------------------
// Internal codes for all ARM registers.
//---------------------------------------------------------------------------
enum
{
k_first_gpr_arm = 0,
gpr_r0_arm = k_first_gpr_arm,
gpr_r1_arm,
gpr_r2_arm,
gpr_r3_arm,
gpr_r4_arm,
gpr_r5_arm,
gpr_r6_arm,
gpr_r7_arm,
gpr_r8_arm,
gpr_r9_arm,
gpr_r10_arm,
gpr_r11_arm,
gpr_r12_arm,
gpr_r13_arm, gpr_sp_arm = gpr_r13_arm,
gpr_r14_arm, gpr_lr_arm = gpr_r14_arm,
gpr_r15_arm, gpr_pc_arm = gpr_r15_arm,
gpr_cpsr_arm,
k_last_gpr_arm = gpr_cpsr_arm,
k_first_fpr_arm,
fpu_s0_arm = k_first_fpr_arm,
fpu_s1_arm,
fpu_s2_arm,
fpu_s3_arm,
fpu_s4_arm,
fpu_s5_arm,
fpu_s6_arm,
fpu_s7_arm,
fpu_s8_arm,
fpu_s9_arm,
fpu_s10_arm,
fpu_s11_arm,
fpu_s12_arm,
fpu_s13_arm,
fpu_s14_arm,
fpu_s15_arm,
fpu_s16_arm,
fpu_s17_arm,
fpu_s18_arm,
fpu_s19_arm,
fpu_s20_arm,
fpu_s21_arm,
fpu_s22_arm,
fpu_s23_arm,
fpu_s24_arm,
fpu_s25_arm,
fpu_s26_arm,
fpu_s27_arm,
fpu_s28_arm,
fpu_s29_arm,
fpu_s30_arm,
fpu_s31_arm,
fpu_fpscr_arm,
k_last_fpr_arm = fpu_fpscr_arm,
exc_exception_arm,
exc_fsr_arm,
exc_far_arm,
dbg_bvr0_arm,
dbg_bvr1_arm,
dbg_bvr2_arm,
dbg_bvr3_arm,
dbg_bvr4_arm,
dbg_bvr5_arm,
dbg_bvr6_arm,
dbg_bvr7_arm,
dbg_bvr8_arm,
dbg_bvr9_arm,
dbg_bvr10_arm,
dbg_bvr11_arm,
dbg_bvr12_arm,
dbg_bvr13_arm,
dbg_bvr14_arm,
dbg_bvr15_arm,
dbg_bcr0_arm,
dbg_bcr1_arm,
dbg_bcr2_arm,
dbg_bcr3_arm,
dbg_bcr4_arm,
dbg_bcr5_arm,
dbg_bcr6_arm,
dbg_bcr7_arm,
dbg_bcr8_arm,
dbg_bcr9_arm,
dbg_bcr10_arm,
dbg_bcr11_arm,
dbg_bcr12_arm,
dbg_bcr13_arm,
dbg_bcr14_arm,
dbg_bcr15_arm,
dbg_wvr0_arm,
dbg_wvr1_arm,
dbg_wvr2_arm,
dbg_wvr3_arm,
dbg_wvr4_arm,
dbg_wvr5_arm,
dbg_wvr6_arm,
dbg_wvr7_arm,
dbg_wvr8_arm,
dbg_wvr9_arm,
dbg_wvr10_arm,
dbg_wvr11_arm,
dbg_wvr12_arm,
dbg_wvr13_arm,
dbg_wvr14_arm,
dbg_wvr15_arm,
dbg_wcr0_arm,
dbg_wcr1_arm,
dbg_wcr2_arm,
dbg_wcr3_arm,
dbg_wcr4_arm,
dbg_wcr5_arm,
dbg_wcr6_arm,
dbg_wcr7_arm,
dbg_wcr8_arm,
dbg_wcr9_arm,
dbg_wcr10_arm,
dbg_wcr11_arm,
dbg_wcr12_arm,
dbg_wcr13_arm,
dbg_wcr14_arm,
dbg_wcr15_arm,
k_num_registers_arm,
k_num_gpr_registers_arm = k_last_gpr_arm - k_first_gpr_arm + 1,
k_num_fpr_registers_arm = k_last_fpr_arm - k_first_fpr_arm + 1
};
}
#endif // #ifndef lldb_arm64_register_enums_h

View File

@ -5,6 +5,7 @@ set(LLVM_NO_RTTI 1)
add_lldb_library(lldbPluginProcessElfCore add_lldb_library(lldbPluginProcessElfCore
ProcessElfCore.cpp ProcessElfCore.cpp
ThreadElfCore.cpp ThreadElfCore.cpp
RegisterContextPOSIXCore_arm.cpp
RegisterContextPOSIXCore_arm64.cpp RegisterContextPOSIXCore_arm64.cpp
RegisterContextPOSIXCore_mips64.cpp RegisterContextPOSIXCore_mips64.cpp
RegisterContextPOSIXCore_powerpc.cpp RegisterContextPOSIXCore_powerpc.cpp

View File

@ -0,0 +1,94 @@
//===-- RegisterContextCorePOSIX_arm.cpp ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX.h"
#include "RegisterContextPOSIXCore_arm.h"
using namespace lldb_private;
RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm(Thread &thread,
RegisterInfoInterface *register_info,
const DataExtractor &gpregset,
const DataExtractor &fpregset)
: RegisterContextPOSIX_arm(thread, 0, register_info)
{
m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize()));
m_gpr.SetData(m_gpr_buffer);
m_gpr.SetByteOrder(gpregset.GetByteOrder());
}
RegisterContextCorePOSIX_arm::~RegisterContextCorePOSIX_arm()
{
}
bool
RegisterContextCorePOSIX_arm::ReadGPR()
{
return true;
}
bool
RegisterContextCorePOSIX_arm::ReadFPR()
{
return false;
}
bool
RegisterContextCorePOSIX_arm::WriteGPR()
{
assert(0);
return false;
}
bool
RegisterContextCorePOSIX_arm::WriteFPR()
{
assert(0);
return false;
}
bool
RegisterContextCorePOSIX_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
{
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
RegisterContextCorePOSIX_arm::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
{
return false;
}
bool
RegisterContextCorePOSIX_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
{
return false;
}
bool
RegisterContextCorePOSIX_arm::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
{
return false;
}
bool
RegisterContextCorePOSIX_arm::HardwareSingleStep(bool enable)
{
return false;
}

View File

@ -0,0 +1,60 @@
//===-- RegisterContextCorePOSIX_arm.h -----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===---------------------------------------------------------------------===//
#ifndef liblldb_RegisterContextCorePOSIX_arm_H_
#define liblldb_RegisterContextCorePOSIX_arm_H_
#include "lldb/Core/DataBufferHeap.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
class RegisterContextCorePOSIX_arm :
public RegisterContextPOSIX_arm
{
public:
RegisterContextCorePOSIX_arm (lldb_private::Thread &thread,
lldb_private::RegisterInfoInterface *register_info,
const lldb_private::DataExtractor &gpregset,
const lldb_private::DataExtractor &fpregset);
~RegisterContextCorePOSIX_arm();
virtual bool
ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
virtual bool
WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
bool
ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
bool
WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
bool
HardwareSingleStep(bool enable);
protected:
bool
ReadGPR();
bool
ReadFPR();
bool
WriteGPR();
bool
WriteFPR();
private:
lldb::DataBufferSP m_gpr_buffer;
lldb_private::DataExtractor m_gpr;
};
#endif // #ifndef liblldb_RegisterContextCorePOSIX_arm_H_

View File

@ -16,12 +16,14 @@
#include "ThreadElfCore.h" #include "ThreadElfCore.h"
#include "ProcessElfCore.h" #include "ProcessElfCore.h"
#include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
#include "RegisterContextPOSIXCore_arm.h"
#include "RegisterContextPOSIXCore_arm64.h" #include "RegisterContextPOSIXCore_arm64.h"
#include "RegisterContextPOSIXCore_mips64.h" #include "RegisterContextPOSIXCore_mips64.h"
#include "RegisterContextPOSIXCore_powerpc.h" #include "RegisterContextPOSIXCore_powerpc.h"
@ -127,6 +129,9 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
{ {
switch (arch.GetMachine()) switch (arch.GetMachine())
{ {
case llvm::Triple::arm:
reg_interface = new RegisterContextLinux_arm(arch);
break;
case llvm::Triple::x86_64: case llvm::Triple::x86_64:
reg_interface = new RegisterContextLinux_x86_64(arch); reg_interface = new RegisterContextLinux_x86_64(arch);
break; break;
@ -152,6 +157,9 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
case llvm::Triple::aarch64: case llvm::Triple::aarch64:
m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm64 (*this, reg_interface, m_gpregset_data, m_fpregset_data));
break; break;
case llvm::Triple::arm:
m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm (*this, reg_interface, m_gpregset_data, m_fpregset_data));
break;
case llvm::Triple::mips64: case llvm::Triple::mips64:
m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data));
break; break;