[Lldb-commits] [lldb] r331447 - lldb-test symbols: Add ability to do name-based lookup

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Thu May 3 03:57:16 PDT 2018


Author: labath
Date: Thu May  3 03:57:16 2018
New Revision: 331447

URL: http://llvm.org/viewvc/llvm-project?rev=331447&view=rev
Log:
lldb-test symbols: Add ability to do name-based lookup

Summary:
lldb-test already had the ability to dump all symbol information in a
module. This is interesting, but it can be too verbose, and it also does
not use the same APIs that lldb uses to query symbol information. The
last part is interesting to me now, because I am about to add DWARF v5
debug_names support, which needs to implement these APIs.

This patch adds a set of arguments to lldb-test, which modify it's
behavior from dumping all symbols to dumping only the requested
information:
- --find={function,namespace,type,variable} - search for the given
  kind of objects.

- --name - the name to search for.

- --regex - whether to treat the "name" as a regular expression. This is
  not available for all lookup types (we do not have the required APIs
  for namespaces and types).

- --context - specifies the context, which can be used to restrict the
  search. This argument takes a variable name (which must be defined and
  be unique), and we then use the context that this variable is defined
  in as the search context.

- --function-flags={auto,full,base,method,selector} - a set of flags to
  further restrict the search for function symbols.

Together, these flags and their combinations cover the main SymbolFile
entry points which I will need to modify for the accelerator table
support, and so I plan to do most of the regression testing this way.
(I've also found this a useful tool for exploration of what the given
APIs are supposed to do.)

I add a couple of tests to demonstrate the usage of the usage of the
various options, and also an xfailed test which demonstrates a bug I
found while playing with this. The only requirement for these tests is
the presence of lld -- the should run on any platform which is able to
build lldb.

These tests use c++ code as input, but this isn't a requirement. It is also
possible to use IR, assembly or json to create the test module.

Reviewers: davide, zturner, asmith, JDevlieghere, clayborg, alexshap

Subscribers: mgorny, aprantl, lldb-commits

Differential Revision: https://reviews.llvm.org/D46318

Added:
    lldb/trunk/lit/SymbolFile/DWARF/
    lldb/trunk/lit/SymbolFile/DWARF/find-basic-function.cpp
    lldb/trunk/lit/SymbolFile/DWARF/find-basic-namespace.cpp
    lldb/trunk/lit/SymbolFile/DWARF/find-basic-type.cpp
    lldb/trunk/lit/SymbolFile/DWARF/find-basic-variable.cpp
    lldb/trunk/lit/SymbolFile/DWARF/find-type-in-function.cpp
    lldb/trunk/lit/SymbolFile/DWARF/lit.local.cfg
Modified:
    lldb/trunk/include/lldb/Symbol/VariableList.h
    lldb/trunk/lit/CMakeLists.txt
    lldb/trunk/lit/lit.cfg
    lldb/trunk/lit/lit.site.cfg.in
    lldb/trunk/tools/lldb-test/lldb-test.cpp

Modified: lldb/trunk/include/lldb/Symbol/VariableList.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/VariableList.h?rev=331447&r1=331446&r2=331447&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/VariableList.h (original)
+++ lldb/trunk/include/lldb/Symbol/VariableList.h Thu May  3 03:57:16 2018
@@ -66,6 +66,7 @@ public:
   size_t MemorySize() const;
 
   size_t GetSize() const;
+  bool Empty() const { return m_variables.empty(); }
 
 protected:
   typedef std::vector<lldb::VariableSP> collection;

Modified: lldb/trunk/lit/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/CMakeLists.txt?rev=331447&r1=331446&r2=331447&view=diff
==============================================================================
--- lldb/trunk/lit/CMakeLists.txt (original)
+++ lldb/trunk/lit/CMakeLists.txt Thu May  3 03:57:16 2018
@@ -18,6 +18,24 @@ endif ()
 string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_LIBS_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR})
 string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TOOLS_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR})
 
