http://reviews.llvm.org/D10454

Files:
  test/functionalities/unwind/standard/Makefile
  test/functionalities/unwind/standard/TestStandardUnwind.py

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: test/functionalities/unwind/standard/Makefile
===================================================================
--- /dev/null
+++ test/functionalities/unwind/standard/Makefile
@@ -0,0 +1,3 @@
+LEVEL = ../../../make
+
+include $(LEVEL)/Makefile.rules
Index: test/functionalities/unwind/standard/TestStandardUnwind.py
===================================================================
--- /dev/null
+++ test/functionalities/unwind/standard/TestStandardUnwind.py
@@ -0,0 +1,131 @@
+"""
+Test that we can backtrace correctly from standard functions.
+
+This test suit is a collection of automatically generated tests from the source files in the
+directory. Please DON'T add individual test cases to this file.
+
+To add a new test case to this test suit please create a simple C/C++ application and put the
+source file into the directory of the test cases. The test suit will automatically pick the
+file up and generate a test case from it in run time (with name test_standard_unwind_<file_name>
+after escaping some special characters).
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+test_source_dirs = ["."]
+
+class StandardUnwindTest(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    def standard_unwind_tests (self):
+        # The following variables have to be defined for each architecture and OS we testing for:
+        # base_function_names: List of function names where we accept that the stack unwinding is
+        #                      correct if they are on the stack. It should include the bottom most
+        #                      function on the stack and a list of functions where we know we can't
+        #                      unwind for any reason (list of expected failure functions)
+        # no_step_function_names: The list of functions where we don't want to step through
+        #                         instruction by instruction for any reason. (A valid reason is if
+        #                         it is impossible to step through a function instruction by
+        #                         instruction because it is special for some reason.) For these
+        #                         functions we will immediately do a step-out when we hit them.
+
+        triple = self.dbg.GetSelectedPlatform().GetTriple()
+        if re.match("arm-.*-.*-android", triple):
+            base_function_names = [
+                "_start",                # Base function on the stack
+                "__memcpy_base",         # Function reached by a fall through from the previous function
+                "__memcpy_base_aligned", # Function reached by a fall through from the previous function
+                "__subdf3",              # __aeabi_ui2d jumps into the middle of the function. Possibly missing symbol?
+                "__aeabi_ldivmod",       # Do a "push {sp}" what is not handled correctly
+                "__aeabi_uldivmod",      # Do a "push {sp}" what is not handled correctly
+            ]
+            no_step_function_names = [
+                "__sync_fetch_and_add_4", # Calls into a special SO where we can't set a breakpoint
+                "pthread_mutex_lock",     # Uses ldrex and strex what interfiers with the software single stepping
+                "pthread_mutex_unlock",   # Uses ldrex and strex what interfiers with the software single stepping
+                "pthread_once",           # Uses ldrex and strex what interfiers with the software single stepping
+            ]
+        else:
+            self.skipTest("No expectations for the current architecture")
+
+        exe = os.path.join(os.getcwd(), "a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        target.BreakpointCreateByName("main")
+
+        process = target.LaunchSimple (None, None, self.get_process_working_directory())
+        self.assertTrue(process is not None, "SBTarget.Launch() failed")
+
+        index = 0
+        while process.GetState() == lldb.eStateStopped:
+            index += 1
+            for i in range(process.GetNumThreads()):
+                thread = process.GetThreadAtIndex(i)
+
+                if self.TraceOn():
+                    print "INDEX:", index, "THREAD:", i
+                    for f in thread.frames:
+                        print f
+
+                if thread.GetFrameAtIndex(0).GetFunctionName() is not None:
+                    found_main = False
+                    for f in thread.frames:
+                        if f.GetFunctionName() in base_function_names:
+                            found_main = True
+                            break
+                    self.assertTrue(found_main, "Main function isn't found on the backtrace")
+
+                if thread.GetFrameAtIndex(0).GetFunctionName() in no_step_function_names:
+                    thread.StepOut()
+                else:
+                    thread.StepInstruction(False)
+
+# Collect source files in the specified directories
+test_source_files = set([])
+for d in test_source_dirs:
+    if os.path.isabs(d):
+        dirname = d
+    else:
+        dirname = os.path.join(os.path.dirname(__file__), d)
+
+    for root, _, files in os.walk(dirname):
+        test_source_files = test_source_files | set(os.path.abspath(os.path.join(root, f)) for f in files)
+
+# Generate test cases based on the collected source files
+for f in test_source_files:
+    if f.endswith(".cpp") or f.endswith(".c"):
+        @dwarf_test
+        @unittest2.skipIf(TestBase.skipLongRunningTest(), "Skip this long running test")
+        def test_function_dwarf(self, f=f):
+            if f.endswith(".cpp"):
+                d = {'CXX_SOURCES': os.path.join(dirname, f)}
+            elif f.endswith(".c"):
+                d = {'C_SOURCES': os.path.join(dirname, f)}
+
+            # If we can't compile the inferior just skip the test instead of failing it.
+            # It makes the test suit more robust when testing on several different architecture
+            # avoid the hassle of skipping tests manually.
+            try:
+                self.buildDwarf(dictionary=d)
+                self.setTearDownCleanup(d)
+            except:
+                self.skipTest("Inferior not supported")
+            self.standard_unwind_tests()
+
+        test_name = "test_unwind_" + str(f)
+        for c in ".=()/\\":
+            test_name = test_name.replace(c, '_')
+
+        test_function_dwarf.__name__ = test_name
+        setattr(StandardUnwindTest, test_function_dwarf.__name__, test_function_dwarf)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()
_______________________________________________
lldb-commits mailing list
lldb-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits

Reply via email to