Index: lldb/lit/SymbolFile/DWARF/compilercontext.ll =================================================================== --- /dev/null +++ lldb/lit/SymbolFile/DWARF/compilercontext.ll @@ -0,0 +1,23 @@ +; This simulates the debug info for a Clang module. +source_filename = "/t.c" +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.14.0" + +!llvm.dbg.cu = !{!2} +!llvm.linker.options = !{} +!llvm.module.flags = !{!18, !19} +!llvm.ident = !{!22} + +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, nameTableKind: GNU, retainedTypes: !{!11}) +!3 = !DIFile(filename: "t.c", directory: "/") +!8 = !DIModule(scope: !9, name: "SubModule", includePath: "", isysroot: "/") +!9 = !DIModule(scope: null, name: "CModule", includePath: "", isysroot: "/") +!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "FromSubmodule", scope: !8, file: !3, line: 1, size: 96, elements: !13) +!13 = !{!14, !16, !17} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !11, file: !3, line: 2, baseType: !15, size: 32) +!15 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!16 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !11, file: !3, line: 2, baseType: !15, size: 32, offset: 32) +!17 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !11, file: !3, line: 2, baseType: !15, size: 32, offset: 64) +!18 = !{i32 2, !"Dwarf Version", i32 4} +!19 = !{i32 2, !"Debug Info Version", i32 3} +!22 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project 056f1b5cc7c2133f0cb3e30e7f24808d321096d7)"} Index: lldb/lit/SymbolFile/DWARF/compilercontext.test =================================================================== --- /dev/null +++ lldb/lit/SymbolFile/DWARF/compilercontext.test @@ -0,0 +1,11 @@ +Test finding types by CompilerContext. +RUN: llc %S/compilercontext.ll -filetype=obj -o %t.o +RUN: lldb-test symbols %t.o -find=type -compiler-context='[{"kind":"Module","name":"CModule"},{"kind":"Module","name":"SubModule"},{"kind":"Structure","name":"FromSubmodule"}]' | FileCheck %s + + +CHECK: Found 1 types: +CHECK: struct FromSubmodule { +CHECK-NEXT: unsigned int x; +CHECK-NEXT: unsigned int y; +CHECK-NEXT: unsigned int z; +CHECK-NEXT: } Index: lldb/tools/lldb-test/lldb-test.cpp =================================================================== --- lldb/tools/lldb-test/lldb-test.cpp +++ lldb/tools/lldb-test/lldb-test.cpp @@ -30,6 +30,7 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/CleanUp.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/JSON.h" #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" @@ -139,6 +140,11 @@ cl::desc("Restrict search to the context of the given variable."), cl::value_desc("variable"), cl::sub(SymbolsSubcommand)); +static cl::opt CompilerContext( + "compiler-context", + cl::desc("Specify a compiler context as \"[(type,name),...]\"."), + cl::value_desc("context"), cl::sub(SymbolsSubcommand)); + static cl::list FunctionNameFlags( "function-flags", cl::desc("Function search flags:"), cl::values(clEnumValN(eFunctionNameTypeAuto, "auto", @@ -220,6 +226,62 @@ } // namespace opts +std::vector parseCompilerContext() { + std::vector result; + if (opts::symbols::CompilerContext.empty()) + return result; + + JSONParser parser(StringRef{opts::symbols::CompilerContext}); + auto val = parser.ParseJSONValue(); + auto array = dyn_cast_or_null(val.get()); + if (!array) { + WithColor::error() << "compiler context is not a JSON array\n"; + exit(1); + } + for (unsigned i = 0; i < array->GetNumElements(); ++i) { + auto val = array->GetObject(i); + auto entry = dyn_cast(val.get()); + if (!entry) { + WithColor::error() << "compiler context entry is not a JSON object\n"; + exit(1); + } + auto kind_val = + dyn_cast_or_null(entry->GetObject("kind").get()); + if (!kind_val) { + WithColor::error() << "compiler context entry has no \"kind\"\n"; + exit(1); + } + auto kind = + StringSwitch(kind_val->GetData()) + .Case("TranslationUnit", CompilerContextKind::TranslationUnit) + .Case("Module", CompilerContextKind::Module) + .Case("Namespace", CompilerContextKind::Namespace) + .Case("Class", CompilerContextKind::Class) + .Case("Structure", CompilerContextKind::Structure) + .Case("Union", CompilerContextKind::Union) + .Case("Function", CompilerContextKind::Function) + .Case("Variable", CompilerContextKind::Variable) + .Case("Enumeration", CompilerContextKind::Enumeration) + .Case("Typedef", CompilerContextKind::Typedef) + .Default(CompilerContextKind::Invalid); + auto name_val = + dyn_cast_or_null(entry->GetObject("name").get()); + if (!name_val) { + WithColor::error() << "compiler context entry has no \"name\"\n"; + exit(1); + } + result.push_back({kind, ConstString{name_val->GetData()}}); + } + outs() << "Search context: {\n"; + for (auto entry: result) { + outs() << " " << (unsigned)entry.type; + outs() << " \"" << entry.name.GetStringRef() << "\"\n"; + } + outs() << "}\n"; + + return result; +} + template static Error make_string_error(const char *Format, Args &&... args) { return llvm::make_error( @@ -464,8 +526,11 @@ DenseSet SearchedFiles; TypeMap Map; - Symfile.FindTypes(ConstString(Name), ContextPtr, true, UINT32_MAX, - SearchedFiles, Map); + if (!Name.empty()) + Symfile.FindTypes(ConstString(Name), ContextPtr, true, UINT32_MAX, + SearchedFiles, Map); + else + Symfile.FindTypes(parseCompilerContext(), true, Map); outs() << formatv("Found {0} types:\n", Map.GetSize()); StreamString Stream; @@ -679,6 +744,9 @@ if (Regex || !File.empty() || Line != 0) return make_string_error("Cannot search for types using regular " "expressions, file names or line numbers."); + if (!Name.empty() && !CompilerContext.empty()) + return make_string_error("Name is ignored if compiler context present."); + return findTypes; case FindType::Variable: