blob: ce185177f2b9d114a5506cba29fbdf9bfed46135 [file] [log] [blame]
// Copyright 2018 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 "garnet/bin/zxdb/client/system_impl.h"
#include "garnet/bin/zxdb/client/breakpoint_impl.h"
#include "garnet/bin/zxdb/client/job_context_impl.h"
#include "garnet/bin/zxdb/client/process_impl.h"
#include "garnet/bin/zxdb/client/remote_api.h"
#include "garnet/bin/zxdb/client/session.h"
#include "garnet/bin/zxdb/client/system_observer.h"
#include "garnet/bin/zxdb/client/target_impl.h"
#include "garnet/lib/debug_ipc/helper/message_loop.h"
namespace zxdb {
SystemImpl::SystemImpl(Session* session)
: System(session), weak_factory_(this) {
AddNewTarget(std::make_unique<TargetImpl>(this));
AddNewJobContext(std::make_unique<JobContextImpl>(this));
// Forward all messages from the symbol index to our observers. It's OK to
// bind |this| because the symbol index is owned by |this|.
symbols_.build_id_index().set_information_callback(
[this](const std::string& msg) {
for (auto& observer : observers())
observer.OnSymbolIndexingInformation(msg);
});
}
SystemImpl::~SystemImpl() {
// Target destruction may depend on the symbol system. Ensure the targets
// get cleaned up first.
for (auto& target : targets_) {
// It's better if process destruction notifications are sent before target
// ones because the target owns the process. Because this class sends the
// target notifications, force the process destruction before doing
// anything.
target->ImplicitlyDetach();
for (auto& observer : observers())
observer.WillDestroyTarget(target.get());
}
targets_.clear();
}
ProcessImpl* SystemImpl::ProcessImplFromKoid(uint64_t koid) const {
for (const auto& target : targets_) {
ProcessImpl* process = target->process();
if (process && process->GetKoid() == koid)
return process;
}
return nullptr;
}
void SystemImpl::NotifyDidCreateProcess(Process* process) {
for (auto& observer : observers())
observer.GlobalDidCreateProcess(process);
}
void SystemImpl::NotifyWillDestroyProcess(Process* process) {
for (auto& observer : observers())
observer.GlobalWillDestroyProcess(process);
}
std::vector<TargetImpl*> SystemImpl::GetTargetImpls() const {
std::vector<TargetImpl*> result;
for (const auto& t : targets_)
result.push_back(t.get());
return result;
}
SystemSymbols* SystemImpl::GetSymbols() { return &symbols_; }
std::vector<Target*> SystemImpl::GetTargets() const {
std::vector<Target*> result;
result.reserve(targets_.size());
for (const auto& t : targets_)
result.push_back(t.get());
return result;
}
std::vector<JobContext*> SystemImpl::GetJobContexts() const {
std::vector<JobContext*> result;
result.reserve(job_contexts_.size());
for (const auto& t : job_contexts_)
result.push_back(t.get());
return result;
}
std::vector<Breakpoint*> SystemImpl::GetBreakpoints() const {
std::vector<Breakpoint*> result;
result.reserve(breakpoints_.size());
for (const auto& pair : breakpoints_) {
if (!pair.second->is_internal())
result.push_back(pair.second.get());
}
return result;
}
Process* SystemImpl::ProcessFromKoid(uint64_t koid) const {
return ProcessImplFromKoid(koid);
}
void SystemImpl::GetProcessTree(ProcessTreeCallback callback) {
session()->remote_api()->ProcessTree(debug_ipc::ProcessTreeRequest(),
std::move(callback));
}
Target* SystemImpl::CreateNewTarget(Target* clone) {
auto target = clone ? static_cast<TargetImpl*>(clone)->Clone(this)
: std::make_unique<TargetImpl>(this);
Target* to_return = target.get();
AddNewTarget(std::move(target));
return to_return;
}
JobContext* SystemImpl::CreateNewJobContext(JobContext* clone) {
auto job_context = clone ? static_cast<JobContextImpl*>(clone)->Clone(this)
: std::make_unique<JobContextImpl>(this);
JobContext* to_return = job_context.get();
AddNewJobContext(std::move(job_context));
return to_return;
}
Breakpoint* SystemImpl::CreateNewBreakpoint() {
auto owning = std::make_unique<BreakpointImpl>(session(), false);
uint32_t id = owning->backend_id();
Breakpoint* to_return = owning.get();
breakpoints_[id] = std::move(owning);
// Notify observers (may mutate breakpoint list).
for (auto& observer : observers())
observer.DidCreateBreakpoint(to_return);
return to_return;
}
Breakpoint* SystemImpl::CreateNewInternalBreakpoint() {
auto owning = std::make_unique<BreakpointImpl>(session(), true);
uint32_t id = owning->backend_id();
Breakpoint* to_return = owning.get();
breakpoints_[id] = std::move(owning);
return to_return;
}
void SystemImpl::DeleteBreakpoint(Breakpoint* breakpoint) {
BreakpointImpl* impl = static_cast<BreakpointImpl*>(breakpoint);
auto found = breakpoints_.find(impl->backend_id());
if (found == breakpoints_.end()) {
// Should always have found the breakpoint.
FXL_NOTREACHED();
return;
}
// Only notify observers for non-internal breakpoints.
if (!found->second->is_internal()) {
for (auto& observer : observers())
observer.WillDestroyBreakpoint(breakpoint);
}
breakpoints_.erase(found);
}
void SystemImpl::Pause() {
debug_ipc::PauseRequest request;
request.process_koid = 0; // 0 means all processes.
request.thread_koid = 0; // 0 means all threads.
session()->remote_api()->Pause(
request, std::function<void(const Err&, debug_ipc::PauseReply)>());
}
void SystemImpl::Continue() {
debug_ipc::ResumeRequest request;
request.process_koid = 0; // 0 means all processes.
request.how = debug_ipc::ResumeRequest::How::kContinue;
session()->remote_api()->Resume(
request, std::function<void(const Err&, debug_ipc::ResumeReply)>());
}
void SystemImpl::DidConnect() {
// Force reload the symbol mappings after connection. This needs to be done
// for every connection since a new image could have been compiled and
// launched which will have a different build ID file.
symbols_.build_id_index().ClearCache();
}
void SystemImpl::DidDisconnect() {
for (auto& target : targets_)
target->ImplicitlyDetach();
}
BreakpointImpl* SystemImpl::BreakpointImplForId(uint32_t id) {
auto found = breakpoints_.find(id);
if (found == breakpoints_.end())
return nullptr;
return found->second.get();
}
void SystemImpl::AddNewTarget(std::unique_ptr<TargetImpl> target) {
Target* for_observers = target.get();
targets_.push_back(std::move(target));
for (auto& observer : observers())
observer.DidCreateTarget(for_observers);
}
void SystemImpl::AddNewJobContext(std::unique_ptr<JobContextImpl> job_context) {
JobContext* for_observers = job_context.get();
job_contexts_.push_back(std::move(job_context));
for (auto& observer : observers())
observer.DidCreateJobContext(for_observers);
}
} // namespace zxdb