summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/Linux/NativeProcessLinux.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/Linux/NativeProcessLinux.cpp')
-rw-r--r--source/Plugins/Process/Linux/NativeProcessLinux.cpp325
1 files changed, 35 insertions, 290 deletions
diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 3fb886e1c7a3..8c6c95380e81 100644
--- a/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -9,29 +9,23 @@
#include "NativeProcessLinux.h"
-// C Includes
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
-// C++ Includes
#include <fstream>
#include <mutex>
#include <sstream>
#include <string>
#include <unordered_map>
-// Other libraries and framework includes
#include "lldb/Core/EmulateInstruction.h"
#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/RegisterValue.h"
-#include "lldb/Core/State.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostProcess.h"
#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Host/ThreadLauncher.h"
-#include "lldb/Host/common/NativeBreakpoint.h"
#include "lldb/Host/common/NativeRegisterContext.h"
#include "lldb/Host/linux/Ptrace.h"
#include "lldb/Host/linux/Uio.h"
@@ -41,6 +35,8 @@
#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/State.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StringExtractor.h"
#include "llvm/Support/Errno.h"
@@ -49,6 +45,7 @@
#include "NativeThreadLinux.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/LinuxProcMaps.h"
#include "Procfs.h"
#include <linux/unistd.h>
@@ -759,9 +756,7 @@ void NativeProcessLinux::MonitorBreakpoint(NativeThreadLinux &thread) {
// Mark the thread as stopped at breakpoint.
thread.SetStoppedByBreakpoint();
- Status error = FixupBreakpointPCAsNeeded(thread);
- if (error.Fail())
- LLDB_LOG(log, "pid = {0} fixup: {1}", thread.GetID(), error);
+ FixupBreakpointPCAsNeeded(thread);
if (m_threads_stepping_with_breakpoint.find(thread.GetID()) !=
m_threads_stepping_with_breakpoint.end())
@@ -1238,90 +1233,6 @@ Status NativeProcessLinux::Kill() {
return error;
}
-static Status
-ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef &maps_line,
- MemoryRegionInfo &memory_region_info) {
- memory_region_info.Clear();
-
- StringExtractor line_extractor(maps_line);
-
- // Format: {address_start_hex}-{address_end_hex} perms offset dev inode
- // pathname perms: rwxp (letter is present if set, '-' if not, final
- // character is p=private, s=shared).
-
- // Parse out the starting address
- lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0);
-
- // Parse out hyphen separating start and end address from range.
- if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-'))
- return Status(
- "malformed /proc/{pid}/maps entry, missing dash between address range");
-
- // Parse out the ending address
- lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address);
-
- // Parse out the space after the address.
- if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' '))
- return Status(
- "malformed /proc/{pid}/maps entry, missing space after range");
-
- // Save the range.
- memory_region_info.GetRange().SetRangeBase(start_address);
- memory_region_info.GetRange().SetRangeEnd(end_address);
-
- // Any memory region in /proc/{pid}/maps is by definition mapped into the
- // process.
- memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
-
- // Parse out each permission entry.
- if (line_extractor.GetBytesLeft() < 4)
- return Status("malformed /proc/{pid}/maps entry, missing some portion of "
- "permissions");
-
- // Handle read permission.
- const char read_perm_char = line_extractor.GetChar();
- if (read_perm_char == 'r')
- memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
- else if (read_perm_char == '-')
- memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
- else
- return Status("unexpected /proc/{pid}/maps read permission char");
-
- // Handle write permission.
- const char write_perm_char = line_extractor.GetChar();
- if (write_perm_char == 'w')
- memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
- else if (write_perm_char == '-')
- memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
- else
- return Status("unexpected /proc/{pid}/maps write permission char");
-
- // Handle execute permission.
- const char exec_perm_char = line_extractor.GetChar();
- if (exec_perm_char == 'x')
- memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
- else if (exec_perm_char == '-')
- memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
- else
- return Status("unexpected /proc/{pid}/maps exec permission char");
-
- line_extractor.GetChar(); // Read the private bit
- line_extractor.SkipSpaces(); // Skip the separator
- line_extractor.GetHexMaxU64(false, 0); // Read the offset
- line_extractor.GetHexMaxU64(false, 0); // Read the major device number
- line_extractor.GetChar(); // Read the device id separator
- line_extractor.GetHexMaxU64(false, 0); // Read the major device number
- line_extractor.SkipSpaces(); // Skip the separator
- line_extractor.GetU64(0, 10); // Read the inode number
-
- line_extractor.SkipSpaces();
- const char *name = line_extractor.Peek();
- if (name)
- memory_region_info.SetName(name);
-
- return Status();
-}
-
Status NativeProcessLinux::GetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &range_info) {
// FIXME review that the final memory region returned extends to the end of
@@ -1407,22 +1318,23 @@ Status NativeProcessLinux::PopulateMemoryRegionCache() {
m_supports_mem_region = LazyBool::eLazyBoolNo;
return BufferOrError.getError();
}
- StringRef Rest = BufferOrError.get()->getBuffer();
- while (! Rest.empty()) {
- StringRef Line;
- std::tie(Line, Rest) = Rest.split('\n');
- MemoryRegionInfo info;
- const Status parse_error =
- ParseMemoryRegionInfoFromProcMapsLine(Line, info);
- if (parse_error.Fail()) {
- LLDB_LOG(log, "failed to parse proc maps line '{0}': {1}", Line,
- parse_error);
- m_supports_mem_region = LazyBool::eLazyBoolNo;
- return parse_error;
- }
- m_mem_region_cache.emplace_back(
- info, FileSpec(info.GetName().GetCString(), true));
- }
+ Status Result;
+ ParseLinuxMapRegions(BufferOrError.get()->getBuffer(),
+ [&](const MemoryRegionInfo &Info, const Status &ST) {
+ if (ST.Success()) {
+ FileSpec file_spec(Info.GetName().GetCString());
+ FileSystem::Instance().Resolve(file_spec);
+ m_mem_region_cache.emplace_back(Info, file_spec);
+ return true;
+ } else {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ LLDB_LOG(log, "failed to parse proc maps: {0}", ST);
+ Result = ST;
+ return false;
+ }
+ });
+ if (Result.Fail())
+ return Result;
if (m_mem_region_cache.empty()) {
// No entries after attempting to read them. This shouldn't happen if
@@ -1502,40 +1414,6 @@ size_t NativeProcessLinux::UpdateThreads() {
return m_threads.size();
}
-Status NativeProcessLinux::GetSoftwareBreakpointPCOffset(
- uint32_t &actual_opcode_size) {
- // FIXME put this behind a breakpoint protocol class that can be
- // set per architecture. Need ARM, MIPS support here.
- static const uint8_t g_i386_opcode[] = {0xCC};
- static const uint8_t g_s390x_opcode[] = {0x00, 0x01};
-
- switch (m_arch.GetMachine()) {
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- actual_opcode_size = static_cast<uint32_t>(sizeof(g_i386_opcode));
- return Status();
-
- case llvm::Triple::systemz:
- actual_opcode_size = static_cast<uint32_t>(sizeof(g_s390x_opcode));
- return Status();
-
- case llvm::Triple::arm:
- case llvm::Triple::aarch64:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::ppc64le:
- // On these architectures the PC don't get updated for breakpoint hits
- actual_opcode_size = 0;
- return Status();
-
- default:
- assert(false && "CPU type not supported!");
- return Status("CPU type not supported");
- }
-}
-
Status NativeProcessLinux::SetBreakpoint(lldb::addr_t addr, uint32_t size,
bool hardware) {
if (hardware)
@@ -1551,74 +1429,26 @@ Status NativeProcessLinux::RemoveBreakpoint(lldb::addr_t addr, bool hardware) {
return NativeProcessProtocol::RemoveBreakpoint(addr);
}
-Status NativeProcessLinux::GetSoftwareBreakpointTrapOpcode(
- size_t trap_opcode_size_hint, size_t &actual_opcode_size,
- const uint8_t *&trap_opcode_bytes) {
- // FIXME put this behind a breakpoint protocol class that can be set per
- // architecture. Need MIPS support here.
- static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xd4};
+llvm::Expected<llvm::ArrayRef<uint8_t>>
+NativeProcessLinux::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
// 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_i386_opcode[] = {0xCC};
- static const uint8_t g_mips64_opcode[] = {0x00, 0x00, 0x00, 0x0d};
- static const uint8_t g_mips64el_opcode[] = {0x0d, 0x00, 0x00, 0x00};
- static const uint8_t g_s390x_opcode[] = {0x00, 0x01};
- static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde};
- static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap
-
- switch (m_arch.GetMachine()) {
- case llvm::Triple::aarch64:
- trap_opcode_bytes = g_aarch64_opcode;
- actual_opcode_size = sizeof(g_aarch64_opcode);
- return Status();
+ static const uint8_t g_arm_opcode[] = {0xf0, 0x01, 0xf0, 0xe7};
+ static const uint8_t g_thumb_opcode[] = {0x01, 0xde};
+ switch (GetArchitecture().GetMachine()) {
case llvm::Triple::arm:
- switch (trap_opcode_size_hint) {
+ switch (size_hint) {
case 2:
- trap_opcode_bytes = g_thumb_breakpoint_opcode;
- actual_opcode_size = sizeof(g_thumb_breakpoint_opcode);
- return Status();
+ return llvm::makeArrayRef(g_thumb_opcode);
case 4:
- trap_opcode_bytes = g_arm_breakpoint_opcode;
- actual_opcode_size = sizeof(g_arm_breakpoint_opcode);
- return Status();
+ return llvm::makeArrayRef(g_arm_opcode);
default:
- assert(false && "Unrecognised trap opcode size hint!");
- return Status("Unrecognised trap opcode size hint!");
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Unrecognised trap opcode size hint!");
}
-
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- trap_opcode_bytes = g_i386_opcode;
- actual_opcode_size = sizeof(g_i386_opcode);
- return Status();
-
- case llvm::Triple::mips:
- case llvm::Triple::mips64:
- trap_opcode_bytes = g_mips64_opcode;
- actual_opcode_size = sizeof(g_mips64_opcode);
- return Status();
-
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64el:
- trap_opcode_bytes = g_mips64el_opcode;
- actual_opcode_size = sizeof(g_mips64el_opcode);
- return Status();
-
- case llvm::Triple::systemz:
- trap_opcode_bytes = g_s390x_opcode;
- actual_opcode_size = sizeof(g_s390x_opcode);
- return Status();
-
- case llvm::Triple::ppc64le:
- trap_opcode_bytes = g_ppc64le_opcode;
- actual_opcode_size = sizeof(g_ppc64le_opcode);
- return Status();
-
default:
- assert(false && "CPU type not supported!");
- return Status("CPU type not supported");
+ return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint);
}
}
@@ -1677,15 +1507,6 @@ Status NativeProcessLinux::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
return Status();
}
-Status NativeProcessLinux::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf,
- size_t size,
- size_t &bytes_read) {
- Status error = ReadMemory(addr, buf, size, bytes_read);
- if (error.Fail())
- return error;
- return m_breakpoint_list.RemoveTrapsFromBuffer(addr, buf, size);
-}
-
Status NativeProcessLinux::WriteMemory(lldb::addr_t addr, const void *buf,
size_t size, size_t &bytes_written) {
const unsigned char *src = static_cast<const unsigned char *>(buf);
@@ -1810,90 +1631,14 @@ NativeThreadLinux &NativeProcessLinux::AddThread(lldb::tid_t thread_id) {
return static_cast<NativeThreadLinux &>(*m_threads.back());
}
-Status
-NativeProcessLinux::FixupBreakpointPCAsNeeded(NativeThreadLinux &thread) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
-
- Status error;
-
- // Find out the size of a breakpoint (might depend on where we are in the
- // code).
- NativeRegisterContext &context = thread.GetRegisterContext();
-
- uint32_t breakpoint_size = 0;
- error = GetSoftwareBreakpointPCOffset(breakpoint_size);
- if (error.Fail()) {
- LLDB_LOG(log, "GetBreakpointSize() failed: {0}", error);
- return error;
- } else
- LLDB_LOG(log, "breakpoint size: {0}", breakpoint_size);
-
- // First try probing for a breakpoint at a software breakpoint location: PC -
- // breakpoint size.
- const lldb::addr_t initial_pc_addr = context.GetPCfromBreakpointLocation();
- lldb::addr_t breakpoint_addr = initial_pc_addr;
- if (breakpoint_size > 0) {
- // Do not allow breakpoint probe to wrap around.
- if (breakpoint_addr >= breakpoint_size)
- breakpoint_addr -= breakpoint_size;
- }
-
- // Check if we stopped because of a breakpoint.
- NativeBreakpointSP breakpoint_sp;
- error = m_breakpoint_list.GetBreakpoint(breakpoint_addr, breakpoint_sp);
- if (!error.Success() || !breakpoint_sp) {
- // We didn't find one at a software probe location. Nothing to do.
- LLDB_LOG(log,
- "pid {0} no lldb breakpoint found at current pc with "
- "adjustment: {1}",
- GetID(), breakpoint_addr);
- return Status();
- }
-
- // If the breakpoint is not a software breakpoint, nothing to do.
- if (!breakpoint_sp->IsSoftwareBreakpoint()) {
- LLDB_LOG(
- log,
- "pid {0} breakpoint found at {1:x}, not software, nothing to adjust",
- GetID(), breakpoint_addr);
- return Status();
- }
-
- //
- // We have a software breakpoint and need to adjust the PC.
- //
-
- // Sanity check.
- if (breakpoint_size == 0) {
- // Nothing to do! How did we get here?
- LLDB_LOG(log,
- "pid {0} breakpoint found at {1:x}, it is software, but the "
- "size is zero, nothing to do (unexpected)",
- GetID(), breakpoint_addr);
- return Status();
- }
-
- // Change the program counter.
- LLDB_LOG(log, "pid {0} tid {1}: changing PC from {2:x} to {3:x}", GetID(),
- thread.GetID(), initial_pc_addr, breakpoint_addr);
-
- error = context.SetPC(breakpoint_addr);
- if (error.Fail()) {
- LLDB_LOG(log, "pid {0} tid {1}: failed to set PC: {2}", GetID(),
- thread.GetID(), error);
- return error;
- }
-
- return error;
-}
-
Status NativeProcessLinux::GetLoadedModuleFileSpec(const char *module_path,
FileSpec &file_spec) {
Status error = PopulateMemoryRegionCache();
if (error.Fail())
return error;
- FileSpec module_file_spec(module_path, true);
+ FileSpec module_file_spec(module_path);
+ FileSystem::Instance().Resolve(module_file_spec);
file_spec.Clear();
for (const auto &it : m_mem_region_cache) {
@@ -1913,7 +1658,7 @@ Status NativeProcessLinux::GetFileLoadAddress(const llvm::StringRef &file_name,
if (error.Fail())
return error;
- FileSpec file(file_name, false);
+ FileSpec file(file_name);
for (const auto &it : m_mem_region_cache) {
if (it.second == file) {
load_addr = it.first.GetRange().GetRangeBase();