+set(LLDB_TEST_DEPS
+  LLDBUnitTests
+  dsymutil
+  lldb
+  lldb-test
+  llvm-config
+  llvm-mc
+  llvm-objcopy
+  )
+
+if(TARGET lld)
+  list(APPEND LLDB_TEST_DEPS lld)
+  set(LLDB_HAVE_LLD 1)
+else()
+  set(LLDB_HAVE_LLD 0)
+endif()
+
+
 if(BUILD_SHARED_LIBS)
   set(ENABLE_SHARED 1)
 else()
@@ -36,16 +54,6 @@ configure_lit_site_cfg(
   ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
   )
 
-set(LLDB_TEST_DEPS
-  LLDBUnitTests
-  dsymutil
-  lldb
-  lldb-test
-  llvm-config
-  llvm-mc
-  llvm-objcopy
-  )
-
 if(NOT LLDB_BUILT_STANDALONE)
   list(APPEND LLDB_TEST_DEPS FileCheck not yaml2obj)
 endif()

Added: lldb/trunk/lit/SymbolFile/DWARF/find-basic-function.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/DWARF/find-basic-function.cpp?rev=331447&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/DWARF/find-basic-function.cpp (added)
+++ lldb/trunk/lit/SymbolFile/DWARF/find-basic-function.cpp Thu May  3 03:57:16 2018
@@ -0,0 +1,67 @@
+// REQUIRES: lld
+
+// RUN: clang %s -g -c -o %t.o --target=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t
+// RUN: lldb-test symbols --name=foo --find=function --function-flags=base %t | \
+// RUN:   FileCheck --check-prefix=BASE %s
+// RUN: lldb-test symbols --name=foo --find=function --function-flags=method %t | \
+// RUN:   FileCheck --check-prefix=METHOD %s
+// RUN: lldb-test symbols --name=foo --find=function --function-flags=full %t | \
+// RUN:   FileCheck --check-prefix=FULL %s
+// RUN: lldb-test symbols --name=foo --context=context --find=function --function-flags=base %t | \
+// RUN:   FileCheck --check-prefix=CONTEXT %s
+// RUN: lldb-test symbols --name=not_there --find=function %t | \
+// RUN:   FileCheck --check-prefix=EMPTY %s
+
+// BASE: Found 4 functions:
+// BASE-DAG: name = "foo()", mangled = "_Z3foov"
+// BASE-DAG: name = "foo(int)", mangled = "_Z3fooi"
+// BASE-DAG: name = "bar::foo()", mangled = "_ZN3bar3fooEv"
+// BASE-DAG: name = "bar::baz::foo()", mangled = "_ZN3bar3baz3fooEv"
+
+// METHOD: Found 3 functions:
+// METHOD-DAG: name = "sbar::foo()", mangled = "_ZN4sbar3fooEv"
+// METHOD-DAG: name = "sbar::foo(int)", mangled = "_ZN4sbar3fooEi"
+// METHOD-DAG: name = "ffbar()::sbar::foo()", mangled = "_ZZ5ffbarvEN4sbar3fooEv"
+
+// FULL: Found 2 functions:
+// FULL-DAG: name = "foo()", mangled = "_Z3foov"
+// FULL-DAG: name = "foo(int)", mangled = "_Z3fooi"
+
+// CONTEXT: Found 1 functions:
+// CONTEXT-DAG: name = "bar::foo()", mangled = "_ZN3bar3fooEv"
+
+// EMPTY: Found 0 functions:
+
+void foo() {}
+void foo(int) {}
+
+namespace bar {
+int context;
+void foo() {}
+namespace baz {
+void foo() {}
+} // namespace baz
+} // namespace bar
+
+struct foo {};
+void fbar(struct foo) {}
+
+void Foo() {}
+
+struct sbar {
+  void foo();
+  static void foo(int);
+};
+void sbar::foo() {}
+void sbar::foo(int) {}
+
+void ffbar() {
+  struct sbar {
+    void foo() {}
+  };
+  sbar a;
+  a.foo();
+}
+
+extern "C" void _start() {}

