blob: 072b9707a60adac285b805b8a3e8e403557c39f6 [file] [log] [blame]
// Copyright 2020 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_sym_stat.h"
#include "src/developer/debug/zxdb/client/process.h"
#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/format_table.h"
#include "src/developer/debug/zxdb/console/output_buffer.h"
#include "src/developer/debug/zxdb/console/verbs.h"
#include "src/developer/debug/zxdb/symbols/module_symbol_status.h"
#include "src/developer/debug/zxdb/symbols/process_symbols.h"
#include "src/developer/debug/zxdb/symbols/system_symbols.h"
#include "src/lib/fxl/strings/string_printf.h"
namespace zxdb {
namespace {
constexpr int kDumpIndexSwitch = 1;
const char kSymStatShortHelp[] = "sym-stat: Print process symbol status.";
const char kSymStatHelp[] =
R"(sym-stat [ --dump-index ]
Prints out symbol information.
With no arguments, this refreshes the symbol index and shows global
information and information for the current (or specified) process.
The global information includes the symbol search paths and how many files are
indexed from each location. When a symbol path is a "build-id" directory
hierarchy, the output prints "folder" since these are not indexed in advance.
Instead, build-id folders are searched for a matching file name on demand.
If there is a current process the output will includes which libraries are
loaded, how many symbols each has, and where the symbol file is located.
Symbol troubleshooting
Processes with zero or very few symbols likely indicate the file has had the
symbols stripped (there are sometimes a few symbols even in stripped
binaries). Make sure an unstripped binary exists in a directory in the
"symbol-paths" setting and restart either the debugged program or the
debugger.
To append to the symbol search path, run for example:
set symbol-paths += /home/you/project/out/debug/exe.unstripped
or use the "-s" command-line flag. See "get symbol-paths" for more information
on this setting and to view the current list.
Arguments
--dump-index
Dumps the symbol index which maps build IDs to local file paths. This
can be useful for debugging cases of missing symbols.
Note that this does not print out the information from "build-id" folders
(denoted "folder" in the sym-stat output). These are loaded on-demand by
searching for a file name with the corresponding build ID.
Example
sym-stat
process 2 sym-stat
sym-stat --dump-index
)";
void SummarizeProcessSymbolStatus(ConsoleContext* context, Process* process, OutputBuffer* out) {
// Get modules sorted by name.
std::vector<ModuleSymbolStatus> modules = process->GetSymbols()->GetStatus();
std::sort(
modules.begin(), modules.end(),
[](const ModuleSymbolStatus& a, const ModuleSymbolStatus& b) { return a.name < b.name; });
out->Append(Syntax::kHeading, fxl::StringPrintf("\nProcess %d symbol status\n\n",
context->IdForTarget(process->GetTarget())));
for (const auto& module : modules) {
out->Append(Syntax::kHeading, " " + module.name + "\n");
out->Append(fxl::StringPrintf(" Base: 0x%" PRIx64 "\n", module.base));
out->Append(" Build ID: " + module.build_id);
if (context->session()->system().HasDownload(module.build_id)) {
out->Append(Syntax::kWarning, " (Downloading...)");
}
out->Append("\n");
if (module.symbols_loaded) {
out->Append(" Symbols loaded: Yes\n Symbol file: ");
out->Append(Syntax::kFileName, module.symbol_file);
out->Append(module.files_indexed ? Syntax::kNormal : Syntax::kError,
fxl::StringPrintf("\n Source files indexed: %zu", module.files_indexed));
out->Append(module.functions_indexed ? Syntax::kNormal : Syntax::kError,
fxl::StringPrintf("\n Symbols indexed: %zu", module.functions_indexed));
} else {
out->Append(Syntax::kError, " Symbols loaded: No");
}
out->Append("\n\n");
}
if (modules.empty())
out->Append(Syntax::kError, " No known modules.\n");
out->Append(Syntax::kWarning, " 👉 ");
out->Append(Syntax::kComment, "Use \"libs\" to refresh the module list from the process.");
out->Append(Syntax::kNormal, "\n\n");
}
void DumpIndexOverview(SystemSymbols* system_symbols, OutputBuffer* out) {
out->Append(Syntax::kHeading, "Symbol index status\n\n");
out->Append(Syntax::kComment, " This command just refreshed the index.\n");
std::vector<std::vector<OutputBuffer>> table;
auto index_status = system_symbols->build_id_index().GetStatus();
if (index_status.empty()) {
out->Append(Syntax::kError, " No symbol locations are indexed.");
out->Append(
"\n\n Use the command-line switch \"zxdb -s <path>\" or the option \"symbol-paths\"\n"
" (see \"get/set symbol-paths\") to specify the location of your symbols.\n\n");
} else {
out->Append(Syntax::kComment,
" Use \"sym-stat --dump-index\" to see the individual mappings.\n\n");
for (const auto& pair : index_status) {
auto& row = table.emplace_back();
auto syntax = pair.second ? Syntax::kNormal : Syntax::kError;
if (pair.second != BuildIDIndex::kStatusIsFolder) {
row.emplace_back(syntax, std::to_string(pair.second));
} else {
row.emplace_back(syntax, "(folder)");
}
row.emplace_back(syntax, pair.first);
}
FormatTable(
{ColSpec(Align::kRight, 0, "Indexed", 2), ColSpec(Align::kLeft, 0, "Source path", 1)},
table, out);
}
}
void DumpBuildIdIndex(SystemSymbols* system_symbols, OutputBuffer* out) {
const auto& build_id_to_files = system_symbols->build_id_index().build_id_to_files();
if (build_id_to_files.empty()) {
out->Append(Syntax::kError, " No build IDs found.\n");
} else {
for (const auto& [id, files] : build_id_to_files)
out->Append(fxl::StringPrintf("%s %s\n", id.c_str(), files.debug_info.c_str()));
}
out->Append("\n");
}
Err RunVerbSymStat(ConsoleContext* context, const Command& cmd) {
Err err = cmd.ValidateNouns({Noun::kProcess});
if (err.has_error())
return err;
if (!cmd.args().empty())
return Err("\"sym-stat\" takes no arguments.");
SystemSymbols* system_symbols = context->session()->system().GetSymbols();
OutputBuffer out;
if (cmd.HasSwitch(kDumpIndexSwitch)) {
DumpBuildIdIndex(system_symbols, &out);
} else {
// Force an update of the symbol index.
system_symbols->build_id_index().ClearCache();
DumpIndexOverview(system_symbols, &out);
// Process symbol status (if any).
if (cmd.target() && cmd.target()->GetProcess())
SummarizeProcessSymbolStatus(context, cmd.target()->GetProcess(), &out);
}
Console* console = Console::get();
console->Output(out);
return Err();
}
} // namespace
VerbRecord GetSymStatVerbRecord() {
VerbRecord sym_stat(&RunVerbSymStat, {"sym-stat"}, kSymStatShortHelp, kSymStatHelp,
CommandGroup::kSymbol);
sym_stat.switches.emplace_back(kDumpIndexSwitch, false, "dump-index", 0);
return sym_stat;
}
} // namespace zxdb