blob: 3c0046355ee4a6c9b2268f47eecae861abb0cb77 [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_info.h"
#include "llvm/Demangle/Demangle.h"
#include "src/developer/debug/zxdb/client/frame.h"
#include "src/developer/debug/zxdb/client/process.h"
#include "src/developer/debug/zxdb/client/target.h"
#include "src/developer/debug/zxdb/common/string_util.h"
#include "src/developer/debug/zxdb/console/command.h"
#include "src/developer/debug/zxdb/console/console.h"
#include "src/developer/debug/zxdb/console/format_name.h"
#include "src/developer/debug/zxdb/console/format_symbol.h"
#include "src/developer/debug/zxdb/console/output_buffer.h"
#include "src/developer/debug/zxdb/console/verbs.h"
#include "src/developer/debug/zxdb/expr/eval_context.h"
#include "src/developer/debug/zxdb/expr/expr_parser.h"
#include "src/developer/debug/zxdb/expr/find_name.h"
#include "src/developer/debug/zxdb/expr/found_name.h"
#include "src/developer/debug/zxdb/symbols/code_block.h"
#include "src/developer/debug/zxdb/symbols/location.h"
#include "src/lib/fxl/strings/string_printf.h"
namespace zxdb {
namespace {
constexpr int kDwarfExprSwitch = 1;
const char kSymInfoShortHelp[] = "sym-info: Print information about a symbol.";
const char kSymInfoHelp[] =
R"(sym-info <name>
Displays information about a given named symbol.
It will also show the demangled name if the input is a mangled symbol.
Options
)" DWARF_EXPR_COMMAND_SWTICH_HELP
R"(
Example
sym-info i
thread 1 frame 4 sym-info i
)";
// Demangles specifically for sym-info (this attempts to filter out simple type remapping which
// would normally be desirable for a generic demangler). Returns a nullopt on failure.
std::optional<std::string> DemangleForSymInfo(const ParsedIdentifier& identifier) {
std::string full_input = identifier.GetFullNameNoQual();
if (full_input.empty() || full_input[0] != '_') {
// Filter out all names that don't start with underscores. sym-info is mostly used to look up
// functions and variables. Functions should be demangled, but variables shouldn't. The problem
// is that some common variables like "f" and "i" demangle to "float" and "int" respectively
// which is not what the user wants. By only unmangling when things start with an underscore,
// we mostly restrict to mangled function names.
return std::nullopt;
}
return llvm::demangle(full_input);
}
Err RunVerbSymInfo(ConsoleContext* context, const Command& cmd) {
if (cmd.args().empty())
return Err("sym-info expects the name of the symbol to look up.");
ParsedIdentifier identifier;
Err err = ExprParser::ParseIdentifier(cmd.args()[0], &identifier);
if (err.has_error())
return err;
// See if it looks mangled.
OutputBuffer out;
if (std::optional<std::string> demangled = DemangleForSymInfo(identifier)) {
out.Append(Syntax::kHeading, "Demangled name: ");
// Output the demangled name as a colored identifier if possible.
ParsedIdentifier demangled_identifier;
if (ExprParser::ParseIdentifier(*demangled, &demangled_identifier).has_error()) {
// Not parseable as an identifier, just use the raw string.
out.Append(*demangled);
} else {
out.Append(FormatIdentifier(demangled_identifier, FormatIdentifierOptions()));
// Use the demangled name to do the lookup.
//
// TODO(brettw) this might need to be revisited if the index supports lookup by mangled name.
// It would probably be best to look up both variants and compute the union.
//
// TODO(brettw) generally function lookup from this point will fail because our looker-upper
// doesn't support function parameters, but the denamgled output will include the parameter
// types or at least "()".
identifier = std::move(demangled_identifier);
}
out.Append("\n\n");
}
ProcessSymbols* process_symbols = nullptr;
FindNameContext find_context;
if (cmd.target()->GetProcess()) {
process_symbols = cmd.target()->GetProcess()->GetSymbols();
if (cmd.frame()) {
find_context = cmd.frame()->GetEvalContext()->GetFindNameContext();
} else {
// This command can support querying symbols without a current stack frame, in which case it
// will do a global search of names in the current process.
find_context = FindNameContext(process_symbols);
}
} else {
// Non-running process. Can do some lookup for some things.
find_context = FindNameContext(cmd.target()->GetSymbols());
}
FindNameOptions find_opts(FindNameOptions::kAllKinds);
find_opts.max_results = std::numeric_limits<size_t>::max();
std::vector<FoundName> found_items;
FindName(find_context, find_opts, identifier, &found_items);
ErrOr<FormatSymbolOptions> opts = GetFormatSymbolOptionsFromCommand(cmd, kDwarfExprSwitch);
if (opts.has_error())
return opts.err();
bool found_item = false;
for (const FoundName& found : found_items) {
switch (found.kind()) {
case FoundName::kNone:
continue;
case FoundName::kVariable:
out.Append(FormatSymbol(process_symbols, found.variable(), opts.value()));
break;
case FoundName::kMemberVariable:
out.Append(FormatSymbol(process_symbols, found.member().data_member(), opts.value()));
break;
case FoundName::kNamespace:
// Probably useless to display info on a namespace.
continue;
case FoundName::kTemplate:
// TODO(brettw) it would be nice to list all template specializations here.
continue;
case FoundName::kType:
out.Append(FormatSymbol(process_symbols, found.type().get(), opts.value()));
break;
case FoundName::kFunction:
out.Append(FormatSymbol(process_symbols, found.function().get(), opts.value()));
break;
case FoundName::kOtherSymbol:
out.Append(FormatSymbol(process_symbols, found.other_symbol().get(), opts.value()));
break;
}
found_item = true;
out.Append("\n");
}
if (!found_item) {
out.Append("No symbol \"");
out.Append(FormatIdentifier(identifier, FormatIdentifierOptions()));
out.Append("\" found in the current context.\n");
}
if (!out.empty())
Console::get()->Output(out);
return Err();
}
} // namespace
VerbRecord GetSymInfoVerbRecord() {
VerbRecord sym_info(&RunVerbSymInfo, {"sym-info"}, kSymInfoShortHelp, kSymInfoHelp,
CommandGroup::kSymbol);
SwitchRecord dwarf_expr_switch(kDwarfExprSwitch, true, "dwarf-expr");
sym_info.switches = {dwarf_expr_switch};
// Accept just one arg and allow for spaces in it.
sym_info.param_type = VerbRecord::kOneParam;
return sym_info;
}
} // namespace zxdb