Added: lldb/trunk/lit/SymbolFile/DWARF/find-basic-namespace.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/DWARF/find-basic-namespace.cpp?rev=331447&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/DWARF/find-basic-namespace.cpp (added)
+++ lldb/trunk/lit/SymbolFile/DWARF/find-basic-namespace.cpp Thu May  3 03:57:16 2018
@@ -0,0 +1,29 @@
+// REQUIRES: lld
+
+// RUN: clang %s -g -c -o %t.o --target=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t
+// RUN: lldb-test symbols --name=foo --find=namespace %t | \
+// RUN:   FileCheck --check-prefix=FOO %s
+// RUN: lldb-test symbols --name=foo --find=namespace --context=context %t | \
+// RUN:   FileCheck --check-prefix=CONTEXT %s
+// RUN: lldb-test symbols --name=not_there --find=namespace %t | \
+// RUN:   FileCheck --check-prefix=EMPTY %s
+
+// FOO: Found namespace: foo
+
+// CONTEXT: Found namespace: bar::foo
+
+// EMPTY: Namespace not found.
+
+namespace foo {
+int X;
+}
+
+namespace bar {
+int context;
+namespace foo {
+int X;
+}
+} // namespace bar
+
+extern "C" void _start() {}

Added: lldb/trunk/lit/SymbolFile/DWARF/find-basic-type.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/DWARF/find-basic-type.cpp?rev=331447&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/DWARF/find-basic-type.cpp (added)
+++ lldb/trunk/lit/SymbolFile/DWARF/find-basic-type.cpp Thu May  3 03:57:16 2018
@@ -0,0 +1,38 @@
+// REQUIRES: lld
+
+// RUN: clang %s -g -c -o %t.o --target=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t
+// RUN: lldb-test symbols --name=foo --find=type %t | \
+// RUN:   FileCheck --check-prefix=NAME %s
+// RUN: lldb-test symbols --name=foo --context=context --find=type %t | \
+// RUN:   FileCheck --check-prefix=CONTEXT %s
+// RUN: lldb-test symbols --name=not_there --find=type %t | \
+// RUN:   FileCheck --check-prefix=EMPTY %s
+
+// EMPTY: Found 0 types:
+// NAME: Found 4 types:
+// CONTEXT: Found 1 types:
+struct foo { };
+// NAME-DAG: name = "foo", {{.*}} decl = find-basic-type.cpp:[[@LINE-1]]
+
+namespace bar {
+int context;
+struct foo {};
+// NAME-DAG: name = "foo", {{.*}} decl = find-basic-type.cpp:[[@LINE-1]]
+// CONTEXT-DAG: name = "foo", {{.*}} decl = find-basic-type.cpp:[[@LINE-2]]
+namespace baz {
+struct foo {};
+// NAME-DAG: name = "foo", {{.*}} decl = find-basic-type.cpp:[[@LINE-1]]
+}
+}
+
+struct sbar {
+  struct foo {};
+// NAME-DAG: name = "foo", {{.*}} decl = find-basic-type.cpp:[[@LINE-1]]
+};
+
+struct foobar {};
+
+struct Foo {};
+
+extern "C" void _start(foo, bar::foo, bar::baz::foo, sbar::foo, foobar, Foo) {}

