summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Process
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process')
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp557
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h53
-rw-r--r--lldb/source/Plugins/Process/Utility/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp11
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h11
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp117
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h42
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp2
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h14
-rw-r--r--lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp46
-rw-r--r--lldb/source/Plugins/Process/elf-core/ProcessElfCore.h14
-rw-r--r--lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp27
-rw-r--r--lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h1
-rw-r--r--lldb/source/Plugins/Process/elf-core/RegisterUtilities.h5
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp2
-rw-r--r--lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp17
-rw-r--r--lldb/source/Plugins/Process/scripted/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp191
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedFrame.h63
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedThread.cpp82
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedThread.h5
21 files changed, 671 insertions, 591 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
index fdafacf410d6..c1bc6a3f036b 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
@@ -76,7 +76,7 @@ NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
::memset(&m_fpr, 0, sizeof(m_fpr));
::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm));
::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
- ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs));
+ ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
// 16 is just a maximum value, query hardware for actual watchpoint count
m_max_hwp_supported = 16;
@@ -283,522 +283,43 @@ bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const {
return false;
}
-uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
- Log *log = GetLog(POSIXLog::Breakpoints);
-
- LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
- Status error;
-
- // Read hardware breakpoint and watchpoint information.
- error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return 0;
-
- LLDB_LOG(log, "{0}", m_max_hbp_supported);
- return m_max_hbp_supported;
-}
-
-uint32_t
-NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
- size_t size) {
- Log *log = GetLog(POSIXLog::Breakpoints);
- LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return LLDB_INVALID_INDEX32;
-
- uint32_t control_value = 0, bp_index = 0;
-
- // Setup address and control values.
- // Use size to get a hint of arm vs thumb modes.
- switch (size) {
- case 2:
- control_value = (0x3 << 5) | 7;
- addr &= ~1;
- break;
- case 4:
- control_value = (0xfu << 5) | 7;
- addr &= ~3;
- break;
- default:
- return LLDB_INVALID_INDEX32;
- }
-
- // Iterate over stored breakpoints and find a free bp_index
- bp_index = LLDB_INVALID_INDEX32;
- for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
- if ((m_hbr_regs[i].control & 1) == 0) {
- bp_index = i; // Mark last free slot
- } else if (m_hbr_regs[i].address == addr) {
- return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
- }
- }
-
- if (bp_index == LLDB_INVALID_INDEX32)
- return LLDB_INVALID_INDEX32;
-
- // Update breakpoint in local cache
- m_hbr_regs[bp_index].real_addr = addr;
- m_hbr_regs[bp_index].address = addr;
- m_hbr_regs[bp_index].control = control_value;
-
- // PTRACE call to set corresponding hardware breakpoint register.
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK,
- bp_index);
-
- if (error.Fail()) {
- m_hbr_regs[bp_index].address = 0;
- m_hbr_regs[bp_index].control &= ~1;
-
- return LLDB_INVALID_INDEX32;
- }
-
- return bp_index;
-}
-
-bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
- Log *log = GetLog(POSIXLog::Breakpoints);
- LLDB_LOG(log, "hw_idx: {0}", hw_idx);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return false;
-
- if (hw_idx >= m_max_hbp_supported)
- return false;
-
- // Create a backup we can revert to in case of failure.
- lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
- uint32_t tempControl = m_hbr_regs[hw_idx].control;
-
- m_hbr_regs[hw_idx].control &= ~1;
- m_hbr_regs[hw_idx].address = 0;
-
- // PTRACE call to clear corresponding hardware breakpoint register.
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK,
- hw_idx);
-
- if (error.Fail()) {
- m_hbr_regs[hw_idx].control = tempControl;
- m_hbr_regs[hw_idx].address = tempAddr;
-
- return false;
- }
-
- return true;
-}
-
-Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
- uint32_t &bp_index, lldb::addr_t trap_addr) {
- Log *log = GetLog(POSIXLog::Breakpoints);
-
- LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
- lldb::addr_t break_addr;
-
- for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
- break_addr = m_hbr_regs[bp_index].address;
-
- if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
- m_hbr_regs[bp_index].hit_addr = trap_addr;
- return Status();
- }
- }
-
- bp_index = LLDB_INVALID_INDEX32;
- return Status();
-}
-
-Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
- Log *log = GetLog(POSIXLog::Breakpoints);
-
- LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
- Status error;
-
- // Read hardware breakpoint and watchpoint information.
- error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return error;
-
- lldb::addr_t tempAddr = 0;
- uint32_t tempControl = 0;
-
- for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
- if (m_hbr_regs[i].control & 0x01) {
- // Create a backup we can revert to in case of failure.
- tempAddr = m_hbr_regs[i].address;
- tempControl = m_hbr_regs[i].control;
-
- // Clear breakpoints in local cache
- m_hbr_regs[i].control &= ~1;
- m_hbr_regs[i].address = 0;
-
- // Ptrace call to update hardware debug registers
- error =
- WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK, i);
-
- if (error.Fail()) {
- m_hbr_regs[i].control = tempControl;
- m_hbr_regs[i].address = tempAddr;
-
- return error;
- }
- }
- }
-
- return Status();
-}
-
-uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
- Log *log = GetLog(POSIXLog::Watchpoints);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return 0;
-
- LLDB_LOG(log, "{0}", m_max_hwp_supported);
- return m_max_hwp_supported;
-}
-
-uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
- lldb::addr_t addr, size_t size, uint32_t watch_flags) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
- watch_flags);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return LLDB_INVALID_INDEX32;
-
- uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
- lldb::addr_t real_addr = addr;
-
- // Check if we are setting watchpoint other than read/write/access Also
- // update watchpoint flag to match Arm write-read bit configuration.
- switch (watch_flags) {
- case 1:
- watch_flags = 2;
- break;
- case 2:
- watch_flags = 1;
- break;
- case 3:
- break;
- default:
- return LLDB_INVALID_INDEX32;
- }
-
- // Can't watch zero bytes
- // Can't watch more than 4 bytes per WVR/WCR pair
-
- if (size == 0 || size > 4)
- return LLDB_INVALID_INDEX32;
-
- // Check 4-byte alignment for hardware watchpoint target address. Below is a
- // hack to recalculate address and size in order to make sure we can watch
- // non 4-byte aligned addresses as well.
- if (addr & 0x03) {
- uint8_t watch_mask = (addr & 0x03) + size;
-
- if (watch_mask > 0x04)
- return LLDB_INVALID_INDEX32;
- else if (watch_mask <= 0x02)
- size = 2;
- else
- size = 4;
-
- addr = addr & (~0x03);
- }
-
- // We can only watch up to four bytes that follow a 4 byte aligned address
- // per watchpoint register pair, so make sure we can properly encode this.
- addr_word_offset = addr % 4;
- byte_mask = ((1u << size) - 1u) << addr_word_offset;
-
- // Check if we need multiple watchpoint register
- if (byte_mask > 0xfu)
- return LLDB_INVALID_INDEX32;
-
- // Setup control value
- // Make the byte_mask into a valid Byte Address Select mask
- control_value = byte_mask << 5;
-
- // Turn on appropriate watchpoint flags read or write
- control_value |= (watch_flags << 3);
-
- // Enable this watchpoint and make it stop in privileged or user mode;
- control_value |= 7;
-
- // Make sure bits 1:0 are clear in our address
- addr &= ~((lldb::addr_t)3);
-
- // Iterate over stored watchpoints and find a free wp_index
- wp_index = LLDB_INVALID_INDEX32;
- for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
- if ((m_hwp_regs[i].control & 1) == 0) {
- wp_index = i; // Mark last free slot
- } else if (m_hwp_regs[i].address == addr) {
- return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
- }
- }
-
- if (wp_index == LLDB_INVALID_INDEX32)
- return LLDB_INVALID_INDEX32;
-
- // Update watchpoint in local cache
- m_hwp_regs[wp_index].real_addr = real_addr;
- m_hwp_regs[wp_index].address = addr;
- m_hwp_regs[wp_index].control = control_value;
-
- // PTRACE call to set corresponding watchpoint register.
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH,
- wp_index);
-
- if (error.Fail()) {
- m_hwp_regs[wp_index].address = 0;
- m_hwp_regs[wp_index].control &= ~1;
-
- return LLDB_INVALID_INDEX32;
- }
-
- return wp_index;
-}
-
-bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
- uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return false;
-
- if (wp_index >= m_max_hwp_supported)
- return false;
-
- // Create a backup we can revert to in case of failure.
- lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
- uint32_t tempControl = m_hwp_regs[wp_index].control;
-
- // Update watchpoint in local cache
- m_hwp_regs[wp_index].control &= ~1;
- m_hwp_regs[wp_index].address = 0;
-
- // Ptrace call to update hardware debug registers
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH,
- wp_index);
-
- if (error.Fail()) {
- m_hwp_regs[wp_index].control = tempControl;
- m_hwp_regs[wp_index].address = tempAddr;
-
- return false;
- }
-
- return true;
-}
-
-Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return error;
-
- lldb::addr_t tempAddr = 0;
- uint32_t tempControl = 0;
-
- for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
- if (m_hwp_regs[i].control & 0x01) {
- // Create a backup we can revert to in case of failure.
- tempAddr = m_hwp_regs[i].address;
- tempControl = m_hwp_regs[i].control;
-
- // Clear watchpoints in local cache
- m_hwp_regs[i].control &= ~1;
- m_hwp_regs[i].address = 0;
-
- // Ptrace call to update hardware debug registers
- error =
- WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH, i);
-
- if (error.Fail()) {
- m_hwp_regs[i].control = tempControl;
- m_hwp_regs[i].address = tempAddr;
-
- return error;
- }
- }
- }
-
- return Status();
-}
-
-uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
- case 0x01:
- return 1;
- case 0x03:
- return 2;
- case 0x07:
- return 3;
- case 0x0f:
- return 4;
- default:
- return 0;
- }
-}
-bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
- return true;
- else
- return false;
-}
-
-Status
-NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index,
- lldb::addr_t trap_addr) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
-
- uint32_t watch_size;
- lldb::addr_t watch_addr;
-
- for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
- watch_size = GetWatchpointSize(wp_index);
- watch_addr = m_hwp_regs[wp_index].address;
-
- if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
- trap_addr < watch_addr + watch_size) {
- m_hwp_regs[wp_index].hit_addr = trap_addr;
- return Status();
- }
- }
-
- wp_index = LLDB_INVALID_INDEX32;
- return Status();
-}
-
-lldb::addr_t
-NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- if (wp_index >= m_max_hwp_supported)
- return LLDB_INVALID_ADDRESS;
-
- if (WatchpointIsEnabled(wp_index))
- return m_hwp_regs[wp_index].real_addr;
- else
- return LLDB_INVALID_ADDRESS;
-}
-
-lldb::addr_t
-NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- if (wp_index >= m_max_hwp_supported)
- return LLDB_INVALID_ADDRESS;
-
- if (WatchpointIsEnabled(wp_index))
- return m_hwp_regs[wp_index].hit_addr;
- else
- return LLDB_INVALID_ADDRESS;
-}
-
-Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
- Status error;
-
- if (!m_refresh_hwdebug_info) {
- return Status();
- }
+llvm::Error NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
+ if (!m_refresh_hwdebug_info)
+ return llvm::Error::success();
#ifdef __arm__
unsigned int cap_val;
-
- error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(),
- nullptr, &cap_val,
- sizeof(unsigned int));
+ Status error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_GETHBPREGS, m_thread.GetID(), nullptr, &cap_val,
+ sizeof(unsigned int));
if (error.Fail())
- return error;
+ return error.ToError();
m_max_hwp_supported = (cap_val >> 8) & 0xff;
m_max_hbp_supported = cap_val & 0xff;
m_refresh_hwdebug_info = false;
- return error;
+ return error.ToError();
#else // __aarch64__
return arm64::ReadHardwareDebugInfo(m_thread.GetID(), m_max_hwp_supported,
- m_max_hbp_supported);
+ m_max_hbp_supported)
+ .ToError();
#endif // ifdef __arm__
}
-Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
- NativeRegisterContextDBReg::DREGType hwbType, int hwb_index) {
- Status error;
-
+llvm::Error
+NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(DREGType hwbType) {
#ifdef __arm__
- lldb::addr_t *addr_buf;
- uint32_t *ctrl_buf;
-
- if (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) {
- addr_buf = &m_hwp_regs[hwb_index].address;
- ctrl_buf = &m_hwp_regs[hwb_index].control;
-
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf,
- sizeof(unsigned int));
-
- if (error.Fail())
- return error;
-
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
- sizeof(unsigned int));
- } else {
- addr_buf = &m_hbr_regs[hwb_index].address;
- ctrl_buf = &m_hbr_regs[hwb_index].control;
-
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf,
- sizeof(unsigned int));
+ uint32_t max_index = m_max_hbp_supported;
+ if (hwbType == eDREGTypeWATCH)
+ max_index = m_max_hwp_supported;
- if (error.Fail())
+ for (uint32_t idx = 0; idx < max_index; ++idx)
+ if (auto error = WriteHardwareDebugReg(hwbType, idx))
return error;
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
- sizeof(unsigned int));
- }
-
- return error;
+ return llvm::Error::success();
#else // __aarch64__
uint32_t max_supported =
(hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
@@ -806,12 +327,48 @@ Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
: m_max_hbp_supported;
auto &regs = (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
? m_hwp_regs
- : m_hbr_regs;
+ : m_hbp_regs;
return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), max_supported,
- regs);
+ regs)
+ .ToError();
#endif // ifdef __arm__
}
+#ifdef __arm__
+llvm::Error
+NativeRegisterContextLinux_arm::WriteHardwareDebugReg(DREGType hwbType,
+ int hwb_index) {
+ Status error;
+ lldb::addr_t *addr_buf;
+ uint32_t *ctrl_buf;
+ int addr_idx = (hwb_index << 1) + 1;
+ int ctrl_idx = addr_idx + 1;
+
+ if (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) {
+ addr_idx *= -1;
+ addr_buf = &m_hwp_regs[hwb_index].address;
+ ctrl_idx *= -1;
+ ctrl_buf = &m_hwp_regs[hwb_index].control;
+ } else {
+ addr_buf = &m_hbp_regs[hwb_index].address;
+ ctrl_buf = &m_hbp_regs[hwb_index].control;
+ }
+
+ error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)addr_idx,
+ addr_buf, sizeof(unsigned int));
+
+ if (error.Fail())
+ return error.ToError();
+
+ error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)ctrl_idx,
+ ctrl_buf, sizeof(unsigned int));
+
+ return error.ToError();
+}
+#endif // ifdef __arm__
+
uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
const RegisterInfo *reg_info) const {
return reg_info->byte_offset - GetGPRSize();
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
index 3a31d68d7a3c..cf36859b16ad 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
@@ -12,7 +12,7 @@
#define lldb_NativeRegisterContextLinux_arm_h
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
-#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
@@ -21,7 +21,8 @@ namespace process_linux {
class NativeProcessLinux;
-class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {
+class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux,
+ public NativeRegisterContextDBReg_arm {
public:
NativeRegisterContextLinux_arm(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
@@ -42,39 +43,6 @@ public:
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
- // Hardware breakpoints/watchpoint management functions
-
- uint32_t NumSupportedHardwareBreakpoints() override;
-
- uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
-
- bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
-
- Status ClearAllHardwareBreakpoints() override;
-
- Status GetHardwareBreakHitIndex(uint32_t &bp_index,
- lldb::addr_t trap_addr) override;
-
- uint32_t NumSupportedHardwareWatchpoints() override;
-
- uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
- uint32_t watch_flags) override;
-
- bool ClearHardwareWatchpoint(uint32_t hw_index) override;
-
- Status ClearAllHardwareWatchpoints() override;
-
- Status GetWatchpointHitIndex(uint32_t &wp_index,
- lldb::addr_t trap_addr) override;
-
- lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
-
- lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
-
- uint32_t GetWatchpointSize(uint32_t wp_index);
-
- bool WatchpointIsEnabled(uint32_t wp_index);
-
protected:
Status DoReadRegisterValue(uint32_t offset, const char *reg_name,
uint32_t size, RegisterValue &value) override;
@@ -100,23 +68,18 @@ private:
uint32_t m_gpr_arm[k_num_gpr_registers_arm];
RegisterInfoPOSIX_arm::FPU m_fpr;
- std::array<NativeRegisterContextDBReg::DREG, 16>
- m_hbr_regs; // Arm native linux hardware breakpoints
- std::array<NativeRegisterContextDBReg::DREG, 16>
- m_hwp_regs; // Arm native linux hardware watchpoints
-
- uint32_t m_max_hwp_supported;
- uint32_t m_max_hbp_supported;
bool m_refresh_hwdebug_info;
bool IsGPR(unsigned reg) const;
bool IsFPR(unsigned reg) const;
- Status ReadHardwareDebugInfo();
+ llvm::Error ReadHardwareDebugInfo() override;
- Status WriteHardwareDebugRegs(NativeRegisterContextDBReg::DREGType hwbType,
- int hwb_index);
+ llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
+#ifdef __arm__
+ llvm::Error WriteHardwareDebugReg(DREGType hwbType, int hwb_index);
+#endif
uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index 5d99c22dafe1..b1e326ec064e 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -13,6 +13,7 @@ add_lldb_library(lldbPluginProcessUtility
MemoryTagManagerAArch64MTE.cpp
NativeProcessSoftwareSingleStep.cpp
NativeRegisterContextDBReg.cpp
+ NativeRegisterContextDBReg_arm.cpp
NativeRegisterContextDBReg_arm64.cpp
NativeRegisterContextDBReg_loongarch.cpp
NativeRegisterContextDBReg_x86.cpp
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
index 19601b7f35d4..f35027e93514 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
@@ -44,15 +44,16 @@ uint32_t NativeRegisterContextDBReg::SetHardwareBreakpoint(lldb::addr_t addr,
return LLDB_INVALID_INDEX32;
}
- uint32_t control_value = 0, bp_index = 0;
-
if (!ValidateBreakpoint(size, addr))
return LLDB_INVALID_INDEX32;
- control_value = MakeBreakControlValue(size);
+ uint32_t control_value = MakeBreakControlValue(size);
+ auto details = AdjustBreakpoint({size, addr});
+ size = details.size;
+ addr = details.addr;
// Iterate over stored breakpoints and find a free bp_index
- bp_index = LLDB_INVALID_INDEX32;
+ uint32_t bp_index = LLDB_INVALID_INDEX32;
for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
if (!BreakpointIsEnabled(i))
bp_index = i; // Mark last free slot
@@ -222,7 +223,7 @@ uint32_t NativeRegisterContextDBReg::SetHardwareWatchpoint(
addr = adjusted->addr;
// Check if we are setting watchpoint other than read/write/access Also
- // update watchpoint flag to match AArch64/LoongArch write-read bit
+ // update watchpoint flag to match ARM/AArch64/LoongArch write-read bit
// configuration.
switch (watch_flags) {
case lldb::eWatchpointKindWrite:
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
index 9b6ecd382c3f..2dd11dcf74de 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
@@ -12,6 +12,7 @@
#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
#include <array>
+#include <optional>
// Common utilities for hardware breakpoints and hardware watchpoints on AArch64
// and LoongArch.
@@ -76,19 +77,25 @@ protected:
// On AArch64 and Loongarch the hardware breakpoint length size is 4, and the
// target address must 4-byte alignment.
- bool ValidateBreakpoint(size_t size, lldb::addr_t addr) {
+ virtual bool ValidateBreakpoint(size_t size, lldb::addr_t addr) {
return (size == 4) && !(addr & 0x3);
}
+
struct WatchpointDetails {
size_t size;
lldb::addr_t addr;
};
virtual std::optional<WatchpointDetails>
AdjustWatchpoint(const WatchpointDetails &details) = 0;
+
+ using BreakpointDetails = WatchpointDetails;
+ virtual BreakpointDetails AdjustBreakpoint(const BreakpointDetails &details) {
+ return details;
+ }
+
virtual uint32_t MakeBreakControlValue(size_t size) = 0;
virtual uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) = 0;
virtual uint32_t GetWatchpointSize(uint32_t wp_index) = 0;
-
virtual llvm::Error ReadHardwareDebugInfo() = 0;
virtual llvm::Error WriteHardwareDebugRegs(DREGType hwbType) = 0;
virtual lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) {
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp
new file mode 100644
index 000000000000..803fed54d6b0
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp
@@ -0,0 +1,117 @@
+//===-- NativeRegisterContextDBReg_arm.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextDBReg_arm.h"
+
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+
+using namespace lldb_private;
+
+uint32_t NativeRegisterContextDBReg_arm::GetWatchpointSize(uint32_t wp_index) {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
+ case 0x01:
+ return 1;
+ case 0x03:
+ return 2;
+ case 0x07:
+ return 3;
+ case 0x0f:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+std::optional<NativeRegisterContextDBReg::WatchpointDetails>
+NativeRegisterContextDBReg_arm::AdjustWatchpoint(
+ const WatchpointDetails &details) {
+ auto [size, addr] = details;
+
+ if (size == 0 || size > 4)
+ return {};
+
+ // Check 4-byte alignment for hardware watchpoint target address. Below is a
+ // hack to recalculate address and size in order to make sure we can watch
+ // non 4-byte aligned addresses as well.
+ if (addr & 0x03) {
+ uint8_t watch_mask = (addr & 0x03) + size;
+ if (watch_mask > 0x04)
+ return {};
+ else if (watch_mask <= 0x02)
+ size = 2;
+ else
+ size = 4;
+
+ addr = addr & (~0x03);
+ }
+
+ return WatchpointDetails{size, addr};
+}
+
+NativeRegisterContextDBReg::BreakpointDetails
+NativeRegisterContextDBReg_arm::AdjustBreakpoint(
+ const BreakpointDetails &details) {
+ BreakpointDetails bd = details;
+ // Use size to get a hint of arm vs thumb modes.
+ // LLDB usually aligns this client side, but other clients may not.
+ switch (bd.size) {
+ case 2:
+ bd.addr &= ~1;
+ break;
+ case 4:
+ bd.addr &= ~3;
+ break;
+ default:
+ // We assume that ValidateBreakpoint would have caught this earlier.
+ llvm_unreachable("Invalid breakpoint size!");
+ }
+
+ return bd;
+}
+
+uint32_t NativeRegisterContextDBReg_arm::MakeBreakControlValue(size_t size) {
+ switch (size) {
+ case 2:
+ return (0x3 << 5) | 7;
+ case 4:
+ return (0xfu << 5) | 7;
+ default:
+ // ValidateBreakpoint would have rejected this earlier.
+ llvm_unreachable("Invalid breakpoint size.");
+ }
+}
+
+uint32_t
+NativeRegisterContextDBReg_arm::MakeWatchControlValue(size_t size,
+ uint32_t watch_flags) {
+ // We can only watch up to four bytes that follow a 4 byte aligned address
+ // per watchpoint register pair, so make sure we can properly encode this.
+ // We assume that the address was 4 byte aligned by AdjustWatchpoint.
+ uint32_t byte_mask = (1u << size) - 1u;
+
+ // Check if we need multiple watchpoint register
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Setup control value
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t control_value = byte_mask << 5;
+
+ // Turn on appropriate watchpoint flags read or write
+ control_value |= (watch_flags << 3);
+
+ // Enable this watchpoint and make it stop in privileged or user mode;
+ control_value |= 7;
+
+ return control_value;
+}
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h
new file mode 100644
index 000000000000..253ae96c90c9
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h
@@ -0,0 +1,42 @@
+//===-- NativeRegisterContextDBReg_arm.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextDBReg_arm_h
+#define lldb_NativeRegisterContextDBReg_arm_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
+
+namespace lldb_private {
+
+class NativeRegisterContextDBReg_arm : public NativeRegisterContextDBReg {
+public:
+ NativeRegisterContextDBReg_arm()
+ : NativeRegisterContextDBReg(/*enable_bit=*/0x1U) {}
+
+private:
+ uint32_t GetWatchpointSize(uint32_t wp_index) override;
+
+ std::optional<WatchpointDetails>
+ AdjustWatchpoint(const WatchpointDetails &details) override;
+
+ BreakpointDetails AdjustBreakpoint(const BreakpointDetails &details) override;
+
+ uint32_t MakeBreakControlValue(size_t size) override;
+
+ uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) override;
+
+ bool ValidateBreakpoint(size_t size,
+ [[maybe_unused]] lldb::addr_t addr) override {
+ // Break on 4 or 2 byte instructions.
+ return size == 4 || size == 2;
+ }
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextDBReg_arm_h
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
index fbf128553fd5..3b8d6a84c964 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
@@ -79,7 +79,7 @@ static lldb_private::RegisterInfo g_register_infos_mte[] = {
DEFINE_EXTENSION_REG(mte_ctrl)};
static lldb_private::RegisterInfo g_register_infos_tls[] = {
- DEFINE_EXTENSION_REG(tpidr),
+ DEFINE_EXTENSION_REG_GENERIC(tpidr, LLDB_REGNUM_GENERIC_TP),
// Only present when SME is present
DEFINE_EXTENSION_REG(tpidr2)};
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h
index c9c4d7ceae55..829fa076d221 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h
@@ -456,6 +456,7 @@ static uint32_t g_d29_invalidates[] = {fpu_v29, fpu_s29, LLDB_INVALID_REGNUM};
static uint32_t g_d30_invalidates[] = {fpu_v30, fpu_s30, LLDB_INVALID_REGNUM};
static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM};
+// clang-format off
// Generates register kinds array with DWARF, EH frame and generic kind
#define MISC_KIND(reg, type, generic_kind) \
{ \
@@ -470,6 +471,11 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM};
LLDB_INVALID_REGNUM, lldb_kind \
}
+#define GENERIC_KIND(genenric_kind) \
+ { \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, genenric_kind, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM \
+ }
// Generates register kinds array for registers with only lldb kind
#define KIND_ALL_INVALID \
{ \
@@ -484,8 +490,6 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM};
#define MISC_FPU_KIND(lldb_kind) LLDB_KIND(lldb_kind)
#define MISC_EXC_KIND(lldb_kind) LLDB_KIND(lldb_kind)
-// clang-format off
-
// Defines a 64-bit general purpose register
#define DEFINE_GPR64(reg, generic_kind) \
{ \
@@ -540,6 +544,12 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM};
#reg, nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \
KIND_ALL_INVALID, nullptr, nullptr, nullptr, \
}
+
+#define DEFINE_EXTENSION_REG_GENERIC(reg, generic_kind) \
+ { \
+ #reg, nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \
+ GENERIC_KIND(generic_kind), nullptr, nullptr, nullptr, \
+ }
static lldb_private::RegisterInfo g_register_infos_arm64_le[] = {
// DEFINE_GPR64(name, GENERIC KIND)
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 88eeddf17878..8f5f1242116f 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -99,7 +99,7 @@ bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp,
ProcessElfCore::ProcessElfCore(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
const FileSpec &core_file)
- : PostMortemProcess(target_sp, listener_sp, core_file) {}
+ : PostMortemProcess(target_sp, listener_sp, core_file), m_uuids() {}
// Destructor
ProcessElfCore::~ProcessElfCore() {
@@ -257,12 +257,12 @@ Status ProcessElfCore::DoLoadCore() {
// the main executable using data we found in the core file notes.
lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
if (!exe_module_sp) {
- // The first entry in the NT_FILE might be our executable
if (!m_nt_file_entries.empty()) {
+ llvm::StringRef executable_path = GetMainExecutablePath();
ModuleSpec exe_module_spec;
exe_module_spec.GetArchitecture() = arch;
- exe_module_spec.GetUUID() = m_nt_file_entries[0].uuid;
- exe_module_spec.GetFileSpec().SetFile(m_nt_file_entries[0].path,
+ exe_module_spec.GetUUID() = FindModuleUUID(executable_path);
+ exe_module_spec.GetFileSpec().SetFile(executable_path,
FileSpec::Style::native);
if (exe_module_spec.GetFileSpec()) {
exe_module_sp =
@@ -277,21 +277,38 @@ Status ProcessElfCore::DoLoadCore() {
void ProcessElfCore::UpdateBuildIdForNTFileEntries() {
Log *log = GetLog(LLDBLog::Process);
+ m_uuids.clear();
for (NT_FILE_Entry &entry : m_nt_file_entries) {
- entry.uuid = FindBuidIdInCoreMemory(entry.start);
- if (log && entry.uuid.IsValid())
- LLDB_LOGF(log, "%s found UUID @ %16.16" PRIx64 ": %s \"%s\"",
- __FUNCTION__, entry.start, entry.uuid.GetAsString().c_str(),
- entry.path.c_str());
+ UUID uuid = FindBuidIdInCoreMemory(entry.start);
+ if (uuid.IsValid()) {
+ // Assert that either the path is not in the map or the UUID matches
+ assert(m_uuids.count(entry.path) == 0 || m_uuids[entry.path] == uuid);
+ m_uuids[entry.path] = uuid;
+ if (log)
+ LLDB_LOGF(log, "%s found UUID @ %16.16" PRIx64 ": %s \"%s\"",
+ __FUNCTION__, entry.start, uuid.GetAsString().c_str(),
+ entry.path.c_str());
+ }
}
}
+llvm::StringRef ProcessElfCore::GetMainExecutablePath() {
+ if (m_nt_file_entries.empty())
+ return "";
+
+ // The first entry in the NT_FILE might be our executable
+ llvm::StringRef executable_path = m_nt_file_entries[0].path;
+ // Prefer the NT_FILE entry matching m_executable_name as main executable.
+ for (const NT_FILE_Entry &file_entry : m_nt_file_entries)
+ if (llvm::StringRef(file_entry.path).ends_with("/" + m_executable_name)) {
+ executable_path = file_entry.path;
+ break;
+ }
+ return executable_path;
+}
+
UUID ProcessElfCore::FindModuleUUID(const llvm::StringRef path) {
- // Returns the gnu uuid from matched NT_FILE entry
- for (NT_FILE_Entry &entry : m_nt_file_entries)
- if (path == entry.path && entry.uuid.IsValid())
- return entry.uuid;
- return UUID();
+ return m_uuids[std::string(path)];
}
lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
@@ -935,6 +952,7 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef<CoreNote> notes) {
return status.ToError();
thread_data.name.assign (prpsinfo.pr_fname, strnlen (prpsinfo.pr_fname, sizeof (prpsinfo.pr_fname)));
SetID(prpsinfo.pr_pid);
+ m_executable_name = prpsinfo.pr_fname;
break;
}
case ELF::NT_SIGINFO: {
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
index a91c04a277f6..576c6858477a 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -17,6 +17,7 @@
#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H
#include <list>
+#include <unordered_map>
#include <vector>
#include "lldb/Target/PostMortemProcess.h"
@@ -115,10 +116,6 @@ private:
lldb::addr_t end;
lldb::addr_t file_ofs;
std::string path;
- // Add a UUID member for convenient access. The UUID value is not in the
- // NT_FILE entries, we will find it in core memory and store it here for
- // easy access.
- lldb_private::UUID uuid;
};
// For ProcessElfCore only
@@ -152,6 +149,12 @@ private:
// NT_FILE entries found from the NOTE segment
std::vector<NT_FILE_Entry> m_nt_file_entries;
+ // Map from file path to UUID for quick lookup
+ std::unordered_map<std::string, lldb_private::UUID> m_uuids;
+
+ // Executable name found from the ELF PRPSINFO
+ std::string m_executable_name;
+
// Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment
llvm::Error ParseThreadContextsFromNoteSegment(
const elf::ELFProgramHeader &segment_header,
@@ -165,6 +168,9 @@ private:
lldb_private::UUID FindModuleUUID(const llvm::StringRef path) override;
+ // Returns the main executable path
+ llvm::StringRef GetMainExecutablePath();
+
// Returns the value of certain type of note of a given start address
lldb_private::UUID FindBuidIdInCoreMemory(lldb::addr_t address);
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
index 3a62081827c6..c9e90ebf8a4d 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
@@ -23,6 +23,10 @@ RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm(
gpregset.GetByteSize());
m_gpr.SetData(m_gpr_buffer);
m_gpr.SetByteOrder(gpregset.GetByteOrder());
+
+ const llvm::Triple &target_triple =
+ m_register_info_up->GetTargetArchitecture().GetTriple();
+ m_fpr = getRegset(notes, target_triple, ARM_VFP_Desc);
}
RegisterContextCorePOSIX_arm::~RegisterContextCorePOSIX_arm() = default;
@@ -43,14 +47,25 @@ bool RegisterContextCorePOSIX_arm::WriteFPR() {
bool RegisterContextCorePOSIX_arm::ReadRegister(const RegisterInfo *reg_info,
RegisterValue &value) {
- lldb::offset_t offset = reg_info->byte_offset;
- if (offset + reg_info->byte_size <= GetGPRSize()) {
- 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;
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM)
+ return false;
+
+ if (IsGPR(reg)) {
+ lldb::offset_t offset = reg_info->byte_offset;
+ if (m_gpr.ValidOffsetForDataOfSize(offset, reg_info->byte_size)) {
+ value = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ return offset == reg_info->byte_offset + reg_info->byte_size;
}
+ } else if (IsFPR(reg)) {
+ assert(reg_info->byte_offset >= GetGPRSize());
+ lldb::offset_t offset = reg_info->byte_offset - GetGPRSize();
+ if (m_fpr.ValidOffsetForDataOfSize(offset, reg_info->byte_size))
+ return value
+ .SetValueFromData(*reg_info, m_fpr, offset, /*partial_data_ok=*/false)
+ .Success();
}
+
return false;
}
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
index 8d773a046bca..e466ee242181 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
@@ -48,6 +48,7 @@ protected:
private:
lldb::DataBufferSP m_gpr_buffer;
lldb_private::DataExtractor m_gpr;
+ lldb_private::DataExtractor m_fpr;
};
#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM_H
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
index 59382a12cde0..a5b0d788a190 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
+++ b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
@@ -152,6 +152,11 @@ constexpr RegsetDesc AARCH64_GCS_Desc[] = {
{llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_GCS},
};
+constexpr RegsetDesc ARM_VFP_Desc[] = {
+ {llvm::Triple::FreeBSD, llvm::Triple::arm, llvm::ELF::NT_ARM_VFP},
+ {llvm::Triple::Linux, llvm::Triple::arm, llvm::ELF::NT_ARM_VFP},
+};
+
constexpr RegsetDesc PPC_VMX_Desc[] = {
{llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},
{llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 85e141d41747..91f3a6ce383b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -5773,7 +5773,7 @@ public:
CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter)
: CommandObjectRaw(interpreter, "process plugin packet monitor",
"Send a qRcmd packet through the GDB remote protocol "
- "and print the response."
+ "and print the response. "
"The argument passed to this command will be hex "
"encoded into a valid 'qRcmd' packet, sent and the "
"response will be printed.") {}
diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
index 6037c8d2514b..a780b3f59ade 100644
--- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
+++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -799,6 +799,23 @@ Status ProcessMachCore::DoGetMemoryRegionInfo(addr_t load_addr,
region_info.SetMapped(MemoryRegionInfo::eNo);
}
return Status();
+ } else {
+ // The corefile has no LC_SEGMENT at this virtual address,
+ // but see if there is a binary whose Section has been
+ // loaded at that address in the current Target.
+ Address addr;
+ if (GetTarget().ResolveLoadAddress(load_addr, addr)) {
+ SectionSP section_sp(addr.GetSection());
+ if (section_sp) {
+ region_info.GetRange().SetRangeBase(
+ section_sp->GetLoadBaseAddress(&GetTarget()));
+ region_info.GetRange().SetByteSize(section_sp->GetByteSize());
+ if (region_info.GetRange().Contains(load_addr)) {
+ region_info.SetLLDBPermissions(section_sp->GetPermissions());
+ return Status();
+ }
+ }
+ }
}
region_info.GetRange().SetRangeBase(load_addr);
diff --git a/lldb/source/Plugins/Process/scripted/CMakeLists.txt b/lldb/source/Plugins/Process/scripted/CMakeLists.txt
index 590166591a41..1516ad3132e3 100644
--- a/lldb/source/Plugins/Process/scripted/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/scripted/CMakeLists.txt
@@ -1,6 +1,7 @@
add_lldb_library(lldbPluginScriptedProcess PLUGIN
ScriptedProcess.cpp
ScriptedThread.cpp
+ ScriptedFrame.cpp
LINK_COMPONENTS
BinaryFormat
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
new file mode 100644
index 000000000000..6519df9185df
--- /dev/null
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
@@ -0,0 +1,191 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptedFrame.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void ScriptedFrame::CheckInterpreterAndScriptObject() const {
+ lldbassert(m_script_object_sp && "Invalid Script Object.");
+ lldbassert(GetInterface() && "Invalid Scripted Frame Interface.");
+}
+
+llvm::Expected<std::shared_ptr<ScriptedFrame>>
+ScriptedFrame::Create(ScriptedThread &thread,
+ StructuredData::DictionarySP args_sp,
+ StructuredData::Generic *script_object) {
+ if (!thread.IsValid())
+ return llvm::createStringError("Invalid scripted thread.");
+
+ thread.CheckInterpreterAndScriptObject();
+
+ auto scripted_frame_interface =
+ thread.GetInterface()->CreateScriptedFrameInterface();
+ if (!scripted_frame_interface)
+ return llvm::createStringError("failed to create scripted frame interface");
+
+ llvm::StringRef frame_class_name;
+ if (!script_object) {
+ std::optional<std::string> class_name =
+ thread.GetInterface()->GetScriptedFramePluginName();
+ if (!class_name || class_name->empty())
+ return llvm::createStringError(
+ "failed to get scripted thread class name");
+ frame_class_name = *class_name;
+ }
+
+ ExecutionContext exe_ctx(thread);
+ auto obj_or_err = scripted_frame_interface->CreatePluginObject(
+ frame_class_name, exe_ctx, args_sp, script_object);
+
+ if (!obj_or_err)
+ return llvm::createStringError(
+ "failed to create script object: %s",
+ llvm::toString(obj_or_err.takeError()).c_str());
+
+ StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
+
+ if (!owned_script_object_sp->IsValid())
+ return llvm::createStringError("created script object is invalid");
+
+ lldb::user_id_t frame_id = scripted_frame_interface->GetID();
+
+ lldb::addr_t pc = scripted_frame_interface->GetPC();
+ SymbolContext sc;
+ Address symbol_addr;
+ if (pc != LLDB_INVALID_ADDRESS) {
+ symbol_addr.SetLoadAddress(pc, &thread.GetProcess()->GetTarget());
+ symbol_addr.CalculateSymbolContext(&sc);
+ }
+
+ std::optional<SymbolContext> maybe_sym_ctx =
+ scripted_frame_interface->GetSymbolContext();
+ if (maybe_sym_ctx) {
+ sc = *maybe_sym_ctx;
+ }
+
+ StructuredData::DictionarySP reg_info =
+ scripted_frame_interface->GetRegisterInfo();
+
+ if (!reg_info)
+ return llvm::createStringError(
+ "failed to get scripted thread registers info");
+
+ std::shared_ptr<DynamicRegisterInfo> register_info_sp =
+ DynamicRegisterInfo::Create(
+ *reg_info, thread.GetProcess()->GetTarget().GetArchitecture());
+
+ lldb::RegisterContextSP reg_ctx_sp;
+
+ std::optional<std::string> reg_data =
+ scripted_frame_interface->GetRegisterContext();
+ if (reg_data) {
+ DataBufferSP data_sp(
+ std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
+
+ if (!data_sp->GetByteSize())
+ return llvm::createStringError("failed to copy raw registers data");
+
+ std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
+ std::make_shared<RegisterContextMemory>(
+ thread, frame_id, *register_info_sp, LLDB_INVALID_ADDRESS);
+ if (!reg_ctx_memory)
+ return llvm::createStringError("failed to create a register context.");
+
+ reg_ctx_memory->SetAllRegisterData(data_sp);
+ reg_ctx_sp = reg_ctx_memory;
+ }
+
+ return std::make_shared<ScriptedFrame>(
+ thread, scripted_frame_interface, frame_id, pc, sc, reg_ctx_sp,
+ register_info_sp, owned_script_object_sp);
+}
+
+ScriptedFrame::ScriptedFrame(ScriptedThread &thread,
+ ScriptedFrameInterfaceSP interface_sp,
+ lldb::user_id_t id, lldb::addr_t pc,
+ SymbolContext &sym_ctx,
+ lldb::RegisterContextSP reg_ctx_sp,
+ std::shared_ptr<DynamicRegisterInfo> reg_info_sp,
+ StructuredData::GenericSP script_object_sp)
+ : StackFrame(thread.shared_from_this(), /*frame_idx=*/id,
+ /*concrete_frame_idx=*/id, /*reg_context_sp=*/reg_ctx_sp,
+ /*cfa=*/0, /*pc=*/pc,
+ /*behaves_like_zeroth_frame=*/!id, /*symbol_ctx=*/&sym_ctx),
+ m_scripted_frame_interface_sp(interface_sp),
+ m_script_object_sp(script_object_sp), m_register_info_sp(reg_info_sp) {}
+
+ScriptedFrame::~ScriptedFrame() {}
+
+const char *ScriptedFrame::GetFunctionName() {
+ CheckInterpreterAndScriptObject();
+ std::optional<std::string> function_name = GetInterface()->GetFunctionName();
+ if (!function_name)
+ return nullptr;
+ return ConstString(function_name->c_str()).AsCString();
+}
+
+const char *ScriptedFrame::GetDisplayFunctionName() {
+ CheckInterpreterAndScriptObject();
+ std::optional<std::string> function_name =
+ GetInterface()->GetDisplayFunctionName();
+ if (!function_name)
+ return nullptr;
+ return ConstString(function_name->c_str()).AsCString();
+}
+
+bool ScriptedFrame::IsInlined() { return GetInterface()->IsInlined(); }
+
+bool ScriptedFrame::IsArtificial() const {
+ return GetInterface()->IsArtificial();
+}
+
+bool ScriptedFrame::IsHidden() { return GetInterface()->IsHidden(); }
+
+lldb::ScriptedFrameInterfaceSP ScriptedFrame::GetInterface() const {
+ return m_scripted_frame_interface_sp;
+}
+
+std::shared_ptr<DynamicRegisterInfo> ScriptedFrame::GetDynamicRegisterInfo() {
+ CheckInterpreterAndScriptObject();
+
+ if (!m_register_info_sp) {
+ StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
+
+ Status error;
+ if (!reg_info)
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION, "Failed to get scripted frame registers info.",
+ error, LLDBLog::Thread);
+
+ ThreadSP thread_sp = m_thread_wp.lock();
+ if (!thread_sp || !thread_sp->IsValid())
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION,
+ "Failed to get scripted frame registers info: invalid thread.", error,
+ LLDBLog::Thread);
+
+ ProcessSP process_sp = thread_sp->GetProcess();
+ if (!process_sp || !process_sp->IsValid())
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION,
+ "Failed to get scripted frame registers info: invalid process.",
+ error, LLDBLog::Thread);
+
+ m_register_info_sp = DynamicRegisterInfo::Create(
+ *reg_info, process_sp->GetTarget().GetArchitecture());
+ }
+
+ return m_register_info_sp;
+}
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.h b/lldb/source/Plugins/Process/scripted/ScriptedFrame.h
new file mode 100644
index 000000000000..6e01e2fd7653
--- /dev/null
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.h
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SCRIPTED_FRAME_H
+#define LLDB_SOURCE_PLUGINS_SCRIPTED_FRAME_H
+
+#include "Plugins/Process/Utility/RegisterContextMemory.h"
+#include "ScriptedThread.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target/DynamicRegisterInfo.h"
+#include "lldb/Target/StackFrame.h"
+#include <string>
+
+namespace lldb_private {
+class ScriptedThread;
+}
+
+namespace lldb_private {
+
+class ScriptedFrame : public lldb_private::StackFrame {
+
+public:
+ ScriptedFrame(ScriptedThread &thread,
+ lldb::ScriptedFrameInterfaceSP interface_sp,
+ lldb::user_id_t frame_idx, lldb::addr_t pc,
+ SymbolContext &sym_ctx, lldb::RegisterContextSP reg_ctx_sp,
+ std::shared_ptr<DynamicRegisterInfo> reg_info_sp,
+ StructuredData::GenericSP script_object_sp = nullptr);
+
+ ~ScriptedFrame() override;
+
+ static llvm::Expected<std::shared_ptr<ScriptedFrame>>
+ Create(ScriptedThread &thread, StructuredData::DictionarySP args_sp,
+ StructuredData::Generic *script_object = nullptr);
+
+ bool IsInlined() override;
+ bool IsArtificial() const override;
+ bool IsHidden() override;
+ const char *GetFunctionName() override;
+ const char *GetDisplayFunctionName() override;
+
+private:
+ void CheckInterpreterAndScriptObject() const;
+ lldb::ScriptedFrameInterfaceSP GetInterface() const;
+
+ ScriptedFrame(const ScriptedFrame &) = delete;
+ const ScriptedFrame &operator=(const ScriptedFrame &) = delete;
+
+ std::shared_ptr<DynamicRegisterInfo> GetDynamicRegisterInfo();
+
+ lldb::ScriptedFrameInterfaceSP m_scripted_frame_interface_sp;
+ lldb_private::StructuredData::GenericSP m_script_object_sp;
+ std::shared_ptr<DynamicRegisterInfo> m_register_info_sp;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SCRIPTED_FRAME_H
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
index d0d1508e8517..491efac5aade 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "ScriptedThread.h"
+#include "ScriptedFrame.h"
#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
#include "Plugins/Process/Utility/StopInfoMachException.h"
@@ -173,40 +174,101 @@ bool ScriptedThread::LoadArtificialStackFrames() {
.str(),
error, LLDBLog::Thread);
- StackFrameListSP frames = GetStackFrameList();
-
- for (size_t idx = 0; idx < arr_size; idx++) {
+ auto create_frame_from_dict =
+ [this, arr_sp](size_t idx) -> llvm::Expected<StackFrameSP> {
+ Status error;
std::optional<StructuredData::Dictionary *> maybe_dict =
arr_sp->GetItemAtIndexAsDictionary(idx);
- if (!maybe_dict)
- return ScriptedInterface::ErrorWithMessage<bool>(
+ if (!maybe_dict) {
+ ScriptedInterface::ErrorWithMessage<bool>(
LLVM_PRETTY_FUNCTION,
llvm::Twine(
"Couldn't get artificial stackframe dictionary at index (" +
llvm::Twine(idx) + llvm::Twine(") from stackframe array."))
.str(),
error, LLDBLog::Thread);
+ return error.ToError();
+ }
StructuredData::Dictionary *dict = *maybe_dict;
lldb::addr_t pc;
- if (!dict->GetValueForKeyAsInteger("pc", pc))
- return ScriptedInterface::ErrorWithMessage<bool>(
+ if (!dict->GetValueForKeyAsInteger("pc", pc)) {
+ ScriptedInterface::ErrorWithMessage<bool>(
LLVM_PRETTY_FUNCTION,
"Couldn't find value for key 'pc' in stackframe dictionary.", error,
LLDBLog::Thread);
+ return error.ToError();
+ }
Address symbol_addr;
symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());
lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
bool cfa_is_valid = false;
+ const bool artificial = false;
const bool behaves_like_zeroth_frame = false;
SymbolContext sc;
symbol_addr.CalculateSymbolContext(&sc);
- StackFrameSP synth_frame_sp = std::make_shared<StackFrame>(
- this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
- StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc);
+ return std::make_shared<StackFrame>(this->shared_from_this(), idx, idx, cfa,
+ cfa_is_valid, pc,
+ StackFrame::Kind::Synthetic, artificial,
+ behaves_like_zeroth_frame, &sc);
+ };
+
+ auto create_frame_from_script_object =
+ [this, arr_sp](size_t idx) -> llvm::Expected<StackFrameSP> {
+ Status error;
+ StructuredData::ObjectSP object_sp = arr_sp->GetItemAtIndex(idx);
+ if (!object_sp || !object_sp->GetAsGeneric()) {
+ ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine("Couldn't get artificial stackframe object at index (" +
+ llvm::Twine(idx) +
+ llvm::Twine(") from stackframe array."))
+ .str(),
+ error, LLDBLog::Thread);
+ return error.ToError();
+ }
+
+ auto frame_or_error =
+ ScriptedFrame::Create(*this, nullptr, object_sp->GetAsGeneric());
+
+ if (!frame_or_error) {
+ ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION, toString(frame_or_error.takeError()), error);
+ return error.ToError();
+ }
+
+ StackFrameSP frame_sp = frame_or_error.get();
+ lldbassert(frame_sp && "Couldn't initialize scripted frame.");
+
+ return frame_sp;
+ };
+
+ StackFrameListSP frames = GetStackFrameList();
+
+ for (size_t idx = 0; idx < arr_size; idx++) {
+ StackFrameSP synth_frame_sp = nullptr;
+
+ auto frame_from_dict_or_err = create_frame_from_dict(idx);
+ if (!frame_from_dict_or_err) {
+ auto frame_from_script_obj_or_err = create_frame_from_script_object(idx);
+
+ if (!frame_from_script_obj_or_err) {
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine("Couldn't add artificial frame (" + llvm::Twine(idx) +
+ llvm::Twine(") to ScriptedThread StackFrameList."))
+ .str(),
+ error, LLDBLog::Thread);
+ } else {
+ llvm::consumeError(frame_from_dict_or_err.takeError());
+ synth_frame_sp = *frame_from_script_obj_or_err;
+ }
+ } else {
+ synth_frame_sp = *frame_from_dict_or_err;
+ }
if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))
return ScriptedInterface::ErrorWithMessage<bool>(
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.h b/lldb/source/Plugins/Process/scripted/ScriptedThread.h
index cd224d60ceef..ee5ace405967 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedThread.h
+++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.h
@@ -15,11 +15,12 @@
#include "Plugins/Process/Utility/RegisterContextMemory.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
-#include "lldb/Target//DynamicRegisterInfo.h"
+#include "lldb/Target/DynamicRegisterInfo.h"
#include "lldb/Target/Thread.h"
namespace lldb_private {
class ScriptedProcess;
+class ScriptedFrame;
}
namespace lldb_private {
@@ -61,6 +62,8 @@ public:
StructuredData::ObjectSP FetchThreadExtendedInfo() override;
private:
+ friend class ScriptedFrame;
+
void CheckInterpreterAndScriptObject() const;
lldb::ScriptedThreadInterfaceSP GetInterface() const;