diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp --- a/lldb/source/Breakpoint/BreakpointResolverName.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp @@ -246,6 +246,8 @@ // accelerate function lookup. At that point, we should switch the depth to // CompileUnit, and look in these tables. +#include "lldb/Symbol/CompileUnit.h" + Searcher::CallbackReturn BreakpointResolverName::SearchCallback(SearchFilter &filter, SymbolContext &context, Address *addr) { @@ -260,6 +262,8 @@ SymbolContextList func_list; bool filter_by_cu = (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0; + bool filter_by_function = + (filter.GetFilterRequiredItems() & eSymbolContextFunction) != 0; bool filter_by_language = (m_language != eLanguageTypeUnknown); const bool include_symbols = !filter_by_cu; const bool include_inlines = true; @@ -304,11 +308,23 @@ bool remove_it = false; SymbolContext sc; func_list.GetContextAtIndex(idx, sc); - if (filter_by_cu) { + if (filter_by_cu && !filter_by_function) { if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit)) remove_it = true; } + if (filter_by_cu && filter_by_function) { + // Keep this symbol context if it is a function call to a function + // whose declaration is located in a file that passes. This is needed + // for inlined functions (e.g. when LTO is enabled) and templates. + if (Type *type = sc.function->GetType()) { + Declaration &decl = const_cast(type->GetDeclaration()); + FileSpec &source_file = decl.GetFile(); + if (!filter.CompUnitPasses(source_file)) + remove_it = true; + } + } + if (filter_by_language) { LanguageType sym_language = sc.GetLanguage(); if ((Language::GetPrimaryLanguage(sym_language) != diff --git a/lldb/source/Core/SearchFilter.cpp b/lldb/source/Core/SearchFilter.cpp --- a/lldb/source/Core/SearchFilter.cpp +++ b/lldb/source/Core/SearchFilter.cpp @@ -712,16 +712,12 @@ if (m_cu_spec_list.GetSize() != 0) return false; // Has no comp_unit so can't pass the file check. } - FileSpec cu_spec; - if (sym_ctx.comp_unit) - cu_spec = sym_ctx.comp_unit->GetPrimaryFile(); - if (m_cu_spec_list.FindFileIndex(0, cu_spec, false) == UINT32_MAX) - return false; // Fails the file check - return SearchFilterByModuleList::ModulePasses(sym_ctx.module_sp); + return SearchFilterByModuleList::ModulePasses(sym_ctx.module_sp); } bool SearchFilterByModuleListAndCU::CompUnitPasses(FileSpec &fileSpec) { - return m_cu_spec_list.FindFileIndex(0, fileSpec, false) != UINT32_MAX; + return ModulePasses(fileSpec) && + m_cu_spec_list.FindFileIndex(0, fileSpec, false) != UINT32_MAX; } bool SearchFilterByModuleListAndCU::CompUnitPasses(CompileUnit &compUnit) { @@ -811,7 +807,7 @@ } uint32_t SearchFilterByModuleListAndCU::GetFilterRequiredItems() { - return eSymbolContextModule | eSymbolContextCompUnit; + return eSymbolContextModule | eSymbolContextCompUnit | eSymbolContextFunction; } void SearchFilterByModuleListAndCU::Dump(Stream *s) const {} diff --git a/lldb/test/Shell/Breakpoint/Inputs/search-support-files.h b/lldb/test/Shell/Breakpoint/Inputs/search-support-files.h new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/Breakpoint/Inputs/search-support-files.h @@ -0,0 +1 @@ +int inlined_42() { return 42; } diff --git a/lldb/test/Shell/Breakpoint/Inputs/search-support-files.cpp b/lldb/test/Shell/Breakpoint/Inputs/search-support-files.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/Breakpoint/Inputs/search-support-files.cpp @@ -0,0 +1,6 @@ +#include "search-support-files.h" + +int main(int argc, char *argv[]) { + int a = inlined_42(); + return a; +} diff --git a/lldb/test/Shell/Breakpoint/search-support-files.test b/lldb/test/Shell/Breakpoint/search-support-files.test new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/Breakpoint/search-support-files.test @@ -0,0 +1,46 @@ +# In these tests we will set breakpoints on a function by name. That function +# is defined in a header file (search-support-files.h) and will therefore be +# inlined into the file that includes it (search-support-files.cpp). +# +# TODO(kwk): Check that we can also do the same with C++ methods in files? +# (See https://lldb.llvm.org/use/tutorial.html and look for --method.) + +# RUN: %build %p/Inputs/search-support-files.cpp -o dummy.out +# RUN: %lldb -b -s %s dummy.out | FileCheck --color --dump-input=fail %s + +# Set breakpoint by function name. + +breakpoint set -n inlined_42 +# CHECK: (lldb) breakpoint set -n inlined_42 +# CHECK-NEXT: Breakpoint 1: where = dummy.out`inlined_42() + 4 at search-support-files.h:1:20, address = 0x0{{.*}} + +breakpoint set -n main +# CHECK: (lldb) breakpoint set -n main +# CHECK-NEXT: Breakpoint 2: where = dummy.out`main + 22 at search-support-files.cpp:4:11, address = 0x0{{.*}} + +# Set breakpoint by function name and filename (the one in which the function +# is inlined, aka the compilation unit). + +breakpoint set -n inlined_42 -f search-support-files.cpp +# CHECK: (lldb) breakpoint set -n inlined_42 -f search-support-files.cpp +# CHECK-NEXT: Breakpoint 3: no locations (pending). + +# Set breakpoint by function name and source filename (the file in which the +# function is defined). +# +# NOTE: This test is the really interesting one as it shows that we can +# search by source files that are themselves no compulation units. + +breakpoint set -n inlined_42 -f search-support-files.h +# CHECK: (lldb) breakpoint set -n inlined_42 -f search-support-files.h +# CHECK-NEXT: Breakpoint 4: where = dummy.out`inlined_42() + 4 at search-support-files.h:1:20, address = 0x0{{.*}} + +# Set breakpoint by function name and source filename. This time the file +# doesn't exist to prove that we haven't widen the search space too much. When +# we search for a function in a file that doesn't exist, we should get no +# results. + +breakpoint set -n inlined_42 -f file-not-existing.h +# CHECK: (lldb) breakpoint set -n inlined_42 -f file-not-existing.h +# CHECK-NEXT: Breakpoint 5: no locations (pending). +# CHECK-NEXT: WARNING: Unable to resolve breakpoint to any actual locations.