Added: lldb/trunk/lit/SymbolFile/DWARF/find-basic-variable.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/DWARF/find-basic-variable.cpp?rev=331447&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/DWARF/find-basic-variable.cpp (added)
+++ lldb/trunk/lit/SymbolFile/DWARF/find-basic-variable.cpp Thu May  3 03:57:16 2018
@@ -0,0 +1,55 @@
+// REQUIRES: lld
+
+// RUN: clang %s -g -c -o %t.o --target=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t
+// RUN: lldb-test symbols --name=foo --find=variable --context=context %t | \
+// RUN:   FileCheck --check-prefix=CONTEXT %s
+// RUN: lldb-test symbols --name=foo --find=variable %t | \
+// RUN:   FileCheck --check-prefix=NAME %s
+// RUN: lldb-test symbols --regex --name=foo --find=variable %t | \
+// RUN:   FileCheck --check-prefix=REGEX %s
+// RUN: lldb-test symbols --name=not_there --find=variable %t | \
+// RUN:   FileCheck --check-prefix=EMPTY %s
+
+// EMPTY: Found 0 variables:
+// NAME: Found 4 variables:
+// CONTEXT: Found 1 variables:
+// REGEX: Found 5 variables:
+int foo;
+// NAME-DAG: name = "foo", type = {{.*}} (int), {{.*}} decl = find-basic-variable.cpp:[[@LINE-1]]
+// REGEX-DAG: name = "foo", type = {{.*}} (int), {{.*}} decl = find-basic-variable.cpp:[[@LINE-2]]
+namespace bar {
+int context;
+long foo;
+// NAME-DAG: name = "foo", type = {{.*}} (long int), {{.*}} decl = find-basic-variable.cpp:[[@LINE-1]]
+// CONTEXT-DAG: name = "foo", type = {{.*}} (long int), {{.*}} decl = find-basic-variable.cpp:[[@LINE-2]]
+// REGEX-DAG: name = "foo", type = {{.*}} (long int), {{.*}} decl = find-basic-variable.cpp:[[@LINE-3]]
+namespace baz {
+static short foo;
+// NAME-DAG: name = "foo", type = {{.*}} (short), {{.*}} decl = find-basic-variable.cpp:[[@LINE-1]]
+// REGEX-DAG: name = "foo", type = {{.*}} (short), {{.*}} decl = find-basic-variable.cpp:[[@LINE-2]]
+}
+}
+
+struct sbar {
+  static int foo;
+// NAME-DAG: name = "foo", type = {{.*}} (int), {{.*}} decl = find-basic-variable.cpp:[[@LINE-1]]
+// REGEX-DAG: name = "foo", type = {{.*}} (int), {{.*}} decl = find-basic-variable.cpp:[[@LINE-2]]
+};
+int sbar::foo;
+
+int foobar;
+// REGEX-DAG: name = "foobar", type = {{.*}} (int), {{.*}} decl = find-basic-variable.cpp:[[@LINE-1]]
+
+int fbar() {
+  static int foo;
+  return foo + bar::baz::foo;
+}
+
+int Foo;
+
+struct ssbar {
+  int foo;
+};
+
+extern "C" void _start(sbar, ssbar) {}

Added: lldb/trunk/lit/SymbolFile/DWARF/find-type-in-function.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/DWARF/find-type-in-function.cpp?rev=331447&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/DWARF/find-type-in-function.cpp (added)
+++ lldb/trunk/lit/SymbolFile/DWARF/find-type-in-function.cpp Thu May  3 03:57:16 2018
@@ -0,0 +1,24 @@
+// REQUIRES: lld
+
+// XFAIL: *
+
+// RUN: clang %s -g -c -o %t.o --target=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t
+// RUN: lldb-test symbols --name=foo --find=type %t | \
+// RUN:   FileCheck --check-prefix=NAME %s
+
+// Lookup for "foo" should find either both "struct foo" types or just the
+// global one. Right now, it finds the definition inside bar(), which is
+// definitely wrong.
+
+// NAME: Found 2 types:
+struct foo {};
+// NAME-DAG: name = "foo", {{.*}} decl = find-type-in-function.cpp:[[@LINE-1]]
+
+void bar() {
+  struct foo {};
+// NAME-DAG: name = "foo", {{.*}} decl = find-type-in-function.cpp:[[@LINE-1]]
+  foo a;
+}
+
+extern "C" void _start(foo) {}

