Change the unwinder to not use a hard-coded limit on the
authorJason Molenda <jmolenda@apple.com>
Tue, 25 Sep 2018 21:01:54 +0000 (21:01 +0000)
committerJason Molenda <jmolenda@apple.com>
Tue, 25 Sep 2018 21:01:54 +0000 (21:01 +0000)
max number of stack frames to backtrace, make it a setting,
target.process.thread.max-backtrace-depth.
Add a test case for the setting.

<rdar://problem/28759559>

llvm-svn: 343029

lldb/include/lldb/Target/Thread.h
lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_limit/Makefile [new file with mode: 0644]
lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_limit/TestBacktraceLimit.py [new file with mode: 0644]
lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_limit/main.cpp [new file with mode: 0644]
lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp
lldb/source/Target/Thread.cpp

index 9ce73e0cbeffca9e7c735755ae7f7ae704639c7e..28a477a4d6ed4a32fa8643cb1112f6945fc15fa5 100644 (file)
@@ -57,6 +57,8 @@ public:
   bool GetStepInAvoidsNoDebug() const;
 
   bool GetStepOutAvoidsNoDebug() const;
+  
+  uint64_t GetMaxBacktraceDepth() const;
 };
 
 typedef std::shared_ptr<ThreadProperties> ThreadPropertiesSP;
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_limit/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_limit/Makefile
new file mode 100644 (file)
index 0000000..f0bcf97
--- /dev/null
@@ -0,0 +1,6 @@
+LEVEL = ../../../make
+
+CXXFLAGS += -std=c++11
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_limit/TestBacktraceLimit.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_limit/TestBacktraceLimit.py
new file mode 100644 (file)
index 0000000..4e595ea
--- /dev/null
@@ -0,0 +1,31 @@
+"""
+Test that the target.process.thread.max-backtrace-depth setting works.
+"""
+
+import unittest2
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class BacktraceLimitSettingTest(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+
+    def test_backtrace_depth(self):
+        """Test that the max-backtrace-depth setting limits backtraces."""
+        self.build()
+        self.main_source_file = lldb.SBFileSpec("main.cpp")
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
+                "Set a breakpoint here", self.main_source_file)
+        interp = self.dbg.GetCommandInterpreter()
+        result = lldb.SBCommandReturnObject()
+        interp.HandleCommand("settings set target.process.thread.max-backtrace-depth 30", result)
+        self.assertEqual(True, result.Succeeded())
+        self.assertEqual(30, thread.GetNumFrames())
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_limit/main.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_limit/main.cpp
new file mode 100644 (file)
index 0000000..eca1ead
--- /dev/null
@@ -0,0 +1,13 @@
+int bottom () { 
+  return 1;  // Set a breakpoint here
+} 
+int foo(int in) { 
+  if (in > 0)
+    return foo(--in) + 5; 
+  else
+    return bottom();
+}
+int main()
+{
+   return foo(500);
+}
index 55559f07f1e5ac881373721c792889e64558e72e..49c06fea78a845056000aac0468bed7d480ae727 100644 (file)
@@ -130,6 +130,8 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) {
   RegisterContextLLDBSP reg_ctx_sp(new RegisterContextLLDB(
       m_thread, prev_frame->reg_ctx_lldb_sp, cursor_sp->sctx, cur_idx, *this));
 
+  uint64_t max_stack_depth = m_thread.GetMaxBacktraceDepth();
+
   // We want to detect an unwind that cycles erroneously and stop backtracing.
   // Don't want this maximum unwind limit to be too low -- if you have a
   // backtrace with an "infinitely recursing" bug, it will crash when the stack
@@ -138,7 +140,7 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) {
   // unwind at 10,000 or something. Realistically anything over around 200,000
   // is going to blow out the stack space. If we're still unwinding at that
   // point, we're probably never going to finish.
-  if (cur_idx > 300000) {
+  if (cur_idx >= max_stack_depth) {
     if (log)
       log->Printf("%*sFrame %d unwound too many frames, assuming unwind has "
                   "gone astray, stopping.",
index 7fbad420700ca9a8eb40ec4bf7014f76beb3d262..660cb773d11acfec528fc18f197f17f32c34ae02 100644 (file)
@@ -80,6 +80,8 @@ static PropertyDefinition g_properties[] = {
      nullptr, "A list of libraries that source stepping won't stop in."},
     {"trace-thread", OptionValue::eTypeBoolean, false, false, nullptr, nullptr,
      "If true, this thread will single-step and log execution."},
+    {"max-backtrace-depth", OptionValue::eTypeUInt64, false, 300000, nullptr,
+     nullptr, "Maximum number of frames to backtrace."},
     {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}};
 
 enum {
@@ -87,7 +89,8 @@ enum {
   ePropertyStepOutAvoidsNoDebug,
   ePropertyStepAvoidRegex,
   ePropertyStepAvoidLibraries,
-  ePropertyEnableThreadTrace
+  ePropertyEnableThreadTrace,
+  ePropertyMaxBacktraceDepth
 };
 
 class ThreadOptionValueProperties : public OptionValueProperties {
@@ -165,6 +168,12 @@ bool ThreadProperties::GetStepOutAvoidsNoDebug() const {
       nullptr, idx, g_properties[idx].default_uint_value != 0);
 }
 
+uint64_t ThreadProperties::GetMaxBacktraceDepth() const {
+  const uint32_t idx = ePropertyMaxBacktraceDepth;
+  return m_collection_sp->GetPropertyAtIndexAsUInt64(
+      nullptr, idx, g_properties[idx].default_uint_value != 0);
+}
+
 //------------------------------------------------------------------
 // Thread Event Data
 //------------------------------------------------------------------