diff options
author | Pavel Labath <pavel@labath.sk> | 2018-09-26 07:31:41 +0000 |
---|---|---|
committer | Pavel Labath <pavel@labath.sk> | 2018-09-26 07:31:41 +0000 |
commit | a053a48c5551a8b9454cb54832b9136f60232996 (patch) | |
tree | 2c249d2285e182f582ae226b63a214c2395481a2 /lldb/source | |
parent | 912c4c9012c5c3a0b478e29fe4f66295db61107c (diff) |
Fix a memory read bug in lldb-server
NativeProcessProtocol::ReadMemoryWithoutTrap had a bug, where it failed
to properly remove inserted breakpoint opcodes if the memory read
partially overlapped the trap opcode. This could not happen on x86
because it has a one-byte breakpoint instruction, but it could happen on
arm, which has a 4-byte breakpoint instruction (in arm mode).
Since triggerring this condition would only be possible on an arm
machine (and even then it would be a bit tricky). I test this using a
NativeProcessProtocol unit test.
Diffstat (limited to 'lldb/source')
-rw-r--r-- | lldb/source/Host/common/NativeBreakpointList.cpp | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/lldb/source/Host/common/NativeBreakpointList.cpp b/lldb/source/Host/common/NativeBreakpointList.cpp index cfcbe083106..b1a42d7583c 100644 --- a/lldb/source/Host/common/NativeBreakpointList.cpp +++ b/lldb/source/Host/common/NativeBreakpointList.cpp @@ -210,20 +210,31 @@ Status NativeBreakpointList::GetBreakpoint(lldb::addr_t addr, Status NativeBreakpointList::RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf, size_t size) const { + auto data = llvm::makeMutableArrayRef(static_cast<uint8_t *>(buf), size); for (const auto &map : m_breakpoints) { - lldb::addr_t bp_addr = map.first; - // Breapoint not in range, ignore - if (bp_addr < addr || addr + size <= bp_addr) - continue; const auto &bp_sp = map.second; // Not software breakpoint, ignore if (!bp_sp->IsSoftwareBreakpoint()) continue; auto software_bp_sp = std::static_pointer_cast<SoftwareBreakpoint>(bp_sp); - auto opcode_addr = static_cast<char *>(buf) + bp_addr - addr; - auto saved_opcodes = software_bp_sp->m_saved_opcodes; + + lldb::addr_t bp_addr = map.first; auto opcode_size = software_bp_sp->m_opcode_size; - ::memcpy(opcode_addr, saved_opcodes, opcode_size); + + // Breapoint not in range, ignore + if (bp_addr + opcode_size < addr || addr + size <= bp_addr) + continue; + + auto saved_opcodes = + llvm::makeArrayRef(software_bp_sp->m_saved_opcodes, opcode_size); + if (bp_addr < addr) { + saved_opcodes = saved_opcodes.drop_front(addr - bp_addr); + bp_addr = addr; + } + auto bp_data = data.drop_front(bp_addr - addr); + std::copy_n(saved_opcodes.begin(), + std::min(saved_opcodes.size(), bp_data.size()), + bp_data.begin()); } return Status(); } |