blob: a6b284dc1d12b03e36e1ef3c1ec9c70cf85ad03c [file] [log] [blame]
// Copyright 2023 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 "src/developer/debug/debug_agent/linux_thread_handle.h"
#include <map>
#include "src/developer/debug/debug_agent/linux_suspend_handle.h"
#include "src/developer/debug/debug_agent/linux_utils.h"
#include "src/developer/debug/shared/logging/logging.h"
namespace debug_agent {
LinuxThreadHandle::LinuxThreadHandle(fxl::RefPtr<LinuxTask> task) : task_(std::move(task)) {}
std::string LinuxThreadHandle::GetName() const { return linux::GetStatus(task_->pid())["Name"]; }
ThreadHandle::State LinuxThreadHandle::GetState() const {
auto state = linux::ThreadStateFromLinuxState(linux::GetStatus(task_->pid())["State"]);
if (!state)
return State(debug_ipc::ThreadRecord::State::kDead);
return *state;
}
std::unique_ptr<SuspendHandle> LinuxThreadHandle::Suspend() {
DEBUG_LOG(Thread) << "Suspending thread " << task_->pid();
return std::make_unique<LinuxSuspendHandle>(task_);
}
bool LinuxThreadHandle::WaitForSuspension(TickTimePoint deadline) const {
// Linux suspensions are synchronous so we never need to wait for one.
return true;
}
debug_ipc::ThreadRecord LinuxThreadHandle::GetThreadRecord(zx_koid_t process_koid) const {
DEBUG_LOG(Thread) << "LinuxThreadHandle::GetThreadRecord";
auto map = linux::GetStatus(task_->pid());
debug_ipc::ThreadRecord record;
record.id = {.process = process_koid, .thread = static_cast<uint64_t>(task_->pid())};
record.name = map["Name"];
if (auto state = linux::ThreadStateFromLinuxState(map["State"])) {
record.state = state->state;
record.blocked_reason = state->blocked_reason;
} else {
record.state = debug_ipc::ThreadRecord::State::kDead;
}
return record;
}
std::optional<GeneralRegisters> LinuxThreadHandle::GetGeneralRegisters() const {
if (auto result = linux::ReadGeneralRegisters(task_->pid())) {
DEBUG_LOG(Thread) << "General registers IP = " << std::hex << "0x" << result->rip;
return GeneralRegisters(*result);
}
return std::nullopt;
}
void LinuxThreadHandle::SetGeneralRegisters(const GeneralRegisters& regs) {
linux::WriteGeneralRegisters(task_->pid(), regs.GetNativeRegisters());
}
std::optional<DebugRegisters> LinuxThreadHandle::GetDebugRegisters() const {
// TODO(brettw) implement this.
return std::nullopt;
}
bool LinuxThreadHandle::SetDebugRegisters(const DebugRegisters& regs) {
// TODO(brettw) implement this.
return false;
}
void LinuxThreadHandle::SetSingleStep(bool single_step) {
DEBUG_LOG(Thread) << "LinuxThreadHandle::SetSingleStep " << single_step;
task_->set_single_step(single_step);
}
std::vector<debug::RegisterValue> LinuxThreadHandle::ReadRegisters(
const std::vector<debug::RegisterCategory>& cats_to_get) const {
// TODO(brettw) implement this.
return {};
}
std::vector<debug::RegisterValue> LinuxThreadHandle::WriteRegisters(
const std::vector<debug::RegisterValue>& regs) {
// TODO(brettw) implement this.
return {};
}
bool LinuxThreadHandle::InstallHWBreakpoint(uint64_t address) {
// TODO(brettw) implement this.
return false;
}
bool LinuxThreadHandle::UninstallHWBreakpoint(uint64_t address) {
// TODO(brettw) implement this.
return false;
}
std::optional<WatchpointInfo> LinuxThreadHandle::InstallWatchpoint(
debug_ipc::BreakpointType type, const debug::AddressRange& range) {
// TODO(brettw) implement this.
return std::nullopt;
}
bool LinuxThreadHandle::UninstallWatchpoint(const debug::AddressRange& range) {
// TODO(brettw) implement this.
return false;
}
} // namespace debug_agent