[Lldb-commits] [lldb] r344371 - Adding support to step into the callable wrapped by libc++ std::function
Shafik Yaghmour via lldb-commits
lldb-commits at lists.llvm.org
Fri Oct 12 10:20:39 PDT 2018
Author: shafik
Date: Fri Oct 12 10:20:39 2018
New Revision: 344371
URL: http://llvm.org/viewvc/llvm-project?rev=344371&view=rev
Log:
Adding support to step into the callable wrapped by libc++ std::function
rdar://problem/14365983
Differential Revision: https://reviews.llvm.org/D52851
Added:
lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/
lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/Makefile
lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/TestStdFunctionStepIntoCallable.py
lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/main.cpp
Modified:
lldb/trunk/include/lldb/Target/CPPLanguageRuntime.h
lldb/trunk/source/Target/CPPLanguageRuntime.cpp
lldb/trunk/source/Target/ThreadPlanStepThrough.cpp
Modified: lldb/trunk/include/lldb/Target/CPPLanguageRuntime.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/CPPLanguageRuntime.h?rev=344371&r1=344370&r2=344371&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/CPPLanguageRuntime.h (original)
+++ lldb/trunk/include/lldb/Target/CPPLanguageRuntime.h Fri Oct 12 10:20:39 2018
@@ -56,6 +56,19 @@ public:
bool GetObjectDescription(Stream &str, Value &value,
ExecutionContextScope *exe_scope) override;
+ /// Obtain a ThreadPlan to get us into C++ constructs such as std::function.
+ ///
+ /// @param[in] thread
+ /// Curent thrad of execution.
+ ///
+ /// @param[in] stop_others
+ /// True if other threads should pause during execution.
+ ///
+ /// @return
+ /// A ThreadPlan Shared pointer
+ lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop_others);
+
protected:
//------------------------------------------------------------------
// Classes that inherit from CPPLanguageRuntime can see and modify these
Added: lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/Makefile?rev=344371&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/Makefile Fri Oct 12 10:20:39 2018
@@ -0,0 +1,7 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+CXXFLAGS += -std=c++11
+USE_LIBCPP := 1
+
+include $(LEVEL)/Makefile.rules
Added: lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/TestStdFunctionStepIntoCallable.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/TestStdFunctionStepIntoCallable.py?rev=344371&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/TestStdFunctionStepIntoCallable.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/TestStdFunctionStepIntoCallable.py Fri Oct 12 10:20:39 2018
@@ -0,0 +1,71 @@
+"""
+Test stepping into std::function
+"""
+
+from __future__ import print_function
+
+
+import lldb
+import sys
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class LibCxxFunctionTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ NO_DEBUG_INFO_TESTCASE = True
+
+ @add_test_categories(["libc++"])
+ def test(self):
+ """Test that std::function as defined by libc++ is correctly printed by LLDB"""
+ self.build()
+
+ self.main_source = "main.cpp"
+ self.main_source_spec = lldb.SBFileSpec(self.main_source)
+ self.source_foo_line = line_number(
+ self.main_source, '// Source foo start line')
+ self.source_lambda_f2_line = line_number(
+ self.main_source, '// Source lambda used by f2 start line')
+ self.source_lambda_f3_line = line_number(
+ self.main_source, '// Source lambda used by f3 start line')
+ self.source_bar_operator_line = line_number(
+ self.main_source, '// Source Bar::operator()() start line')
+ self.source_bar_add_num_line = line_number(
+ self.main_source, '// Source Bar::add_num start line')
+ self.source_main_invoking_f1 = line_number(
+ self.main_source, '// Source main invoking f1')
+
+ (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+ self, "// Set break point at this line.", self.main_source_spec)
+
+ thread.StepInto()
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), self.source_main_invoking_f1 ) ;
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetFileSpec().GetFilename(), self.main_source) ;
+
+ thread.StepInto()
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), self.source_foo_line ) ;
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetFileSpec().GetFilename(), self.main_source) ;
+ process.Continue()
+
+ thread.StepInto()
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), self.source_lambda_f2_line ) ;
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetFileSpec().GetFilename(), self.main_source) ;
+ process.Continue()
+
+ thread.StepInto()
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), self.source_lambda_f3_line ) ;
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetFileSpec().GetFilename(), self.main_source) ;
+ process.Continue()
+
+ thread.StepInto()
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), self.source_bar_operator_line ) ;
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetFileSpec().GetFilename(), self.main_source) ;
+ process.Continue()
+
+ thread.StepInto()
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), self.source_bar_add_num_line ) ;
+ self.assertEqual( thread.GetFrameAtIndex(0).GetLineEntry().GetFileSpec().GetFilename(), self.main_source) ;
+ process.Continue()
Added: lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/main.cpp?rev=344371&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/main.cpp (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/main.cpp Fri Oct 12 10:20:39 2018
@@ -0,0 +1,38 @@
+#include <functional>
+
+int foo(int x, int y) {
+ return x + y - 1; // Source foo start line
+}
+
+struct Bar {
+ int operator()() {
+ return 66 ; // Source Bar::operator()() start line
+ }
+ int add_num(int i) const { return i + 3 ; } // Source Bar::add_num start line
+ int num_ = 0 ;
+} ;
+
+int main (int argc, char *argv[])
+{
+ int acc = 42;
+ std::function<int (int,int)> f1 = foo;
+ std::function<int (int)> f2 = [acc,f1] (int x) -> int {
+ return x+f1(acc,x); // Source lambda used by f2 start line
+ };
+
+ auto f = [](int x, int y) { return x + y; }; // Source lambda used by f3 start line
+ auto g = [](int x, int y) { return x * y; } ;
+ std::function<int (int,int)> f3 = argc %2 ? f : g ;
+
+ Bar bar1 ;
+ std::function<int ()> f4( bar1 ) ;
+ std::function<int (const Bar&, int)> f5 = &Bar::add_num;
+ std::function<int(Bar const&)> f_mem = &Bar::num_;
+
+ return f_mem(bar1) + // Set break point at this line.
+ f1(acc,acc) + // Source main invoking f1
+ f2(acc) + // Set break point at this line.
+ f3(acc+1,acc+2) + // Set break point at this line.
+ f4() + // Set break point at this line.
+ f5(bar1, 10); // Set break point at this line.
+}
Modified: lldb/trunk/source/Target/CPPLanguageRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/CPPLanguageRuntime.cpp?rev=344371&r1=344370&r2=344371&view=diff
==============================================================================
--- lldb/trunk/source/Target/CPPLanguageRuntime.cpp (original)
+++ lldb/trunk/source/Target/CPPLanguageRuntime.cpp Fri Oct 12 10:20:39 2018
@@ -26,6 +26,7 @@
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Target/ThreadPlanStepInRange.h"
using namespace lldb;
using namespace lldb_private;
@@ -158,7 +159,6 @@ CPPLanguageRuntime::FindLibCppStdFunctio
// We do this by find the first < and , and extracting in between.
//
// This covers the case of the lambda known at compile time.
- //
size_t first_open_angle_bracket = vtable_name.find('<') + 1;
size_t first_comma = vtable_name.find_first_of(',');
@@ -262,3 +262,76 @@ CPPLanguageRuntime::FindLibCppStdFunctio
return optional_info;
}
+
+lldb::ThreadPlanSP
+CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop_others) {
+ ThreadPlanSP ret_plan_sp;
+
+ lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
+
+ TargetSP target_sp(thread.CalculateTarget());
+
+ if (target_sp->GetSectionLoadList().IsEmpty())
+ return ret_plan_sp;
+
+ Address pc_addr_resolved;
+ SymbolContext sc;
+ Symbol *symbol;
+
+ if (!target_sp->GetSectionLoadList().ResolveLoadAddress(curr_pc,
+ pc_addr_resolved))
+ return ret_plan_sp;
+
+ target_sp->GetImages().ResolveSymbolContextForAddress(
+ pc_addr_resolved, eSymbolContextEverything, sc);
+ symbol = sc.symbol;
+
+ if (symbol == nullptr)
+ return ret_plan_sp;
+
+ llvm::StringRef function_name(symbol->GetName().GetCString());
+
+ // Handling the case where we are attempting to step into std::function.
+ // The behavior will be that we will attempt to obtain the wrapped
+ // callable via FindLibCppStdFunctionCallableInfo() and if we find it we
+ // will return a ThreadPlanRunToAddress to the callable. Therefore we will
+ // step into the wrapped callable.
+ //
+ bool found_expected_start_string =
+ function_name.startswith("std::__1::function<");
+
+ if (!found_expected_start_string)
+ return ret_plan_sp;
+
+ AddressRange range_of_curr_func;
+ sc.GetAddressRange(eSymbolContextEverything, 0, false, range_of_curr_func);
+
+ StackFrameSP frame = thread.GetStackFrameAtIndex(0);
+
+ if (frame) {
+ ValueObjectSP value_sp = frame->FindVariable(ConstString("this"));
+
+ CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info =
+ FindLibCppStdFunctionCallableInfo(value_sp);
+
+ if (callable_info.callable_case != LibCppStdFunctionCallableCase::Invalid &&
+ value_sp->GetValueIsValid()) {
+ // We found the std::function wrapped callable and we have its address.
+ // We now create a ThreadPlan to run to the callable.
+ ret_plan_sp.reset(new ThreadPlanRunToAddress(
+ thread, callable_info.callable_address, stop_others));
+ return ret_plan_sp;
+ } else {
+ // We are in std::function but we could not obtain the callable.
+ // We create a ThreadPlan to keep stepping through using the address range
+ // of the current function.
+ ret_plan_sp.reset(new ThreadPlanStepInRange(thread, range_of_curr_func,
+ sc, eOnlyThisThread,
+ eLazyBoolYes, eLazyBoolYes));
+ return ret_plan_sp;
+ }
+ }
+
+ return ret_plan_sp;
+}
Modified: lldb/trunk/source/Target/ThreadPlanStepThrough.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanStepThrough.cpp?rev=344371&r1=344370&r2=344371&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanStepThrough.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanStepThrough.cpp Fri Oct 12 10:20:39 2018
@@ -13,6 +13,7 @@
// Project includes
#include "lldb/Target/ThreadPlanStepThrough.h"
#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
@@ -95,6 +96,15 @@ void ThreadPlanStepThrough::LookForPlanT
if (objc_runtime)
m_sub_plan_sp =
objc_runtime->GetStepThroughTrampolinePlan(m_thread, m_stop_others);
+
+ CPPLanguageRuntime *cpp_runtime =
+ m_thread.GetProcess()->GetCPPLanguageRuntime();
+
+ // If the ObjC runtime did not provide us with a step though plan then if we
+ // have it check the C++ runtime for a step though plan.
+ if (!m_sub_plan_sp.get() && cpp_runtime)
+ m_sub_plan_sp =
+ cpp_runtime->GetStepThroughTrampolinePlan(m_thread, m_stop_others);
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
More information about the lldb-commits
mailing list