Added: lldb/trunk/lit/SymbolFile/DWARF/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/DWARF/lit.local.cfg?rev=331447&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/DWARF/lit.local.cfg (added)
+++ lldb/trunk/lit/SymbolFile/DWARF/lit.local.cfg Thu May  3 03:57:16 2018
@@ -0,0 +1 @@
+config.suffixes = ['.cpp']

Modified: lldb/trunk/lit/lit.cfg
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/lit.cfg?rev=331447&r1=331446&r2=331447&view=diff
==============================================================================
--- lldb/trunk/lit/lit.cfg (original)
+++ lldb/trunk/lit/lit.cfg Thu May  3 03:57:16 2018
@@ -132,6 +132,8 @@ elif re.match(r'cl', config.cc):
     config.available_features.add("compiler-msvc")
 
 config.available_features.add(binary_feature(config.have_zlib, "zlib", "no"))
+if config.have_lld:
+  config.available_features.add("lld")
 
 # llvm-config knows whether it is compiled with asserts (and)
 # whether we are operating in release/debug mode.

Modified: lldb/trunk/lit/lit.site.cfg.in
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/lit.site.cfg.in?rev=331447&r1=331446&r2=331447&view=diff
==============================================================================
--- lldb/trunk/lit/lit.site.cfg.in (original)
+++ lldb/trunk/lit/lit.site.cfg.in Thu May  3 03:57:16 2018
@@ -13,6 +13,7 @@ config.python_executable = "@PYTHON_EXEC
 config.cc = "@LLDB_TEST_C_COMPILER@"
 config.cxx = "@LLDB_TEST_CXX_COMPILER@"
 config.have_zlib = @LLVM_ENABLE_ZLIB@
+config.have_lld = @LLDB_HAVE_LLD@
 
 # Support substitution of the tools and libs dirs with user parameters. This is
 # used when we can't determine the tool dir at configuration time.

Modified: lldb/trunk/tools/lldb-test/lldb-test.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-test/lldb-test.cpp?rev=331447&r1=331446&r2=331447&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-test/lldb-test.cpp (original)
+++ lldb/trunk/tools/lldb-test/lldb-test.cpp Thu May  3 03:57:16 2018
@@ -20,6 +20,10 @@
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Utility/CleanUp.h"
 #include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/StreamString.h"
 
@@ -29,6 +33,7 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/PrettyStackTrace.h"
 #include "llvm/Support/Signals.h"
+#include "llvm/Support/WithColor.h"
 #include <thread>
 
 using namespace lldb;
