blob: bc04e80794a604c624a62da36ae2e304f5a6103c [file] [log] [blame]
// Copyright 2019 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/zxdb/console/commands/verb_ps.h"
#include <iomanip>
#include <optional>
#include <sstream>
#include "src/developer/debug/zxdb/client/session.h"
#include "src/developer/debug/zxdb/console/command.h"
#include "src/developer/debug/zxdb/console/console.h"
#include "src/developer/debug/zxdb/console/output_buffer.h"
#include "src/developer/debug/zxdb/console/verbs.h"
namespace zxdb {
namespace {
void OutputProcessTreeRecord(const debug_ipc::ProcessTreeRecord& rec, int indent,
OutputBuffer* output) {
output->Append(std::string(indent * 2, ' '));
switch (rec.type) {
case debug_ipc::ProcessTreeRecord::Type::kJob:
output->Append("j: ");
break;
case debug_ipc::ProcessTreeRecord::Type::kProcess:
output->Append("p: ");
break;
default:
output->Append("?: ");
break;
}
output->Append(Syntax::kSpecial, std::to_string(rec.koid));
output->Append(" " + rec.name + "\n");
for (const auto& child : rec.children)
OutputProcessTreeRecord(child, indent + 1, output);
}
// Recursively filters the given process tree. All jobs and processes that contain the given filter
// string in their name are matched. These are added to the result, along with any parent job nodes
// required to get to the matched records.
std::optional<debug_ipc::ProcessTreeRecord> FilterProcessTree(
const debug_ipc::ProcessTreeRecord& rec, const std::string& filter) {
debug_ipc::ProcessTreeRecord result;
for (const auto& child : rec.children) {
if (auto matched_child = FilterProcessTree(child, filter))
result.children.push_back(*matched_child);
}
// Return the node when it matches or any of its children do.
if (rec.name.find(filter) != std::string::npos || !result.children.empty()) {
result.type = rec.type;
result.koid = rec.koid;
result.name = rec.name;
return result;
}
return std::nullopt;
}
void OnListProcessesComplete(const std::string& filter, const Err& err,
const debug_ipc::ProcessTreeReply& reply) {
OutputBuffer out;
if (err.has_error()) {
out.Append(err);
} else if (filter.empty()) {
// Output everything.
OutputProcessTreeRecord(reply.root, 0, &out);
} else {
// Filter the results.
if (auto filtered = FilterProcessTree(reply.root, filter)) {
OutputProcessTreeRecord(*filtered, 0, &out);
} else {
out.Append("No processes or jobs matching \"" + filter + "\".\n");
}
}
Console::get()->Output(out);
}
const char kPsShortHelp[] = "ps: Prints the process tree of the debugged system.";
const char kPsHelp[] =
R"(ps [ <filter-string> ]
Prints the process tree of the debugged system.
If a filter-string is provided only jobs and processes whose names contain the
given case-sensitive substring. It does not support regular expressions.
Jobs are annotated with "j: <job koid>"
Processes are annotated with "p: <process koid>")";
Err RunVerbPs(ConsoleContext* context, const Command& cmd) {
std::string filter_string;
if (!cmd.args().empty())
filter_string = cmd.args()[0];
context->session()->system().GetProcessTree(
[filter_string](const Err& err, debug_ipc::ProcessTreeReply reply) {
OnListProcessesComplete(filter_string, err, reply);
});
return Err();
}
} // namespace
VerbRecord GetPsVerbRecord() {
VerbRecord record(&RunVerbPs, {"ps"}, kPsShortHelp, kPsHelp, CommandGroup::kGeneral);
record.param_type = VerbRecord::kOneParam; // Allow spaces in the filter string.
return record;
}
} // namespace zxdb