From 5aa27e1acca98e3f8f1cf2da47dc4b05297786c5 Mon Sep 17 00:00:00 2001 From: Tamas Berghammer Date: Fri, 24 Jul 2015 08:54:22 +0000 Subject: [PATCH] Improve C++ function name handling and step-in avoid regerxp handling If the function is a template then the return type is part of the function name. This CL fixes the parsing of these function names in the case when the return type contains ':'. The name of free functions in C++ don't have context part. Fix the logic geting the function name without arguments out from a full function name to handle this case. Change the handling of step-in-avoid-regexp to match the value against the function name without it's arguments and return value. This is required because the default regex ("^std::") would match any template function returning an std object. Fifferential revision: http://reviews.llvm.org/D11461 llvm-svn: 243099 --- lldb/source/Core/Mangled.cpp | 7 +-- lldb/source/Target/CPPLanguageRuntime.cpp | 17 +++---- lldb/source/Target/ThreadPlanStepInRange.cpp | 2 +- .../disassembly/TestDisassembleBreakpoint.py | 2 +- .../inline-stepping/TestInlineStepping.py | 48 ++++++++++++++++++- .../inline-stepping/calling.cpp | 19 +++++++- 6 files changed, 78 insertions(+), 17 deletions(-) diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index a1916fe913c4..e1b0738ce4d9 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -95,10 +95,11 @@ get_demangled_name_without_arguments (ConstString mangled, ConstString demangled mangled_name_cstr[2] != 'Z')) // named local entities (if we eventually handle eSymbolTypeData, we will want this back) { CPPLanguageRuntime::MethodName cxx_method (demangled); - if (!cxx_method.GetBasename().empty() && !cxx_method.GetContext().empty()) + if (!cxx_method.GetBasename().empty()) { - std::string shortname = cxx_method.GetContext().str(); - shortname += "::"; + std::string shortname; + if (!cxx_method.GetContext().empty()) + shortname = cxx_method.GetContext().str() + "::"; shortname += cxx_method.GetBasename().str(); ConstString result(shortname.c_str()); g_most_recent_mangled_to_name_sans_args.first = mangled; diff --git a/lldb/source/Target/CPPLanguageRuntime.cpp b/lldb/source/Target/CPPLanguageRuntime.cpp index f048c6706a9b..98442c7ba800 100644 --- a/lldb/source/Target/CPPLanguageRuntime.cpp +++ b/lldb/source/Target/CPPLanguageRuntime.cpp @@ -306,17 +306,14 @@ CPPLanguageRuntime::MethodName::Parse() llvm::StringRef lt_gt("<>", 2); if (ReverseFindMatchingChars (full, lt_gt, template_start, template_end, basename_end)) { + // Check for templated functions that include return type like: 'void foo()' + context_start = full.rfind(' ', template_start); + if (context_start == llvm::StringRef::npos) + context_start = 0; + context_end = full.rfind(':', template_start); - if (context_end == llvm::StringRef::npos) - { - // Check for templated functions that include return type like: - // 'void foo()' - context_end = full.rfind(' ', template_start); - if (context_end != llvm::StringRef::npos) - { - context_start = context_end; - } - } + if (context_end == llvm::StringRef::npos || context_end < context_start) + context_end = context_start; } else { diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index b3c82499e5b6..a7f5d6746be5 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -375,7 +375,7 @@ ThreadPlanStepInRange::FrameMatchesAvoidCriteria () SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol); if (sc.symbol != NULL) { - const char *frame_function_name = sc.GetFunctionName().GetCString(); + const char *frame_function_name = sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments).GetCString(); if (frame_function_name) { size_t num_matches = 0; diff --git a/lldb/test/functionalities/disassembly/TestDisassembleBreakpoint.py b/lldb/test/functionalities/disassembly/TestDisassembleBreakpoint.py index 7de71573f5b6..dc47ee23abcf 100644 --- a/lldb/test/functionalities/disassembly/TestDisassembleBreakpoint.py +++ b/lldb/test/functionalities/disassembly/TestDisassembleBreakpoint.py @@ -53,7 +53,7 @@ class DisassemblyTestCase(TestBase): self.assertFalse(op in disassembly) # make sure a few reasonable assembly instructions are here - self.expect(disassembly, exe=False, startstr = "a.out`sum(int, int)", substrs = instructions) + self.expect(disassembly, exe=False, startstr = "a.out`sum", substrs = instructions) if __name__ == '__main__': import atexit diff --git a/lldb/test/functionalities/inline-stepping/TestInlineStepping.py b/lldb/test/functionalities/inline-stepping/TestInlineStepping.py index 9263395b20b0..0137202964b4 100644 --- a/lldb/test/functionalities/inline-stepping/TestInlineStepping.py +++ b/lldb/test/functionalities/inline-stepping/TestInlineStepping.py @@ -45,6 +45,21 @@ class TestInlineStepping(TestBase): """Test stepping over and into inlined functions.""" self.buildDwarf() self.inline_stepping_step_over() + + @skipUnlessDarwin + @python_api_test + @dsym_test + def test_step_in_template_with_dsym_and_python_api(self): + """Test stepping in to templated functions.""" + self.buildDsym() + self.step_in_template() + + @python_api_test + @dwarf_test + def test_step_in_template_with_dwarf_and_python_api(self): + """Test stepping in to templated functions.""" + self.buildDwarf() + self.step_in_template() def setUp(self): # Call super's setUp(). @@ -120,7 +135,6 @@ class TestInlineStepping(TestBase): target_line_entry.SetLine(step_stop_line) self.do_step (step_pattern[1], target_line_entry, test_stack_depth) - def inline_stepping(self): """Use Python APIs to test stepping over and hitting breakpoints.""" exe = os.path.join(os.getcwd(), "a.out") @@ -245,8 +259,40 @@ class TestInlineStepping(TestBase): ["// At increment in caller_ref_2.", "over"]] self.run_step_sequence (step_sequence) + def step_in_template(self): + """Use Python APIs to test stepping in to templated functions.""" + exe = os.path.join(os.getcwd(), "a.out") + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + break_1_in_main = target.BreakpointCreateBySourceRegex ('// Call max_value template', self.main_source_spec) + self.assertTrue(break_1_in_main, VALID_BREAKPOINT) + break_2_in_main = target.BreakpointCreateBySourceRegex ('// Call max_value specialized', self.main_source_spec) + self.assertTrue(break_2_in_main, VALID_BREAKPOINT) + + # Now launch the process, and do not stop at entry point. + self.process = target.LaunchSimple (None, None, self.get_process_working_directory()) + self.assertTrue(self.process, PROCESS_IS_VALID) + + # The stop reason of the thread should be breakpoint. + threads = lldbutil.get_threads_stopped_at_breakpoint (self.process, break_1_in_main) + + if len(threads) != 1: + self.fail ("Failed to stop at first breakpoint in main.") + + self.thread = threads[0] + + step_sequence = [["// In max_value template", "into"]] + self.run_step_sequence(step_sequence) + threads = lldbutil.continue_to_breakpoint (self.process, break_2_in_main) + self.assertEqual(len(threads), 1, "Successfully ran to call site of second caller_trivial_1 call.") + self.thread = threads[0] + + step_sequence = [["// In max_value specialized", "into"]] + self.run_step_sequence(step_sequence) if __name__ == '__main__': import atexit diff --git a/lldb/test/functionalities/inline-stepping/calling.cpp b/lldb/test/functionalities/inline-stepping/calling.cpp index e5a9570f2531..9982fbf42734 100644 --- a/lldb/test/functionalities/inline-stepping/calling.cpp +++ b/lldb/test/functionalities/inline-stepping/calling.cpp @@ -1,4 +1,6 @@ -#include +#include +#include +#include inline int inline_ref_1 (int &value) __attribute__((always_inline)); inline int inline_ref_2 (int &value) __attribute__((always_inline)); @@ -97,6 +99,18 @@ inline_trivial_2 () called_by_inline_trivial (); // At caller_by_inline_trivial in inline_trivial_2. } +template T +max_value(const T& lhs, const T& rhs) +{ + return std::max(lhs, rhs); // In max_value template +} + +template<> std::string +max_value(const std::string& lhs, const std::string& rhs) +{ + return (lhs.size() > rhs.size()) ? lhs : rhs; // In max_value specialized +} + int main (int argc, char **argv) { @@ -114,6 +128,9 @@ main (int argc, char **argv) caller_ref_1 (argc); // At second call of caller_ref_1 in main. function_to_call (); // Make sure debug info for this function gets generated. + + max_value(123, 456); // Call max_value template + max_value(std::string("abc"), std::string("0022")); // Call max_value specialized return 0; // About to return from main. }