@@ -57,7 +62,7 @@ static cl::opt<bool> Persistent(
 static llvm::StringRef plural(uintmax_t value) { return value == 1 ? "" : "s"; }
 static void dumpState(const BreakpointList &List, LinePrinter &P);
 static std::string substitute(StringRef Cmd);
-static void evaluateBreakpoints(Debugger &Dbg);
+static int evaluateBreakpoints(Debugger &Dbg);
 } // namespace breakpoint
 
 namespace module {
@@ -69,12 +74,68 @@ cl::list<std::string> InputFilenames(cl:
 } // namespace module
 
 namespace symbols {
-cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
-                                     cl::OneOrMore, cl::sub(SymbolsSubcommand));
+static cl::list<std::string> InputFilenames(cl::Positional,
+                                            cl::desc("<input files>"),
+                                            cl::OneOrMore,
+                                            cl::sub(SymbolsSubcommand));
+enum class FindType {
+  None,
+  Function,
+  Namespace,
+  Type,
+  Variable,
+};
+static cl::opt<FindType> Find(
+    "find", cl::desc("Choose search type:"),
+    cl::values(
+        clEnumValN(FindType::None, "none",
+                   "No search, just dump the module."),
+        clEnumValN(FindType::Function, "function", "Find functions."),
+        clEnumValN(FindType::Namespace, "namespace", "Find namespaces."),
+        clEnumValN(FindType::Type, "type", "Find types."),
+        clEnumValN(FindType::Variable, "variable", "Find global variables.")),
+    cl::sub(SymbolsSubcommand));
+
+static cl::opt<std::string> Name("name", cl::desc("Name to find."),
+                                 cl::sub(SymbolsSubcommand));
+static cl::opt<bool>
+    Regex("regex",
+          cl::desc("Search using regular expressions (avaliable for variables "
+                   "and functions only)."),
+          cl::sub(SymbolsSubcommand));
+static cl::opt<std::string>
+    Context("context",
+            cl::desc("Restrict search to the context of the given variable."),
+            cl::value_desc("variable"), cl::sub(SymbolsSubcommand));
+
+static cl::list<FunctionNameType> FunctionNameFlags(
+    "function-flags", cl::desc("Function search flags:"),
+    cl::values(clEnumValN(eFunctionNameTypeAuto, "auto",
+                          "Automatically deduce flags based on name."),
+               clEnumValN(eFunctionNameTypeFull, "full", "Full function name."),
+               clEnumValN(eFunctionNameTypeBase, "base", "Base name."),
+               clEnumValN(eFunctionNameTypeMethod, "method", "Method name."),
+               clEnumValN(eFunctionNameTypeSelector, "selector",
+                          "Selector name.")),
+    cl::sub(SymbolsSubcommand));
+static FunctionNameType getFunctionNameFlags() {
+  FunctionNameType Result = FunctionNameType(0);
+  for (FunctionNameType Flag : FunctionNameFlags)
+    Result = FunctionNameType(Result | Flag);
+  return Result;
 }
-} // namespace opts
 
-static llvm::ManagedStatic<SystemLifetimeManager> DebuggerLifetime;
+static Expected<CompilerDeclContext> getDeclContext(SymbolVendor &Vendor);
+
+static Error findFunctions(lldb_private::Module &Module);
+static Error findNamespaces(lldb_private::Module &Module);
+static Error findTypes(lldb_private::Module &Module);
+static Error findVariables(lldb_private::Module &Module);
+static Error dumpModule(lldb_private::Module &Module);
+
+static int dumpSymbols(Debugger &Dbg);
+}
+} // namespace opts
 
 void opts::breakpoint::dumpState(const BreakpointList &List, LinePrinter &P) {
   P.formatLine("{0} breakpoint{1}", List.GetSize(), plural(List.GetSize()));
@@ -130,7 +191,7 @@ std::string opts::breakpoint::substitute
   return std::move(OS.str());
 }
 
