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 @@ -260,6 +260,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 +306,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,12 +712,7 @@ 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) { @@ -811,7 +806,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 function_in_header() { 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 = function_in_header(); + 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 %t.out +# RUN: %lldb -b -s %s %t.out | FileCheck --color --dump-input=fail %s + +# Set breakpoint by function name. + +breakpoint set -n function_in_header +# CHECK: (lldb) breakpoint set -n function_in_header +# CHECK-NEXT: Breakpoint 1: where = {{.*}}.out`function_in_header(){{.*}} at search-support-files.h + +breakpoint set -n main +# CHECK: (lldb) breakpoint set -n main +# CHECK-NEXT: Breakpoint 2: where = {{.*}}.out`main{{.*}} at search-support-files.cpp + +# Set breakpoint by function name and filename (the one in which the function +# is inlined, aka the compilation unit). + +breakpoint set -n function_in_header -f search-support-files.cpp +# CHECK: (lldb) breakpoint set -n function_in_header -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 compilation units. + +breakpoint set -n function_in_header -f search-support-files.h +# CHECK: (lldb) breakpoint set -n function_in_header -f search-support-files.h +# CHECK-NEXT: Breakpoint 4: where = {{.*}}.out`function_in_header(){{.*}} at search-support-files.h + +# 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 function_in_header -f file-not-existing.h +# CHECK: (lldb) breakpoint set -n function_in_header -f file-not-existing.h +# CHECK-NEXT: Breakpoint 5: no locations (pending). +# CHECK-NEXT: WARNING: Unable to resolve breakpoint to any actual locations.