|  | // 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/format_target.h" | 
|  |  | 
|  | #include "src/developer/debug/zxdb/client/process.h" | 
|  | #include "src/developer/debug/zxdb/client/session.h" | 
|  | #include "src/developer/debug/zxdb/console/command_utils.h" | 
|  | #include "src/developer/debug/zxdb/console/console_context.h" | 
|  | #include "src/developer/debug/zxdb/console/format_table.h" | 
|  | #include "src/developer/debug/zxdb/console/string_util.h" | 
|  | #include "src/lib/fxl/strings/string_printf.h" | 
|  |  | 
|  | namespace zxdb { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Returns the process name of the given target, depending on the running | 
|  | // process or the current app name, as applicable. | 
|  | std::string GetTargetName(const Target* target) { | 
|  | // When running, use the object name if any. | 
|  | std::string name; | 
|  | if (target->GetState() == Target::State::kRunning) | 
|  | name = target->GetProcess()->GetName(); | 
|  |  | 
|  | // Otherwise fall back to the program name which is the first arg. | 
|  | if (name.empty()) { | 
|  | const std::vector<std::string>& args = target->GetArgs(); | 
|  | if (!args.empty()) | 
|  | name += args[0]; | 
|  | } | 
|  | return name; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | OutputBuffer FormatTarget(ConsoleContext* context, const Target* target) { | 
|  | OutputBuffer out("Process "); | 
|  | out.Append(Syntax::kSpecial, std::to_string(context->IdForTarget(target))); | 
|  |  | 
|  | out.Append(Syntax::kVariable, " state"); | 
|  | out.Append("=" + FormatConsoleString(TargetStateToString(target->GetState())) + " "); | 
|  |  | 
|  | if (target->GetState() == Target::State::kRunning) { | 
|  | out.Append(Syntax::kVariable, "koid"); | 
|  | out.Append("=" + std::to_string(target->GetProcess()->GetKoid()) + " "); | 
|  | } | 
|  |  | 
|  | out.Append(Syntax::kVariable, "name"); | 
|  | out.Append("=" + FormatConsoleString(GetTargetName(target))); | 
|  |  | 
|  | return out; | 
|  | } | 
|  |  | 
|  | OutputBuffer FormatTargetList(ConsoleContext* context, int indent) { | 
|  | auto targets = context->session()->system().GetTargets(); | 
|  |  | 
|  | int active_target_id = context->GetActiveTargetId(); | 
|  |  | 
|  | // Sort by ID. | 
|  | std::vector<std::pair<int, Target*>> id_targets; | 
|  | for (auto& target : targets) | 
|  | id_targets.push_back(std::make_pair(context->IdForTarget(target), target)); | 
|  | std::sort(id_targets.begin(), id_targets.end()); | 
|  |  | 
|  | std::string indent_str(indent, ' '); | 
|  |  | 
|  | std::vector<std::vector<std::string>> rows; | 
|  | for (const auto& pair : id_targets) { | 
|  | rows.emplace_back(); | 
|  | std::vector<std::string>& row = rows.back(); | 
|  |  | 
|  | // "Current process" marker (or nothing). | 
|  | if (pair.first == active_target_id) | 
|  | row.push_back(indent_str + GetCurrentRowMarker()); | 
|  | else | 
|  | row.push_back(indent_str); | 
|  |  | 
|  | // ID. | 
|  | row.push_back(std::to_string(pair.first)); | 
|  |  | 
|  | // State and koid (if running). | 
|  | row.push_back(TargetStateToString(pair.second->GetState())); | 
|  | if (pair.second->GetState() == Target::State::kRunning) { | 
|  | row.push_back(std::to_string(pair.second->GetProcess()->GetKoid())); | 
|  | } else { | 
|  | row.emplace_back(); | 
|  | } | 
|  |  | 
|  | row.push_back(GetTargetName(pair.second)); | 
|  | } | 
|  |  | 
|  | OutputBuffer out; | 
|  | FormatTable({ColSpec(Align::kLeft), ColSpec(Align::kRight, 0, "#", 0, Syntax::kSpecial), | 
|  | ColSpec(Align::kLeft, 0, "State"), ColSpec(Align::kRight, 0, "Koid"), | 
|  | ColSpec(Align::kLeft, 0, "Name")}, | 
|  | rows, &out); | 
|  | return out; | 
|  | } | 
|  |  | 
|  | const char* TargetStateToString(Target::State state) { | 
|  | switch (state) { | 
|  | case Target::State::kNone: | 
|  | return "Not running"; | 
|  | case Target::State::kStarting: | 
|  | return "Starting"; | 
|  | case Target::State::kAttaching: | 
|  | return "Attaching"; | 
|  | case Target::State::kRunning: | 
|  | return "Running"; | 
|  | } | 
|  | FX_NOTREACHED(); | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | }  // namespace zxdb |