-void opts::breakpoint::evaluateBreakpoints(Debugger &Dbg) {
+int opts::breakpoint::evaluateBreakpoints(Debugger &Dbg) {
   TargetSP Target;
   Status ST =
       Dbg.GetTargetList().CreateTarget(Dbg, breakpoint::Target, /*triple*/ "",
@@ -151,6 +212,7 @@ void opts::breakpoint::evaluateBreakpoin
 
   LinePrinter P(4, outs());
   StringRef Rest = (*MB)->getBuffer();
+  int HadErrors = 0;
   while (!Rest.empty()) {
     StringRef Line;
     std::tie(Line, Rest) = Rest.split('\n');
@@ -167,31 +229,198 @@ void opts::breakpoint::evaluateBreakpoin
     if (!Dbg.GetCommandInterpreter().HandleCommand(
             Command.c_str(), /*add_to_history*/ eLazyBoolNo, Result)) {
       P.formatLine("Failed: {0}", Result.GetErrorData());
+      HadErrors = 1;
       continue;
     }
 
     dumpState(Target->GetBreakpointList(/*internal*/ false), P);
   }
+  return HadErrors;
+}
+
+Expected<CompilerDeclContext>
+opts::symbols::getDeclContext(SymbolVendor &Vendor) {
+  if (Context.empty())
+    return CompilerDeclContext();
+  VariableList List;
+  Vendor.FindGlobalVariables(ConstString(Context), nullptr, false, 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());
+  }
+  return List.GetVariableAtIndex(0)->GetDeclContext();
+}
+
+Error opts::symbols::findFunctions(lldb_private::Module &Module) {
+  SymbolVendor &Vendor = *Module.GetSymbolVendor();
+  SymbolContextList List;
+  if (Regex) {
+    RegularExpression RE(Name);
+    assert(RE.IsValid());
+    Vendor.FindFunctions(RE, true, false, List);
+  } else {
+    Expected<CompilerDeclContext> ContextOr = getDeclContext(Vendor);
+    if (!ContextOr)
+      return ContextOr.takeError();
+    CompilerDeclContext *ContextPtr =
+        ContextOr->IsValid() ? &*ContextOr : nullptr;
+
+    Vendor.FindFunctions(ConstString(Name), ContextPtr, getFunctionNameFlags(),
+                          true, false, List);
+  }
+  outs() << formatv("Found {0} functions:\n", List.GetSize());
+  StreamString Stream;
+  List.Dump(&Stream, nullptr);
+  outs() << Stream.GetData() << "\n";
+  return Error::success();
+}
+
+Error opts::symbols::findNamespaces(lldb_private::Module &Module) {
+  SymbolVendor &Vendor = *Module.GetSymbolVendor();
+  Expected<CompilerDeclContext> ContextOr = getDeclContext(Vendor);
+  if (!ContextOr)
+    return ContextOr.takeError();
+  CompilerDeclContext *ContextPtr =
+      ContextOr->IsValid() ? &*ContextOr : nullptr;
+
+  SymbolContext SC;
+  CompilerDeclContext Result =
+      Vendor.FindNamespace(SC, ConstString(Name), ContextPtr);
+  if (Result)
+    outs() << "Found namespace: "
+           << Result.GetScopeQualifiedName().GetStringRef() << "\n";
+  else
+    outs() << "Namespace not found.\n";
+  return Error::success();
+}
+
+Error opts::symbols::findTypes(lldb_private::Module &Module) {
+  SymbolVendor &Vendor = *Module.GetSymbolVendor();
+  Expected<CompilerDeclContext> ContextOr = getDeclContext(Vendor);
+  if (!ContextOr)
+    return ContextOr.takeError();
+  CompilerDeclContext *ContextPtr =
+      ContextOr->IsValid() ? &*ContextOr : nullptr;
+
+  SymbolContext SC;
+  DenseSet<SymbolFile *> SearchedFiles;
+  TypeMap Map;
+  Vendor.FindTypes(SC, ConstString(Name), ContextPtr, true, UINT32_MAX,
+                    SearchedFiles, Map);
+
+  outs() << formatv("Found {0} types:\n", Map.GetSize());
+  StreamString Stream;
+  Map.Dump(&Stream, false);
+  outs() << Stream.GetData() << "\n";
+  return Error::success();
+}
+
+Error opts::symbols::findVariables(lldb_private::Module &Module) {
+  SymbolVendor &Vendor = *Module.GetSymbolVendor();
+  VariableList List;
+  if (Regex) {
+    RegularExpression RE(Name);
+    assert(RE.IsValid());
+    Vendor.FindGlobalVariables(RE, false, UINT32_MAX, List);
+  } else {
+    Expected<CompilerDeclContext> ContextOr = getDeclContext(Vendor);
+    if (!ContextOr)
+      return ContextOr.takeError();
+    CompilerDeclContext *ContextPtr =
+        ContextOr->IsValid() ? &*ContextOr : nullptr;
+
+    Vendor.FindGlobalVariables(ConstString(Name), ContextPtr, false, UINT32_MAX,
+                               List);
+  }
+  outs() << formatv("Found {0} variables:\n", List.GetSize());
+  StreamString Stream;
+  List.Dump(&Stream, false);
+  outs() << Stream.GetData() << "\n";
+  return Error::success();
 }
 
-static void dumpSymbols(Debugger &Dbg) {
-  for (const auto &File : opts::symbols::InputFilenames) {
+Error opts::symbols::dumpModule(lldb_private::Module &Module) {
+  StreamString Stream;
+  Module.ParseAllDebugSymbols();
+  Module.Dump(&Stream);
+  outs() << Stream.GetData() << "\n";
+  return Error::success();
+}
+
+int opts::symbols::dumpSymbols(Debugger &Dbg) {
+  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;
+  }
+
+  Error (*Action)(lldb_private::Module &);
+  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;
+  }
+
+  int HadErrors = 0;
+  for (const auto &File : InputFilenames) {
+    outs() << "Module: " << File << "\n";
     ModuleSpec Spec{FileSpec(File, false)};
     Spec.GetSymbolFileSpec().SetFile(File, false);
 
     auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
+    SymbolVendor *Vendor = ModulePtr->GetSymbolVendor();
+    if (!Vendor) {
+      WithColor::error() << "Module has no symbol vendor.\n";
+      HadErrors = 1;
+      continue;
+    }
+    
+    if (Error E = Action(*ModulePtr)) {
+      WithColor::error() << toString(std::move(E)) << "\n";
+      HadErrors = 1;
+    }
 
-    StreamString Stream;
-    ModulePtr->ParseAllDebugSymbols();
-    ModulePtr->Dump(&Stream);
-    llvm::outs() << Stream.GetData() << "\n";
-    llvm::outs().flush();
+    outs().flush();
   }
+  return HadErrors;
 }
 
-static void dumpModules(Debugger &Dbg) {
+static int dumpModules(Debugger &Dbg) {
   LinePrinter Printer(4, llvm::outs());
 
+  int HadErrors = 0;
   for (const auto &File : opts::module::InputFilenames) {
     ModuleSpec Spec{FileSpec(File, false)};
 
@@ -202,6 +431,7 @@ static void dumpModules(Debugger &Dbg) {
     SectionList *Sections = ModulePtr->GetSectionList();
     if (!Sections) {
       llvm::errs() << "Could not load sections for module " << File << "\n";
+      HadErrors = 1;
       continue;
     }
 
@@ -226,6 +456,7 @@ static void dumpModules(Debugger &Dbg) {
       Printer.NewLine();
     }
   }
+  return HadErrors;
 }
 
 int main(int argc, const char *argv[]) {
@@ -236,18 +467,20 @@ int main(int argc, const char *argv[]) {
 
   cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n");
 
-  DebuggerLifetime->Initialize(llvm::make_unique<SystemInitializerTest>(),
-                               nullptr);
+  SystemLifetimeManager DebuggerLifetime;
+  DebuggerLifetime.Initialize(llvm::make_unique<SystemInitializerTest>(),
+                              nullptr);
+  CleanUp TerminateDebugger([&] { DebuggerLifetime.Terminate(); });
 
   auto Dbg = lldb_private::Debugger::CreateInstance();
 
   if (opts::BreakpointSubcommand)
-    opts::breakpoint::evaluateBreakpoints(*Dbg);
+    return opts::breakpoint::evaluateBreakpoints(*Dbg);
   if (opts::ModuleSubcommand)
-    dumpModules(*Dbg);
-  else if (opts::SymbolsSubcommand)
-    dumpSymbols(*Dbg);
+    return dumpModules(*Dbg);
+  if (opts::SymbolsSubcommand)
+    return opts::symbols::dumpSymbols(*Dbg);
 
-  DebuggerLifetime->Terminate();
-  return 0;
+  WithColor::error() << "No command specified.\n";
+  return 1;
 }




More information about the lldb-commits mailing list