shafik created this revision.
shafik added reviewers: jingham, davide, aprantl.
Herald added a reviewer: EricWF.
- Adding support to step into the callable wrapped by libc++ std::function
- Adding test to validate that functionality
https://reviews.llvm.org/D52851
Files:
include/lldb/Target/CPPLanguageRuntime.h
packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/Makefile
packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/TestStdFunctionStepIntoCallable.py
packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/main.cpp
source/Target/CPPLanguageRuntime.cpp
source/Target/ThreadPlanStepThrough.cpp
Index: source/Target/ThreadPlanStepThrough.cpp
===================================================================
--- source/Target/ThreadPlanStepThrough.cpp
+++ source/Target/ThreadPlanStepThrough.cpp
@@ -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,13 @@
if (objc_runtime)
m_sub_plan_sp =
objc_runtime->GetStepThroughTrampolinePlan(m_thread, m_stop_others);
+
+ CPPLanguageRuntime *cpp_runtime =
+ m_thread.GetProcess()->GetCPPLanguageRuntime();
+
+ if (cpp_runtime)
+ m_sub_plan_sp =
+ cpp_runtime->GetStepThroughTrampolinePlan(m_thread, m_stop_others);
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
Index: source/Target/CPPLanguageRuntime.cpp
===================================================================
--- source/Target/CPPLanguageRuntime.cpp
+++ source/Target/CPPLanguageRuntime.cpp
@@ -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 @@
// 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,77 @@
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.
+ // Currently due to the the:
+ //
+ // target.process.thread.step-avoid-regexp
+ //
+ // setting we will currenly step right out of standard library code.
+ //
+ // The new 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()) {
+ ret_plan_sp.reset(new ThreadPlanRunToAddress(
+ thread, callable_info.callable_address, stop_others));
+ return ret_plan_sp;
+ } else {
+ ret_plan_sp.reset(new ThreadPlanStepInRange(thread, range_of_curr_func,
+ sc, eOnlyThisThread,
+ eLazyBoolYes, eLazyBoolYes));
+ return ret_plan_sp;
+ }
+ }
+
+ return ret_plan_sp;
+}
Index: packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/main.cpp
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/main.cpp
@@ -0,0 +1,44 @@
+//===-- main.cpp --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <functional>
+
+int foo(int x, int y) {
+ return x + y - 1;
+}
+
+struct Bar {
+ int operator()() {
+ return 66 ;
+ }
+ int add_num(int i) const { return i + 3 ; }
+} ;
+
+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);
+ };
+
+ auto f = [](int x, int y) { return x + y; };
+ 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;
+
+ return f1(acc,acc) + // Set break point at this line.
+ 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.
+}
Index: packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/TestStdFunctionStepIntoCallable.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/TestStdFunctionStepIntoCallable.py
@@ -0,0 +1,73 @@
+"""
+Test lldb data formatter subsystem.
+"""
+
+from __future__ import print_function
+
+
+import os
+import time
+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__)
+
+ def get_variable(self, name):
+ var = self.frame().FindVariable(name)
+ var.SetPreferDynamicValue(lldb.eDynamicCanRunTarget)
+ var.SetPreferSyntheticValue(True)
+ return var
+
+ @add_test_categories(["libc++"])
+ def test(self):
+ """Test that std::function as defined by libc++ is correctly printed by LLDB"""
+ self.build()
+ self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
+
+ exe = self.getBuildArtifact("a.out")
+ self.main_source = "main.cpp"
+ self.main_source_spec = lldb.SBFileSpec(self.main_source)
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+
+ break_in_main = target.BreakpointCreateBySourceRegex('// Set break point at this line.', self.main_source_spec)
+ self.assertTrue(break_in_main, VALID_BREAKPOINT)
+
+ self.process = target.LaunchSimple(
+ None, None, self.get_process_working_directory())
+
+ self.assertTrue(self.process, PROCESS_IS_VALID)
+
+ threads = lldbutil.get_stopped_threads(
+ self.process, lldb.eStopReasonBreakpoint)
+ self.assertTrue(
+ len(threads) == 1,
+ "Successfully ran to breakpoint.")
+ self.thread = threads[0]
+
+ self.thread.StepInto()
+ self.assertEqual( self.thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), 13 ) ;
+ self.process.Continue()
+
+ self.thread.StepInto()
+ self.assertEqual( self.thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), 28 ) ;
+ self.process.Continue()
+
+ self.thread.StepInto()
+ self.assertEqual( self.thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), 31 ) ;
+ self.process.Continue()
+
+ self.thread.StepInto()
+ self.assertEqual( self.thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), 18 ) ;
+ self.process.Continue()
+
+ self.thread.StepInto()
+ self.assertEqual( self.thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), 20 ) ;
+ self.process.Continue()
Index: packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/Makefile
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/std-function-step-into-callable/Makefile
@@ -0,0 +1,7 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+CXXFLAGS += -std=c++11
+USE_LIBCPP := 1
+
+include $(LEVEL)/Makefile.rules
Index: include/lldb/Target/CPPLanguageRuntime.h
===================================================================
--- include/lldb/Target/CPPLanguageRuntime.h
+++ include/lldb/Target/CPPLanguageRuntime.h
@@ -56,6 +56,9 @@
bool GetObjectDescription(Stream &str, Value &value,
ExecutionContextScope *exe_scope) override;
+ lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop_others);
+
protected:
//------------------------------------------------------------------
// Classes that inherit from CPPLanguageRuntime can see and modify these
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits