| // Copyright 2016 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "breakpoint.h" |
| |
| #include <cinttypes> |
| |
| #include "lib/fxl/logging.h" |
| #include "lib/fxl/strings/string_printf.h" |
| |
| namespace inferior_control { |
| |
| Breakpoint::Breakpoint(uintptr_t address, size_t kind) |
| : address_(address), kind_(kind) {} |
| |
| ProcessBreakpoint::ProcessBreakpoint(uintptr_t address, size_t kind, |
| ProcessBreakpointSet* owner) |
| : Breakpoint(address, kind), owner_(owner) { |
| FXL_DCHECK(owner_); |
| } |
| |
| SoftwareBreakpoint::SoftwareBreakpoint(uintptr_t address, size_t kind, |
| ProcessBreakpointSet* owner) |
| : ProcessBreakpoint(address, kind, owner) {} |
| |
| SoftwareBreakpoint::~SoftwareBreakpoint() { |
| if (IsInserted()) |
| Remove(); |
| } |
| |
| ProcessBreakpointSet::ProcessBreakpointSet(Process* process) |
| : process_(process) { |
| FXL_DCHECK(process_); |
| } |
| |
| bool ProcessBreakpointSet::InsertSoftwareBreakpoint(uintptr_t address, |
| size_t kind) { |
| if (breakpoints_.find(address) != breakpoints_.end()) { |
| FXL_LOG(ERROR) << fxl::StringPrintf( |
| "Breakpoint already inserted at address: 0x%" PRIxPTR, address); |
| return false; |
| } |
| |
| std::unique_ptr<ProcessBreakpoint> breakpoint( |
| new SoftwareBreakpoint(address, kind, this)); |
| if (!breakpoint->Insert()) { |
| FXL_LOG(ERROR) << "Failed to insert software breakpoint"; |
| return false; |
| } |
| |
| breakpoints_[address] = std::move(breakpoint); |
| return true; |
| } |
| |
| bool ProcessBreakpointSet::RemoveSoftwareBreakpoint(uintptr_t address) { |
| auto iter = breakpoints_.find(address); |
| if (iter == breakpoints_.end()) { |
| FXL_LOG(ERROR) << fxl::StringPrintf( |
| "No breakpoint inserted at address: 0x%" PRIxPTR, address); |
| return false; |
| } |
| |
| if (!iter->second->Remove()) { |
| FXL_LOG(ERROR) << "Failed to remove breakpoint"; |
| return false; |
| } |
| |
| breakpoints_.erase(iter); |
| return true; |
| } |
| |
| ThreadBreakpoint::ThreadBreakpoint(uintptr_t address, size_t kind, |
| ThreadBreakpointSet* owner) |
| : Breakpoint(address, kind), owner_(owner) { |
| FXL_DCHECK(owner_); |
| } |
| |
| SingleStepBreakpoint::SingleStepBreakpoint(uintptr_t address, |
| ThreadBreakpointSet* owner) |
| : ThreadBreakpoint(address, 0 /*TODO:type?*/, owner) {} |
| |
| SingleStepBreakpoint::~SingleStepBreakpoint() { |
| if (IsInserted()) |
| Remove(); |
| } |
| |
| ThreadBreakpointSet::ThreadBreakpointSet(Thread* thread) : thread_(thread) { |
| FXL_DCHECK(thread_); |
| } |
| |
| bool ThreadBreakpointSet::InsertSingleStepBreakpoint(uintptr_t address) { |
| if (single_step_breakpoint_) { |
| FXL_LOG(ERROR) << fxl::StringPrintf( |
| "S/S bkpt already inserted at 0x%" PRIxPTR |
| ", requested address: 0x%" PRIxPTR, |
| single_step_breakpoint_->address(), address); |
| return false; |
| } |
| |
| std::unique_ptr<ThreadBreakpoint> breakpoint( |
| new SingleStepBreakpoint(address, this)); |
| if (!breakpoint->Insert()) { |
| FXL_LOG(ERROR) << "Failed to insert s/s bkpt"; |
| return false; |
| } |
| |
| single_step_breakpoint_ = std::move(breakpoint); |
| return true; |
| } |
| |
| bool ThreadBreakpointSet::RemoveSingleStepBreakpoint() { |
| if (!single_step_breakpoint_) { |
| FXL_LOG(ERROR) << fxl::StringPrintf("No s/s bkpt inserted"); |
| return false; |
| } |
| |
| single_step_breakpoint_.reset(); |
| return true; |
| } |
| |
| bool ThreadBreakpointSet::SingleStepBreakpointInserted() { |
| return !!single_step_breakpoint_; |
| } |
| |
| } // namespace inferior_control |