1 //===-- SoftwareBreakpoint.cpp ----------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Host/common/SoftwareBreakpoint.h"
12 #include "lldb/Core/Error.h"
13 #include "lldb/Core/Log.h"
14 #include "lldb/Host/Debug.h"
16 #include "lldb/Host/common/NativeProcessProtocol.h"
18 using namespace lldb_private;
20 // -------------------------------------------------------------------
22 // -------------------------------------------------------------------
24 Error SoftwareBreakpoint::CreateSoftwareBreakpoint(
25 NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint,
26 NativeBreakpointSP &breakpoint_sp) {
27 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
29 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
31 // Validate the address.
32 if (addr == LLDB_INVALID_ADDRESS)
33 return Error("SoftwareBreakpoint::%s invalid load address specified.",
36 // Ask the NativeProcessProtocol subclass to fill in the correct software
38 // trap for the breakpoint site.
39 size_t bp_opcode_size = 0;
40 const uint8_t *bp_opcode_bytes = NULL;
41 Error error = process.GetSoftwareBreakpointTrapOpcode(
42 size_hint, bp_opcode_size, bp_opcode_bytes);
46 log->Printf("SoftwareBreakpoint::%s failed to retrieve software "
47 "breakpoint trap opcode: %s",
48 __FUNCTION__, error.AsCString());
52 // Validate size of trap opcode.
53 if (bp_opcode_size == 0) {
55 log->Printf("SoftwareBreakpoint::%s failed to retrieve any trap opcodes",
57 return Error("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
58 "returned zero, unable to get breakpoint trap for address "
63 if (bp_opcode_size > MAX_TRAP_OPCODE_SIZE) {
65 log->Printf("SoftwareBreakpoint::%s cannot support %zu trapcode bytes, "
67 __FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
68 return Error("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
69 "returned too many trap opcode bytes: requires %zu but we "
70 "only support a max of %zu",
71 bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
74 // Validate that we received opcodes.
75 if (!bp_opcode_bytes) {
77 log->Printf("SoftwareBreakpoint::%s failed to retrieve trap opcode bytes",
79 return Error("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
80 "returned NULL trap opcode bytes, unable to get breakpoint "
81 "trap for address 0x%" PRIx64,
85 // Enable the breakpoint.
86 uint8_t saved_opcode_bytes[MAX_TRAP_OPCODE_SIZE];
87 error = EnableSoftwareBreakpoint(process, addr, bp_opcode_size,
88 bp_opcode_bytes, saved_opcode_bytes);
91 log->Printf("SoftwareBreakpoint::%s: failed to enable new breakpoint at "
93 __FUNCTION__, addr, error.AsCString());
98 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS",
101 // Set the breakpoint and verified it was written properly. Now
102 // create a breakpoint remover that understands how to undo this
104 breakpoint_sp.reset(new SoftwareBreakpoint(process, addr, saved_opcode_bytes,
105 bp_opcode_bytes, bp_opcode_size));
109 Error SoftwareBreakpoint::EnableSoftwareBreakpoint(
110 NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size,
111 const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes) {
112 assert(bp_opcode_size <= MAX_TRAP_OPCODE_SIZE &&
113 "bp_opcode_size out of valid range");
114 assert(bp_opcode_bytes && "bp_opcode_bytes is NULL");
115 assert(saved_opcode_bytes && "saved_opcode_bytes is NULL");
117 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
119 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
121 // Save the original opcodes by reading them so we can restore later.
122 size_t bytes_read = 0;
125 process.ReadMemory(addr, saved_opcode_bytes, bp_opcode_size, bytes_read);
128 log->Printf("SoftwareBreakpoint::%s failed to read memory while "
129 "attempting to set breakpoint: %s",
130 __FUNCTION__, error.AsCString());
134 // Ensure we read as many bytes as we expected.
135 if (bytes_read != bp_opcode_size) {
137 log->Printf("SoftwareBreakpoint::%s failed to read memory while "
138 "attempting to set breakpoint: attempted to read %zu bytes "
140 __FUNCTION__, bp_opcode_size, bytes_read);
141 return Error("SoftwareBreakpoint::%s failed to read memory while "
142 "attempting to set breakpoint: attempted to read %zu bytes "
144 __FUNCTION__, bp_opcode_size, bytes_read);
150 for (const uint8_t *read_byte = saved_opcode_bytes;
151 read_byte < saved_opcode_bytes + bp_opcode_size; ++read_byte) {
152 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
153 " ovewriting byte index %d (was 0x%hhx)",
154 __FUNCTION__, addr, i++, *read_byte);
158 // Write a software breakpoint in place of the original opcode.
159 size_t bytes_written = 0;
161 process.WriteMemory(addr, bp_opcode_bytes, bp_opcode_size, bytes_written);
164 log->Printf("SoftwareBreakpoint::%s failed to write memory while "
165 "attempting to set breakpoint: %s",
166 __FUNCTION__, error.AsCString());
170 // Ensure we wrote as many bytes as we expected.
171 if (bytes_written != bp_opcode_size) {
172 error.SetErrorStringWithFormat(
173 "SoftwareBreakpoint::%s failed write memory while attempting to set "
174 "breakpoint: attempted to write %zu bytes but only wrote %zu",
175 __FUNCTION__, bp_opcode_size, bytes_written);
177 log->PutCString(error.AsCString());
181 uint8_t verify_bp_opcode_bytes[MAX_TRAP_OPCODE_SIZE];
182 size_t verify_bytes_read = 0;
183 error = process.ReadMemory(addr, verify_bp_opcode_bytes, bp_opcode_size,
187 log->Printf("SoftwareBreakpoint::%s failed to read memory while "
188 "attempting to verify the breakpoint set: %s",
189 __FUNCTION__, error.AsCString());
193 // Ensure we read as many verification bytes as we expected.
194 if (verify_bytes_read != bp_opcode_size) {
196 log->Printf("SoftwareBreakpoint::%s failed to read memory while "
197 "attempting to verify breakpoint: attempted to read %zu "
198 "bytes but only read %zu",
199 __FUNCTION__, bp_opcode_size, verify_bytes_read);
200 return Error("SoftwareBreakpoint::%s failed to read memory while "
201 "attempting to verify breakpoint: attempted to read %zu bytes "
203 __FUNCTION__, bp_opcode_size, verify_bytes_read);
206 if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0) {
208 log->Printf("SoftwareBreakpoint::%s: verification of software breakpoint "
209 "writing failed - trap opcodes not successfully read back "
210 "after writing when setting breakpoint at 0x%" PRIx64,
212 return Error("SoftwareBreakpoint::%s: verification of software breakpoint "
213 "writing failed - trap opcodes not successfully read back "
214 "after writing when setting breakpoint at 0x%" PRIx64,
219 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS",
225 // -------------------------------------------------------------------
226 // instance-level members
227 // -------------------------------------------------------------------
229 SoftwareBreakpoint::SoftwareBreakpoint(NativeProcessProtocol &process,
231 const uint8_t *saved_opcodes,
232 const uint8_t *trap_opcodes,
234 : NativeBreakpoint(addr), m_process(process), m_saved_opcodes(),
235 m_trap_opcodes(), m_opcode_size(opcode_size) {
236 assert(opcode_size > 0 && "setting software breakpoint with no trap opcodes");
237 assert(opcode_size <= MAX_TRAP_OPCODE_SIZE && "trap opcode size too large");
239 ::memcpy(m_saved_opcodes, saved_opcodes, opcode_size);
240 ::memcpy(m_trap_opcodes, trap_opcodes, opcode_size);
243 Error SoftwareBreakpoint::DoEnable() {
244 return EnableSoftwareBreakpoint(m_process, m_addr, m_opcode_size,
245 m_trap_opcodes, m_saved_opcodes);
248 Error SoftwareBreakpoint::DoDisable() {
250 assert(m_addr && (m_addr != LLDB_INVALID_ADDRESS) &&
251 "can't remove a software breakpoint for an invalid address");
253 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
255 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__,
258 assert((m_opcode_size > 0) &&
259 "cannot restore opcodes when there are no opcodes");
261 if (m_opcode_size > 0) {
262 // Clear a software breakpoint instruction
263 uint8_t curr_break_op[MAX_TRAP_OPCODE_SIZE];
264 bool break_op_found = false;
265 assert(m_opcode_size <= sizeof(curr_break_op));
267 // Read the breakpoint opcode
268 size_t bytes_read = 0;
270 m_process.ReadMemory(m_addr, curr_break_op, m_opcode_size, bytes_read);
271 if (error.Success() && bytes_read < m_opcode_size) {
272 error.SetErrorStringWithFormat(
273 "SoftwareBreakpointr::%s addr=0x%" PRIx64
274 ": tried to read %zu bytes but only read %zu",
275 __FUNCTION__, m_addr, m_opcode_size, bytes_read);
277 if (error.Success()) {
279 // Make sure the breakpoint opcode exists at this address
280 if (::memcmp(curr_break_op, m_trap_opcodes, m_opcode_size) == 0) {
281 break_op_found = true;
282 // We found a valid breakpoint opcode at this address, now restore
284 size_t bytes_written = 0;
285 error = m_process.WriteMemory(m_addr, m_saved_opcodes, m_opcode_size,
287 if (error.Success() && bytes_written < m_opcode_size) {
288 error.SetErrorStringWithFormat(
289 "SoftwareBreakpoint::%s addr=0x%" PRIx64
290 ": tried to write %zu bytes but only wrote %zu",
291 __FUNCTION__, m_addr, m_opcode_size, bytes_written);
293 if (error.Success()) {
297 error.SetErrorString(
298 "Original breakpoint trap is no longer in memory.");
299 // Set verify to true and so we can check if the original opcode has
300 // already been restored
305 uint8_t verify_opcode[MAX_TRAP_OPCODE_SIZE];
306 assert(m_opcode_size <= sizeof(verify_opcode));
307 // Verify that our original opcode made it back to the inferior
309 size_t verify_bytes_read = 0;
310 error = m_process.ReadMemory(m_addr, verify_opcode, m_opcode_size,
312 if (error.Success() && verify_bytes_read < m_opcode_size) {
313 error.SetErrorStringWithFormat(
314 "SoftwareBreakpoint::%s addr=0x%" PRIx64
315 ": tried to read %zu verification bytes but only read %zu",
316 __FUNCTION__, m_addr, m_opcode_size, verify_bytes_read);
318 if (error.Success()) {
319 // compare the memory we just read with the original opcode
320 if (::memcmp(m_saved_opcodes, verify_opcode, m_opcode_size) == 0) {
324 for (const uint8_t *verify_byte = verify_opcode;
325 verify_byte < verify_opcode + m_opcode_size; ++verify_byte) {
326 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
327 " replaced byte index %d with 0x%hhx",
328 __FUNCTION__, m_addr, i++, *verify_byte);
330 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
332 __FUNCTION__, m_addr);
337 error.SetErrorString("Failed to restore original opcode.");
340 error.SetErrorString("Failed to read memory to verify that "
341 "breakpoint trap was restored.");
346 if (log && error.Fail())
347 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- FAILED: %s",
348 __FUNCTION__, m_addr, error.AsCString());
352 bool SoftwareBreakpoint::IsSoftwareBreakpoint() const { return true; }