Skip to content

Commit f7ec3e3

Browse files
committed
[lldb] Skip overlapping hardware and external breakpoints when writing memory
This fixes the assertion `assert(intersects);` in the Process::WriteMemory function. Differential Revision: https://reviews.llvm.org/D84254
1 parent 59fac51 commit f7ec3e3

File tree

5 files changed

+96
-31
lines changed

5 files changed

+96
-31
lines changed

lldb/source/Breakpoint/BreakpointSite.cpp

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -167,40 +167,39 @@ bool BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size,
167167
lldb::addr_t *intersect_addr,
168168
size_t *intersect_size,
169169
size_t *opcode_offset) const {
170-
// We only use software traps for software breakpoints
171-
if (!IsHardware()) {
172-
if (m_byte_size > 0) {
173-
const lldb::addr_t bp_end_addr = m_addr + m_byte_size;
174-
const lldb::addr_t end_addr = addr + size;
175-
// Is the breakpoint end address before the passed in start address?
176-
if (bp_end_addr <= addr)
177-
return false;
178-
// Is the breakpoint start address after passed in end address?
179-
if (end_addr <= m_addr)
180-
return false;
181-
if (intersect_addr || intersect_size || opcode_offset) {
182-
if (m_addr < addr) {
183-
if (intersect_addr)
184-
*intersect_addr = addr;
185-
if (intersect_size)
186-
*intersect_size =
187-
std::min<lldb::addr_t>(bp_end_addr, end_addr) - addr;
188-
if (opcode_offset)
189-
*opcode_offset = addr - m_addr;
190-
} else {
191-
if (intersect_addr)
192-
*intersect_addr = m_addr;
193-
if (intersect_size)
194-
*intersect_size =
195-
std::min<lldb::addr_t>(bp_end_addr, end_addr) - m_addr;
196-
if (opcode_offset)
197-
*opcode_offset = 0;
198-
}
170+
// The function should be called only for software breakpoints.
171+
lldbassert(GetType() == Type::eSoftware);
172+
173+
if (m_byte_size > 0) {
174+
const lldb::addr_t bp_end_addr = m_addr + m_byte_size;
175+
const lldb::addr_t end_addr = addr + size;
176+
// Is the breakpoint end address before the passed in start address?
177+
if (bp_end_addr <= addr)
178+
return false;
179+
// Is the breakpoint start address after passed in end address?
180+
if (end_addr <= m_addr)
181+
return false;
182+
if (intersect_addr || intersect_size || opcode_offset) {
183+
if (m_addr < addr) {
184+
if (intersect_addr)
185+
*intersect_addr = addr;
186+
if (intersect_size)
187+
*intersect_size =
188+
std::min<lldb::addr_t>(bp_end_addr, end_addr) - addr;
189+
if (opcode_offset)
190+
*opcode_offset = addr - m_addr;
191+
} else {
192+
if (intersect_addr)
193+
*intersect_addr = m_addr;
194+
if (intersect_size)
195+
*intersect_size =
196+
std::min<lldb::addr_t>(bp_end_addr, end_addr) - m_addr;
197+
if (opcode_offset)
198+
*opcode_offset = 0;
199199
}
200-
return true;
201200
}
201+
return true;
202202
}
203-
return false;
204203
}
205204

206205
size_t

lldb/source/Target/Process.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2291,6 +2291,9 @@ size_t Process::WriteMemory(addr_t addr, const void *buf, size_t size,
22912291
if (error.Fail())
22922292
return;
22932293

2294+
if (bp->GetType() != BreakpointSite::eSoftware)
2295+
return;
2296+
22942297
addr_t intersect_addr;
22952298
size_t intersect_size;
22962299
size_t opcode_offset;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CXX_SOURCES := main.cpp
2+
3+
include Makefile.rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""
2+
Test that writing memory does't affect hardware breakpoints.
3+
"""
4+
5+
6+
7+
import lldb
8+
from lldbsuite.test.decorators import *
9+
from lldbsuite.test.lldbtest import *
10+
from lldbsuite.test import lldbutil
11+
12+
from functionalities.breakpoint.hardware_breakpoints.base import *
13+
14+
class WriteMemoryWithHWBreakpoint(HardwareBreakpointTestBase):
15+
mydir = TestBase.compute_mydir(__file__)
16+
17+
def does_not_support_hw_breakpoints(self):
18+
return not super().supports_hw_breakpoints()
19+
20+
@skipTestIfFn(does_not_support_hw_breakpoints)
21+
def test_copy_memory_with_hw_break(self):
22+
self.build()
23+
exe = self.getBuildArtifact("a.out")
24+
25+
# Create a target by the debugger.
26+
target = self.dbg.CreateTarget(exe)
27+
self.assertTrue(target, VALID_TARGET)
28+
29+
# Run the program and stop at entry.
30+
self.expect("process launch --stop-at-entry",
31+
patterns=["Process .* launched: .*a.out"])
32+
33+
process = target.GetProcess()
34+
self.assertTrue(process, PROCESS_IS_VALID)
35+
36+
# Set a hardware breakpoint.
37+
bp_id = lldbutil.run_break_set_by_symbol(self, "hw_break_function",
38+
extra_options="--hardware")
39+
40+
# Get breakpoint location from the breakpoint.
41+
location = target.FindBreakpointByID(bp_id).GetLocationAtIndex(0)
42+
self.assertTrue(location and location.IsResolved(),
43+
VALID_BREAKPOINT_LOCATION)
44+
45+
# Check that writing overlapping memory doesn't crash.
46+
address = location.GetLoadAddress()
47+
data = str("\x01\x02\x03\x04")
48+
error = lldb.SBError()
49+
50+
result = process.WriteMemory(address, data, error)
51+
self.assertTrue(error.Success() and result == len(bytes))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
static volatile int num = 1;
2+
3+
bool hw_break_function (int i) {
4+
return num == i;
5+
}
6+
7+
int main (int argc, char const *argv[]) {
8+
return hw_break_function(argc) ? 0 : 1;
9+
}

0 commit comments

Comments
 (0)