blob: 35750261950b222b5b074a13a21c9e3ffedfe903 [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/debug_agent/system_info.h"
#include <fcntl.h>
#include <fuchsia/sysinfo/c/fidl.h>
#include <lib/fdio/util.h>
#include <lib/zx/channel.h>
#include <lib/zx/job.h>
#include <lib/zx/process.h>
#include <unistd.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/object.h>
#include "garnet/bin/debug_agent/object_util.h"
#include "lib/fxl/logging.h"
namespace debug_agent {
namespace {
// TODO(brettw) this is based on the code in Zircon's task-utils which uses
// this hack to get the root job handle. It will likely need to be updated
// when a better way to get the root job is found.
zx::job GetRootJob() {
int fd = open("/dev/misc/sysinfo", O_RDWR);
if (fd < 0) {
FXL_NOTREACHED();
return zx::job();
}
zx::channel channel;
zx_status_t status =
fdio_get_service_handle(fd, channel.reset_and_get_address());
if (status != ZX_OK) {
FXL_NOTREACHED();
return zx::job();
}
zx_handle_t root_job;
zx_status_t fidl_status =
fuchsia_sysinfo_DeviceGetRootJob(channel.get(), &status, &root_job);
if (fidl_status != ZX_OK || status != ZX_OK) {
FXL_NOTREACHED();
return zx::job();
}
return zx::job(root_job);
}
debug_ipc::ProcessTreeRecord GetProcessTreeRecord(
const zx::object_base& object, debug_ipc::ProcessTreeRecord::Type type) {
debug_ipc::ProcessTreeRecord result;
result.type = type;
result.koid = KoidForObject(object);
result.name = NameForObject(object);
if (type == debug_ipc::ProcessTreeRecord::Type::kJob) {
std::vector<zx::process> child_procs = GetChildProcesses(object.get());
std::vector<zx::job> child_jobs = GetChildJobs(object.get());
result.children.reserve(child_procs.size() + child_jobs.size());
for (const auto& job : child_jobs) {
result.children.push_back(
GetProcessTreeRecord(job, debug_ipc::ProcessTreeRecord::Type::kJob));
}
for (const auto& proc : child_procs) {
result.children.push_back(GetProcessTreeRecord(
proc, debug_ipc::ProcessTreeRecord::Type::kProcess));
}
}
return result;
}
// Searches the process tree rooted at "job" for a process with the given
// koid. If found, puts it in *out* and returns true.
bool FindProcess(const zx::job& job, zx_koid_t search_for, zx::process* out) {
for (auto& proc : GetChildProcesses(job.get())) {
if (KoidForObject(proc) == search_for) {
*out = std::move(proc);
return true;
}
}
for (const auto& job : GetChildJobs(job.get())) {
if (FindProcess(job, search_for, out))
return true;
}
return false;
}
// Searches root job for a job with the given
// koid. If found, puts it in *out* and returns true.
bool FindJob(zx::job root_job, zx_koid_t search_for, zx::job* out) {
if (KoidForObject(root_job) == search_for) {
out->reset(root_job.release());
return true;
}
auto child_jobs = GetChildJobs(root_job.get());
for (auto& child_job : child_jobs) {
if (FindJob(zx::job(child_job.release()), search_for, out))
return true;
}
return false;
}
} // namespace
zx_status_t GetProcessTree(debug_ipc::ProcessTreeRecord* root) {
*root = GetProcessTreeRecord(GetRootJob(),
debug_ipc::ProcessTreeRecord::Type::kJob);
return ZX_OK;
}
zx::process GetProcessFromKoid(zx_koid_t koid) {
zx::process result;
FindProcess(GetRootJob(), koid, &result);
return result;
}
zx::job GetJobFromKoid(zx_koid_t koid) {
zx::job result;
FindJob(GetRootJob(), koid, &result);
return result;
}
} // namespace debug_agent