| // 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 |