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,138 @@ +""" +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_ +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", # llvm.org/pr23879 ("push {sp}" not handled correctly) + "__aeabi_uldivmod", # llvm.org/pr23879 ("push {sp}" 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 interferes with the software single stepping + "pthread_mutex_unlock", # Uses ldrex and strex what interferes with the software single stepping + "pthread_once", # Uses ldrex and strex what interferes 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") + self.assertEqual(process.GetState(), lldb.eStateStopped, "The process didn't hit main") + + index = 0 + while process.GetState() == lldb.eStateStopped: + index += 1 + if process.GetNumThreads() > 1: + # In case of a multi threaded inferior if one of the thread is stopped in a blocking + # syscall and we try to step it then SBThread::StepInstruction() will block forever + self.skipTest("Multi threaded inferiors are not supported by this test") + + thread = process.GetThreadAtIndex(0) + + if self.TraceOn(): + print "INDEX: %u" % index + 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': f} + elif f.endswith(".c"): + d = {'C_SOURCES': 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: + if self.TraceOn(): + print sys.exc_info()[0] + 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() Index: test/functionalities/unwind/standard/hand_written/fprintf.cpp =================================================================== --- /dev/null +++ test/functionalities/unwind/standard/hand_written/fprintf.cpp @@ -0,0 +1,16 @@ +//===-- 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 + +int +main(int argc, char const *argv[]) +{ + fprintf(stderr, "%d %p %s\n", argc, argv, argv[0]); +} Index: test/functionalities/unwind/standard/hand_written/new_delete.cpp =================================================================== --- /dev/null +++ test/functionalities/unwind/standard/hand_written/new_delete.cpp @@ -0,0 +1,15 @@ +//===-- main.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +int +main(int argc, char const *argv[]) +{ + int* p = new int; + delete p; +}