summaryrefslogtreecommitdiff
path: root/src/core/debugger/gdbstub.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/debugger/gdbstub.cpp')
-rw-r--r--src/core/debugger/gdbstub.cpp139
1 files changed, 118 insertions, 21 deletions
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp
index 52e76f659..f5e9a303d 100644
--- a/src/core/debugger/gdbstub.cpp
+++ b/src/core/debugger/gdbstub.cpp
@@ -112,6 +112,23 @@ void GDBStub::Stopped(Kernel::KThread* thread) {
112 SendReply(arch->ThreadStatus(thread, GDB_STUB_SIGTRAP)); 112 SendReply(arch->ThreadStatus(thread, GDB_STUB_SIGTRAP));
113} 113}
114 114
115void GDBStub::Watchpoint(Kernel::KThread* thread, const Kernel::DebugWatchpoint& watch) {
116 const auto status{arch->ThreadStatus(thread, GDB_STUB_SIGTRAP)};
117
118 switch (watch.type) {
119 case Kernel::DebugWatchpointType::Read:
120 SendReply(fmt::format("{}rwatch:{:x};", status, watch.start_address));
121 break;
122 case Kernel::DebugWatchpointType::Write:
123 SendReply(fmt::format("{}watch:{:x};", status, watch.start_address));
124 break;
125 case Kernel::DebugWatchpointType::ReadOrWrite:
126 default:
127 SendReply(fmt::format("{}awatch:{:x};", status, watch.start_address));
128 break;
129 }
130}
131
115std::vector<DebuggerAction> GDBStub::ClientData(std::span<const u8> data) { 132std::vector<DebuggerAction> GDBStub::ClientData(std::span<const u8> data) {
116 std::vector<DebuggerAction> actions; 133 std::vector<DebuggerAction> actions;
117 current_command.insert(current_command.end(), data.begin(), data.end()); 134 current_command.insert(current_command.end(), data.begin(), data.end());
@@ -278,41 +295,121 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction
278 case 'c': 295 case 'c':
279 actions.push_back(DebuggerAction::Continue); 296 actions.push_back(DebuggerAction::Continue);
280 break; 297 break;
281 case 'Z': { 298 case 'Z':
282 const auto addr_sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1}; 299 HandleBreakpointInsert(command);
283 const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; 300 break;
301 case 'z':
302 HandleBreakpointRemove(command);
303 break;
304 default:
305 SendReply(GDB_STUB_REPLY_EMPTY);
306 break;
307 }
308}
284 309
285 if (system.Memory().IsValidVirtualAddress(addr)) { 310enum class BreakpointType {
286 replaced_instructions[addr] = system.Memory().Read32(addr); 311 Software = 0,
287 system.Memory().Write32(addr, arch->BreakpointInstruction()); 312 Hardware = 1,
288 system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); 313 WriteWatch = 2,
314 ReadWatch = 3,
315 AccessWatch = 4,
316};
317
318void GDBStub::HandleBreakpointInsert(std::string_view command) {
319 const auto type{static_cast<BreakpointType>(strtoll(command.data(), nullptr, 16))};
320 const auto addr_sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1};
321 const auto size_sep{std::find(command.begin() + addr_sep, command.end(), ',') -
322 command.begin() + 1};
323 const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))};
324 const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))};
325
326 if (!system.Memory().IsValidVirtualAddressRange(addr, size)) {
327 SendReply(GDB_STUB_REPLY_ERR);
328 return;
329 }
289 330
290 SendReply(GDB_STUB_REPLY_OK); 331 bool success{};
291 } else { 332
292 SendReply(GDB_STUB_REPLY_ERR); 333 switch (type) {
293 } 334 case BreakpointType::Software:
335 replaced_instructions[addr] = system.Memory().Read32(addr);
336 system.Memory().Write32(addr, arch->BreakpointInstruction());
337 system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32));
338 success = true;
339 break;
340 case BreakpointType::WriteWatch:
341 success = system.CurrentProcess()->InsertWatchpoint(system, addr, size,
342 Kernel::DebugWatchpointType::Write);
294 break; 343 break;
344 case BreakpointType::ReadWatch:
345 success = system.CurrentProcess()->InsertWatchpoint(system, addr, size,
346 Kernel::DebugWatchpointType::Read);
347 break;
348 case BreakpointType::AccessWatch:
349 success = system.CurrentProcess()->InsertWatchpoint(
350 system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
351 break;
352 case BreakpointType::Hardware:
353 default:
354 SendReply(GDB_STUB_REPLY_EMPTY);
355 return;
356 }
357
358 if (success) {
359 SendReply(GDB_STUB_REPLY_OK);
360 } else {
361 SendReply(GDB_STUB_REPLY_ERR);
295 } 362 }
296 case 'z': { 363}
297 const auto addr_sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1}; 364
298 const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; 365void GDBStub::HandleBreakpointRemove(std::string_view command) {
366 const auto type{static_cast<BreakpointType>(strtoll(command.data(), nullptr, 16))};
367 const auto addr_sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1};
368 const auto size_sep{std::find(command.begin() + addr_sep, command.end(), ',') -
369 command.begin() + 1};
370 const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))};
371 const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))};
372
373 if (!system.Memory().IsValidVirtualAddressRange(addr, size)) {
374 SendReply(GDB_STUB_REPLY_ERR);
375 return;
376 }
377
378 bool success{};
299 379
380 switch (type) {
381 case BreakpointType::Software: {
300 const auto orig_insn{replaced_instructions.find(addr)}; 382 const auto orig_insn{replaced_instructions.find(addr)};
301 if (system.Memory().IsValidVirtualAddress(addr) && 383 if (orig_insn != replaced_instructions.end()) {
302 orig_insn != replaced_instructions.end()) {
303 system.Memory().Write32(addr, orig_insn->second); 384 system.Memory().Write32(addr, orig_insn->second);
304 system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); 385 system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32));
305 replaced_instructions.erase(addr); 386 replaced_instructions.erase(addr);
306 387 success = true;
307 SendReply(GDB_STUB_REPLY_OK);
308 } else {
309 SendReply(GDB_STUB_REPLY_ERR);
310 } 388 }
311 break; 389 break;
312 } 390 }
391 case BreakpointType::WriteWatch:
392 success = system.CurrentProcess()->RemoveWatchpoint(system, addr, size,
393 Kernel::DebugWatchpointType::Write);
394 break;
395 case BreakpointType::ReadWatch:
396 success = system.CurrentProcess()->RemoveWatchpoint(system, addr, size,
397 Kernel::DebugWatchpointType::Read);
398 break;
399 case BreakpointType::AccessWatch:
400 success = system.CurrentProcess()->RemoveWatchpoint(
401 system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
402 break;
403 case BreakpointType::Hardware:
313 default: 404 default:
314 SendReply(GDB_STUB_REPLY_EMPTY); 405 SendReply(GDB_STUB_REPLY_EMPTY);
315 break; 406 return;
407 }
408
409 if (success) {
410 SendReply(GDB_STUB_REPLY_OK);
411 } else {
412 SendReply(GDB_STUB_REPLY_ERR);
316 } 413 }
317} 414}
318 415