forked from OSchip/llvm-project
lldb-test symbols: Add -file argument and the ability to dump global variables in a file
The motivation for this is to be able to Dwarf index ability to look up variables within a given compilation unit. It also fits in with the patch in progress at D47939, which will add the ability to look up funtions using file+line pairs. The verification of which lldb-test options can be used together was getting a bit unwieldy, so I moved the logic out into a separate function. llvm-svn: 334498
This commit is contained in:
parent
3d671248ab
commit
e6954cb2a1
|
@ -0,0 +1,3 @@
|
|||
namespace two {
|
||||
int foo;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// RUN: clang -g -c -o %t-1.o --target=x86_64-pc-linux %s
|
||||
// RUN: clang -g -c -o %t-2.o --target=x86_64-pc-linux %S/Inputs/find-variable-file-2.cpp
|
||||
// RUN: ld.lld %t-1.o %t-2.o -o %t
|
||||
// RUN: lldb-test symbols --file=find-variable-file.cpp --find=variable %t | \
|
||||
// RUN: FileCheck --check-prefix=ONE %s
|
||||
// RUN: lldb-test symbols --file=find-variable-file-2.cpp --find=variable %t | \
|
||||
// RUN: FileCheck --check-prefix=TWO %s
|
||||
|
||||
// ONE: Found 1 variables:
|
||||
namespace one {
|
||||
int foo;
|
||||
// ONE-DAG: name = "foo", type = {{.*}} (int), {{.*}} decl = find-variable-file.cpp:[[@LINE-1]]
|
||||
} // namespace one
|
||||
|
||||
extern "C" void _start() {}
|
||||
|
||||
// TWO: Found 1 variables:
|
||||
// TWO-DAG: name = "foo", {{.*}} decl = find-variable-file-2.cpp:2
|
|
@ -28,6 +28,8 @@ config.test_format = lit.formats.ShTest(execute_external)
|
|||
# suffixes: We only support unit tests
|
||||
config.suffixes = []
|
||||
|
||||
config.excludes = ['Inputs']
|
||||
|
||||
# test_source_root: The root path where tests are located.
|
||||
config.test_source_root = os.path.dirname(__file__)
|
||||
|
||||
|
|
|
@ -148,6 +148,10 @@ static FunctionNameType getFunctionNameFlags() {
|
|||
static cl::opt<bool> Verify("verify", cl::desc("Verify symbol information."),
|
||||
cl::sub(SymbolsSubcommand));
|
||||
|
||||
static cl::opt<std::string> File("file",
|
||||
cl::desc("File (compile unit) to search."),
|
||||
cl::sub(SymbolsSubcommand));
|
||||
|
||||
static Expected<CompilerDeclContext> getDeclContext(SymbolVendor &Vendor);
|
||||
|
||||
static Error findFunctions(lldb_private::Module &Module);
|
||||
|
@ -157,6 +161,7 @@ static Error findVariables(lldb_private::Module &Module);
|
|||
static Error dumpModule(lldb_private::Module &Module);
|
||||
static Error verify(lldb_private::Module &Module);
|
||||
|
||||
static Expected<Error (&)(lldb_private::Module &)> getAction();
|
||||
static int dumpSymbols(Debugger &Dbg);
|
||||
}
|
||||
|
||||
|
@ -197,6 +202,13 @@ int evaluateMemoryMapCommands(Debugger &Dbg);
|
|||
|
||||
} // namespace opts
|
||||
|
||||
template <typename... Args>
|
||||
static Error make_string_error(const char *Format, Args &&... args) {
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
llvm::formatv(Format, std::forward<Args>(args)...).str(),
|
||||
llvm::inconvertibleErrorCode());
|
||||
}
|
||||
|
||||
TargetSP opts::createTarget(Debugger &Dbg, const std::string &Filename) {
|
||||
TargetSP Target;
|
||||
Status ST =
|
||||
|
@ -312,14 +324,10 @@ opts::symbols::getDeclContext(SymbolVendor &Vendor) {
|
|||
return CompilerDeclContext();
|
||||
VariableList List;
|
||||
Vendor.FindGlobalVariables(ConstString(Context), nullptr, UINT32_MAX, List);
|
||||
if (List.Empty()) {
|
||||
return make_error<StringError>("Context search didn't find a match.",
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
if (List.GetSize() > 1) {
|
||||
return make_error<StringError>("Context search found multiple matches.",
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
if (List.Empty())
|
||||
return make_string_error("Context search didn't find a match.");
|
||||
if (List.GetSize() > 1)
|
||||
return make_string_error("Context search found multiple matches.");
|
||||
return List.GetVariableAtIndex(0)->GetDeclContext();
|
||||
}
|
||||
|
||||
|
@ -394,6 +402,22 @@ Error opts::symbols::findVariables(lldb_private::Module &Module) {
|
|||
RegularExpression RE(Name);
|
||||
assert(RE.IsValid());
|
||||
Vendor.FindGlobalVariables(RE, UINT32_MAX, List);
|
||||
} else if (!File.empty()) {
|
||||
CompUnitSP CU;
|
||||
for (size_t Ind = 0; !CU && Ind < Module.GetNumCompileUnits(); ++Ind) {
|
||||
CompUnitSP Candidate = Module.GetCompileUnitAtIndex(Ind);
|
||||
if (!Candidate || Candidate->GetFilename().GetStringRef() != File)
|
||||
continue;
|
||||
if (CU)
|
||||
return make_string_error("Multiple compile units for file `{0}` found.",
|
||||
File);
|
||||
CU = std::move(Candidate);
|
||||
}
|
||||
|
||||
if (!CU)
|
||||
return make_string_error("Compile unit `{0}` not found.", File);
|
||||
|
||||
List.AddVariables(CU->GetVariableList(true).get());
|
||||
} else {
|
||||
Expected<CompilerDeclContext> ContextOr = getDeclContext(Vendor);
|
||||
if (!ContextOr)
|
||||
|
@ -419,15 +443,11 @@ Error opts::symbols::dumpModule(lldb_private::Module &Module) {
|
|||
}
|
||||
|
||||
Error opts::symbols::verify(lldb_private::Module &Module) {
|
||||
SymbolVendor *plugin = Module.GetSymbolVendor();
|
||||
if (!plugin)
|
||||
return make_error<StringError>("Can't get a symbol vendor.",
|
||||
inconvertibleErrorCode());
|
||||
SymbolVendor &plugin = *Module.GetSymbolVendor();
|
||||
|
||||
SymbolFile *symfile = plugin->GetSymbolFile();
|
||||
SymbolFile *symfile = plugin.GetSymbolFile();
|
||||
if (!symfile)
|
||||
return make_error<StringError>("Can't get a symbol file.",
|
||||
inconvertibleErrorCode());
|
||||
return make_string_error("Module has no symbol file.");
|
||||
|
||||
uint32_t comp_units_count = symfile->GetNumCompileUnits();
|
||||
|
||||
|
@ -436,17 +456,14 @@ Error opts::symbols::verify(lldb_private::Module &Module) {
|
|||
for (uint32_t i = 0; i < comp_units_count; i++) {
|
||||
lldb::CompUnitSP comp_unit = symfile->ParseCompileUnitAtIndex(i);
|
||||
if (!comp_unit)
|
||||
return make_error<StringError>("Can't get a compile unit.",
|
||||
inconvertibleErrorCode());
|
||||
return make_string_error("Connot parse compile unit {0}.", i);
|
||||
|
||||
outs() << "Processing '" << comp_unit->GetFilename().AsCString() <<
|
||||
"' compile unit.\n";
|
||||
|
||||
LineTable *lt = comp_unit->GetLineTable();
|
||||
if (!lt)
|
||||
return make_error<StringError>(
|
||||
"Can't get a line table of a compile unit.",
|
||||
inconvertibleErrorCode());
|
||||
return make_string_error("Can't get a line table of a compile unit.");
|
||||
|
||||
uint32_t count = lt->GetSize();
|
||||
|
||||
|
@ -457,23 +474,18 @@ Error opts::symbols::verify(lldb_private::Module &Module) {
|
|||
|
||||
LineEntry le;
|
||||
if (!lt->GetLineEntryAtIndex(0, le))
|
||||
return make_error<StringError>(
|
||||
"Can't get a line entry of a compile unit",
|
||||
inconvertibleErrorCode());
|
||||
return make_string_error("Can't get a line entry of a compile unit.");
|
||||
|
||||
for (uint32_t i = 1; i < count; i++) {
|
||||
lldb::addr_t curr_end =
|
||||
le.range.GetBaseAddress().GetFileAddress() + le.range.GetByteSize();
|
||||
|
||||
if (!lt->GetLineEntryAtIndex(i, le))
|
||||
return make_error<StringError>(
|
||||
"Can't get a line entry of a compile unit",
|
||||
inconvertibleErrorCode());
|
||||
return make_string_error("Can't get a line entry of a compile unit");
|
||||
|
||||
if (curr_end > le.range.GetBaseAddress().GetFileAddress())
|
||||
return make_error<StringError>(
|
||||
"Line table of a compile unit is inconsistent",
|
||||
inconvertibleErrorCode());
|
||||
return make_string_error(
|
||||
"Line table of a compile unit is inconsistent.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -482,53 +494,69 @@ Error opts::symbols::verify(lldb_private::Module &Module) {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
int opts::symbols::dumpSymbols(Debugger &Dbg) {
|
||||
if (Verify && Find != FindType::None) {
|
||||
WithColor::error() << "Cannot both search and verify symbol information.\n";
|
||||
return 1;
|
||||
}
|
||||
if (Find != FindType::None && Regex && !Context.empty()) {
|
||||
WithColor::error()
|
||||
<< "Cannot search using both regular expressions and context.\n";
|
||||
return 1;
|
||||
}
|
||||
if ((Find == FindType::Type || Find == FindType::Namespace) && Regex) {
|
||||
WithColor::error() << "Cannot search for types and namespaces using "
|
||||
"regular expressions.\n";
|
||||
return 1;
|
||||
}
|
||||
if (Find == FindType::Function && Regex && getFunctionNameFlags() != 0) {
|
||||
WithColor::error() << "Cannot search for types using both regular "
|
||||
"expressions and function-flags.\n";
|
||||
return 1;
|
||||
}
|
||||
if (Regex && !RegularExpression(Name).IsValid()) {
|
||||
WithColor::error() << "`" << Name
|
||||
<< "` is not a valid regular expression.\n";
|
||||
return 1;
|
||||
Expected<Error (&)(lldb_private::Module &)> opts::symbols::getAction() {
|
||||
if (Verify) {
|
||||
if (Find != FindType::None)
|
||||
return make_string_error(
|
||||
"Cannot both search and verify symbol information.");
|
||||
if (Regex || !Context.empty() || !Name.empty() || !File.empty())
|
||||
return make_string_error("-regex, -context, -name and -file options are not "
|
||||
"applicable for symbol verification.");
|
||||
return verify;
|
||||
}
|
||||
|
||||
Error (*Action)(lldb_private::Module &);
|
||||
if (!Verify) {
|
||||
switch (Find) {
|
||||
case FindType::Function:
|
||||
Action = findFunctions;
|
||||
break;
|
||||
case FindType::Namespace:
|
||||
Action = findNamespaces;
|
||||
break;
|
||||
case FindType::Type:
|
||||
Action = findTypes;
|
||||
break;
|
||||
case FindType::Variable:
|
||||
Action = findVariables;
|
||||
break;
|
||||
case FindType::None:
|
||||
Action = dumpModule;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
Action = verify;
|
||||
if (Regex && !Context.empty())
|
||||
return make_string_error(
|
||||
"Cannot search using both regular expressions and context.");
|
||||
|
||||
if (Regex && !RegularExpression(Name).IsValid())
|
||||
return make_string_error("`{0}` is not a valid regular expression.", Name);
|
||||
|
||||
if (Regex + !Context.empty() + !File.empty() >= 2)
|
||||
return make_string_error(
|
||||
"Only one of -regex, -context and -file may be used simultaneously.");
|
||||
if (Regex && Name.empty())
|
||||
return make_string_error("-regex used without a -name");
|
||||
|
||||
switch (Find) {
|
||||
case FindType::None:
|
||||
if (!Context.empty() || !Name.empty() || !File.empty())
|
||||
return make_string_error(
|
||||
"Specify search type (-find) to use search options.");
|
||||
return dumpModule;
|
||||
|
||||
case FindType::Function:
|
||||
if (!File.empty())
|
||||
return make_string_error("Cannot search for functions by file name.");
|
||||
if (Regex && getFunctionNameFlags() != 0)
|
||||
return make_string_error("Cannot search for functions using both regular "
|
||||
"expressions and function-flags.");
|
||||
return findFunctions;
|
||||
|
||||
case FindType::Namespace:
|
||||
if (Regex || !File.empty())
|
||||
return make_string_error("Cannot search for namespaces using regular "
|
||||
"expressions or file names.");
|
||||
return findNamespaces;
|
||||
|
||||
case FindType::Type:
|
||||
if (Regex || !File.empty())
|
||||
return make_string_error("Cannot search for types using regular "
|
||||
"expressions or file names.");
|
||||
return findTypes;
|
||||
|
||||
case FindType::Variable:
|
||||
return findVariables;
|
||||
}
|
||||
}
|
||||
|
||||
int opts::symbols::dumpSymbols(Debugger &Dbg) {
|
||||
auto ActionOr = getAction();
|
||||
if (!ActionOr) {
|
||||
logAllUnhandledErrors(ActionOr.takeError(), WithColor::error(), "");
|
||||
return 1;
|
||||
}
|
||||
auto Action = *ActionOr;
|
||||
|
||||
int HadErrors = 0;
|
||||
for (const auto &File : InputFilenames) {
|
||||
|
@ -543,7 +571,7 @@ int opts::symbols::dumpSymbols(Debugger &Dbg) {
|
|||
HadErrors = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (Error E = Action(*ModulePtr)) {
|
||||
WithColor::error() << toString(std::move(E)) << "\n";
|
||||
HadErrors = 1;
|
||||
|
|
Loading…
Reference in New Issue