blob: 3d57b7dd6b88fc6f5509d25d70c789073bb9a9aa [file] [log] [blame]
Todd Fialaaf245d12014-06-30 21:05:18 +00001//===-- SoftwareBreakpoint.cpp ----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Chaoren Lin2fe1d0a2015-02-03 01:51:38 +000010#include "lldb/Host/common/SoftwareBreakpoint.h"
Todd Fialaaf245d12014-06-30 21:05:18 +000011
12#include "lldb/Core/Error.h"
13#include "lldb/Core/Log.h"
14#include "lldb/Host/Debug.h"
Todd Fialaaf245d12014-06-30 21:05:18 +000015
Chaoren Lin2fe1d0a2015-02-03 01:51:38 +000016#include "lldb/Host/common/NativeProcessProtocol.h"
Todd Fialaaf245d12014-06-30 21:05:18 +000017
18using namespace lldb_private;
19
20// -------------------------------------------------------------------
21// static members
22// -------------------------------------------------------------------
23
Kate Stoneb9c1b512016-09-06 20:57:50 +000024Error SoftwareBreakpoint::CreateSoftwareBreakpoint(
25 NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint,
26 NativeBreakpointSP &breakpoint_sp) {
27 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
28 if (log)
29 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
30
31 // Validate the address.
32 if (addr == LLDB_INVALID_ADDRESS)
33 return Error("SoftwareBreakpoint::%s invalid load address specified.",
34 __FUNCTION__);
35
36 // Ask the NativeProcessProtocol subclass to fill in the correct software
37 // breakpoint
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);
43
44 if (error.Fail()) {
Todd Fialaaf245d12014-06-30 21:05:18 +000045 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +000046 log->Printf("SoftwareBreakpoint::%s failed to retrieve software "
47 "breakpoint trap opcode: %s",
48 __FUNCTION__, error.AsCString());
49 return error;
50 }
Todd Fialaaf245d12014-06-30 21:05:18 +000051
Kate Stoneb9c1b512016-09-06 20:57:50 +000052 // Validate size of trap opcode.
53 if (bp_opcode_size == 0) {
Todd Fialaaf245d12014-06-30 21:05:18 +000054 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +000055 log->Printf("SoftwareBreakpoint::%s failed to retrieve any trap opcodes",
56 __FUNCTION__);
57 return Error("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
58 "returned zero, unable to get breakpoint trap for address "
59 "0x%" PRIx64,
60 addr);
61 }
Todd Fialaaf245d12014-06-30 21:05:18 +000062
Kate Stoneb9c1b512016-09-06 20:57:50 +000063 if (bp_opcode_size > MAX_TRAP_OPCODE_SIZE) {
64 if (log)
Zachary Turner5a8ad4592016-10-05 17:07:34 +000065 log->Printf("SoftwareBreakpoint::%s cannot support %zu trapcode bytes, "
66 "max size is %zu",
Kate Stoneb9c1b512016-09-06 20:57:50 +000067 __FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
68 return Error("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
Zachary Turner5a8ad4592016-10-05 17:07:34 +000069 "returned too many trap opcode bytes: requires %zu but we "
70 "only support a max of %zu",
Kate Stoneb9c1b512016-09-06 20:57:50 +000071 bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
72 }
73
74 // Validate that we received opcodes.
75 if (!bp_opcode_bytes) {
76 if (log)
77 log->Printf("SoftwareBreakpoint::%s failed to retrieve trap opcode bytes",
78 __FUNCTION__);
79 return Error("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
80 "returned NULL trap opcode bytes, unable to get breakpoint "
81 "trap for address 0x%" PRIx64,
82 addr);
83 }
84
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);
89 if (error.Fail()) {
90 if (log)
91 log->Printf("SoftwareBreakpoint::%s: failed to enable new breakpoint at "
92 "0x%" PRIx64 ": %s",
93 __FUNCTION__, addr, error.AsCString());
94 return error;
95 }
96
97 if (log)
98 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS",
99 __FUNCTION__, addr);
100
101 // Set the breakpoint and verified it was written properly. Now
102 // create a breakpoint remover that understands how to undo this
103 // breakpoint.
104 breakpoint_sp.reset(new SoftwareBreakpoint(process, addr, saved_opcode_bytes,
105 bp_opcode_bytes, bp_opcode_size));
Mehdi Aminic1edf562016-11-11 04:29:25 +0000106 return Error();
Todd Fialaaf245d12014-06-30 21:05:18 +0000107}
108
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109Error 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");
Todd Fialaaf245d12014-06-30 21:05:18 +0000116
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
118 if (log)
119 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
120
121 // Save the original opcodes by reading them so we can restore later.
122 size_t bytes_read = 0;
123
124 Error error =
125 process.ReadMemory(addr, saved_opcode_bytes, bp_opcode_size, bytes_read);
126 if (error.Fail()) {
Todd Fialaaf245d12014-06-30 21:05:18 +0000127 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128 log->Printf("SoftwareBreakpoint::%s failed to read memory while "
129 "attempting to set breakpoint: %s",
130 __FUNCTION__, error.AsCString());
131 return error;
132 }
Todd Fialaaf245d12014-06-30 21:05:18 +0000133
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134 // Ensure we read as many bytes as we expected.
135 if (bytes_read != bp_opcode_size) {
Todd Fialae231efa2014-10-08 17:14:53 +0000136 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000137 log->Printf("SoftwareBreakpoint::%s failed to read memory while "
Zachary Turner5a8ad4592016-10-05 17:07:34 +0000138 "attempting to set breakpoint: attempted to read %zu bytes "
139 "but only read %zu",
140 __FUNCTION__, bp_opcode_size, bytes_read);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000141 return Error("SoftwareBreakpoint::%s failed to read memory while "
Zachary Turner5a8ad4592016-10-05 17:07:34 +0000142 "attempting to set breakpoint: attempted to read %zu bytes "
143 "but only read %zu",
144 __FUNCTION__, bp_opcode_size, bytes_read);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000145 }
Todd Fialae231efa2014-10-08 17:14:53 +0000146
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 // Log what we read.
148 if (log) {
149 int i = 0;
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);
Todd Fialaaf245d12014-06-30 21:05:18 +0000155 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000156 }
Todd Fialaaf245d12014-06-30 21:05:18 +0000157
Kate Stoneb9c1b512016-09-06 20:57:50 +0000158 // Write a software breakpoint in place of the original opcode.
159 size_t bytes_written = 0;
160 error =
161 process.WriteMemory(addr, bp_opcode_bytes, bp_opcode_size, bytes_written);
162 if (error.Fail()) {
Todd Fialaaf245d12014-06-30 21:05:18 +0000163 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000164 log->Printf("SoftwareBreakpoint::%s failed to write memory while "
165 "attempting to set breakpoint: %s",
166 __FUNCTION__, error.AsCString());
167 return error;
168 }
Todd Fialaaf245d12014-06-30 21:05:18 +0000169
Kate Stoneb9c1b512016-09-06 20:57:50 +0000170 // 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 "
Zachary Turner5a8ad4592016-10-05 17:07:34 +0000174 "breakpoint: attempted to write %zu bytes but only wrote %zu",
175 __FUNCTION__, bp_opcode_size, bytes_written);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000176 if (log)
177 log->PutCString(error.AsCString());
178 return error;
179 }
180
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,
184 verify_bytes_read);
185 if (error.Fail()) {
186 if (log)
187 log->Printf("SoftwareBreakpoint::%s failed to read memory while "
188 "attempting to verify the breakpoint set: %s",
189 __FUNCTION__, error.AsCString());
190 return error;
191 }
192
193 // Ensure we read as many verification bytes as we expected.
194 if (verify_bytes_read != bp_opcode_size) {
195 if (log)
196 log->Printf("SoftwareBreakpoint::%s failed to read memory while "
Zachary Turner5a8ad4592016-10-05 17:07:34 +0000197 "attempting to verify breakpoint: attempted to read %zu "
198 "bytes but only read %zu",
199 __FUNCTION__, bp_opcode_size, verify_bytes_read);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000200 return Error("SoftwareBreakpoint::%s failed to read memory while "
Zachary Turner5a8ad4592016-10-05 17:07:34 +0000201 "attempting to verify breakpoint: attempted to read %zu bytes "
202 "but only read %zu",
203 __FUNCTION__, bp_opcode_size, verify_bytes_read);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000204 }
205
206 if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0) {
207 if (log)
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,
211 __FUNCTION__, addr);
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,
215 __FUNCTION__, addr);
216 }
217
218 if (log)
219 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS",
220 __FUNCTION__, addr);
221
Mehdi Aminic1edf562016-11-11 04:29:25 +0000222 return Error();
Todd Fialaaf245d12014-06-30 21:05:18 +0000223}
224
225// -------------------------------------------------------------------
226// instance-level members
227// -------------------------------------------------------------------
228
Kate Stoneb9c1b512016-09-06 20:57:50 +0000229SoftwareBreakpoint::SoftwareBreakpoint(NativeProcessProtocol &process,
230 lldb::addr_t addr,
231 const uint8_t *saved_opcodes,
232 const uint8_t *trap_opcodes,
233 size_t opcode_size)
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");
Todd Fialaaf245d12014-06-30 21:05:18 +0000238
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239 ::memcpy(m_saved_opcodes, saved_opcodes, opcode_size);
240 ::memcpy(m_trap_opcodes, trap_opcodes, opcode_size);
Todd Fialaaf245d12014-06-30 21:05:18 +0000241}
242
Kate Stoneb9c1b512016-09-06 20:57:50 +0000243Error SoftwareBreakpoint::DoEnable() {
244 return EnableSoftwareBreakpoint(m_process, m_addr, m_opcode_size,
245 m_trap_opcodes, m_saved_opcodes);
Todd Fialaaf245d12014-06-30 21:05:18 +0000246}
247
Kate Stoneb9c1b512016-09-06 20:57:50 +0000248Error SoftwareBreakpoint::DoDisable() {
249 Error error;
250 assert(m_addr && (m_addr != LLDB_INVALID_ADDRESS) &&
251 "can't remove a software breakpoint for an invalid address");
Todd Fialaaf245d12014-06-30 21:05:18 +0000252
Kate Stoneb9c1b512016-09-06 20:57:50 +0000253 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
254 if (log)
255 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__,
256 m_addr);
Todd Fialaaf245d12014-06-30 21:05:18 +0000257
Kate Stoneb9c1b512016-09-06 20:57:50 +0000258 assert((m_opcode_size > 0) &&
259 "cannot restore opcodes when there are no opcodes");
Todd Fialaaf245d12014-06-30 21:05:18 +0000260
Kate Stoneb9c1b512016-09-06 20:57:50 +0000261 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));
Todd Fialaaf245d12014-06-30 21:05:18 +0000266
Kate Stoneb9c1b512016-09-06 20:57:50 +0000267 // Read the breakpoint opcode
268 size_t bytes_read = 0;
269 error =
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
Zachary Turner5a8ad4592016-10-05 17:07:34 +0000274 ": tried to read %zu bytes but only read %zu",
275 __FUNCTION__, m_addr, m_opcode_size, bytes_read);
Todd Fialaaf245d12014-06-30 21:05:18 +0000276 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000277 if (error.Success()) {
278 bool verify = false;
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
283 // the saved opcode.
284 size_t bytes_written = 0;
285 error = m_process.WriteMemory(m_addr, m_saved_opcodes, m_opcode_size,
286 bytes_written);
287 if (error.Success() && bytes_written < m_opcode_size) {
288 error.SetErrorStringWithFormat(
289 "SoftwareBreakpoint::%s addr=0x%" PRIx64
Zachary Turner5a8ad4592016-10-05 17:07:34 +0000290 ": tried to write %zu bytes but only wrote %zu",
291 __FUNCTION__, m_addr, m_opcode_size, bytes_written);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000292 }
293 if (error.Success()) {
294 verify = true;
295 }
296 } else {
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
301 verify = true;
302 }
Todd Fialaaf245d12014-06-30 21:05:18 +0000303
Kate Stoneb9c1b512016-09-06 20:57:50 +0000304 if (verify) {
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
308
309 size_t verify_bytes_read = 0;
310 error = m_process.ReadMemory(m_addr, verify_opcode, m_opcode_size,
311 verify_bytes_read);
312 if (error.Success() && verify_bytes_read < m_opcode_size) {
313 error.SetErrorStringWithFormat(
314 "SoftwareBreakpoint::%s addr=0x%" PRIx64
Zachary Turner5a8ad4592016-10-05 17:07:34 +0000315 ": tried to read %zu verification bytes but only read %zu",
316 __FUNCTION__, m_addr, m_opcode_size, verify_bytes_read);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000317 }
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) {
321 // SUCCESS
322 if (log) {
323 int i = 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);
329 }
330 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
331 " -- SUCCESS",
332 __FUNCTION__, m_addr);
333 }
334 return error;
335 } else {
336 if (break_op_found)
337 error.SetErrorString("Failed to restore original opcode.");
338 }
339 } else
340 error.SetErrorString("Failed to read memory to verify that "
341 "breakpoint trap was restored.");
342 }
343 }
344 }
345
346 if (log && error.Fail())
347 log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- FAILED: %s",
348 __FUNCTION__, m_addr, error.AsCString());
349 return error;
Todd Fialaaf245d12014-06-30 21:05:18 +0000350}
351
Kate Stoneb9c1b512016-09-06 20:57:50 +0000352bool SoftwareBreakpoint::IsSoftwareBreakpoint() const { return true; }