diff options
Diffstat (limited to 'packages/Python/lldbsuite/test/functionalities/unwind')
11 files changed, 427 insertions, 0 deletions
| diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/Makefile b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/Makefile new file mode 100644 index 0000000000000..ede25f029bcd6 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/Makefile @@ -0,0 +1,7 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +CFLAGS ?= -g -Os + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py new file mode 100644 index 0000000000000..a419500f7a175 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py @@ -0,0 +1,76 @@ +""" +Test that we can backtrace correctly with 'noreturn' functions on the stack +""" + +from __future__ import print_function + + + +import os, time +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + +class NoreturnUnwind(TestBase): +    mydir = TestBase.compute_mydir(__file__) + +    @expectedFailurei386 #xfail to get buildbot green, failing config: i386 binary running on ubuntu 14.04 x86_64 +    @skipIfWindows # clang-cl does not support gcc style attributes. +    def test (self): +        """Test that we can backtrace correctly with 'noreturn' functions on the stack""" +        self.build() +        self.setTearDownCleanup() + +        exe = os.path.join(os.getcwd(), "a.out") +        target = self.dbg.CreateTarget(exe) +        self.assertTrue(target, VALID_TARGET) + +        process = target.LaunchSimple (None, None, self.get_process_working_directory()) + +        if not process: +            self.fail("SBTarget.Launch() failed") + +        if process.GetState() != lldb.eStateStopped: +            self.fail("Process should be in the 'stopped' state, " +                      "instead the actual state is: '%s'" % +                      lldbutil.state_type_to_str(process.GetState())) + +        thread = process.GetThreadAtIndex(0) +        abort_frame_number = 0 +        for f in thread.frames: +            # Some C libraries mangle the abort symbol into __GI_abort. +            if f.GetFunctionName() in ["abort", "__GI_abort"]: +                break +            abort_frame_number = abort_frame_number + 1 + +        if self.TraceOn(): +            print("Backtrace once we're stopped:") +            for f in thread.frames: +                print("  %d %s" % (f.GetFrameID(), f.GetFunctionName())) + +        # I'm going to assume that abort() ends up calling/invoking another +        # function before halting the process.  In which case if abort_frame_number +        # equals 0, we didn't find abort() in the backtrace. +        if abort_frame_number == len(thread.frames): +            self.fail("Unable to find abort() in backtrace.") + +        func_c_frame_number = abort_frame_number + 1 +        if thread.GetFrameAtIndex (func_c_frame_number).GetFunctionName() != "func_c": +            self.fail("Did not find func_c() above abort().") + +        # This depends on whether we see the func_b inlined function in the backtrace +        # or not.  I'm not interested in testing that aspect of the backtrace here +        # right now. + +        if thread.GetFrameAtIndex (func_c_frame_number + 1).GetFunctionName() == "func_b": +            func_a_frame_number = func_c_frame_number + 2 +        else: +            func_a_frame_number = func_c_frame_number + 1 + +        if thread.GetFrameAtIndex (func_a_frame_number).GetFunctionName() != "func_a": +            self.fail("Did not find func_a() above func_c().") + +        main_frame_number = func_a_frame_number + 1 + +        if thread.GetFrameAtIndex (main_frame_number).GetFunctionName() != "main": +            self.fail("Did not find main() above func_a().") diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c new file mode 100644 index 0000000000000..7190e38f5d8c6 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static void func_a (void) __attribute__((noinline)); +static void func_b (void) __attribute__((noreturn)); +static void func_c (void) __attribute__((noinline)); + +static void +func_c (void) +{ +	abort (); +} + +static void +func_b (void) +{ +	func_c (); +	while (1) +        ; +} + +static void +func_a (void) +{ +	func_b (); +} + +int +main (int argc, char *argv[]) +{ +    sleep (2); + +	func_a (); + +	return 0; +} diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/Makefile b/packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/Makefile new file mode 100644 index 0000000000000..b09a579159d48 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/TestSigtrampUnwind.py b/packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/TestSigtrampUnwind.py new file mode 100644 index 0000000000000..ddfb1122b6f18 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/TestSigtrampUnwind.py @@ -0,0 +1,81 @@ +""" +Test that we can backtrace correctly with 'sigtramp' functions on the stack +""" + +from __future__ import print_function + + + +import os, time +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + +class SigtrampUnwind(TestBase): +    mydir = TestBase.compute_mydir(__file__) + +    # On different platforms the "_sigtramp" and "__kill" frames are likely to be different. +    # This test could probably be adapted to run on linux/*bsd easily enough. +    @skipUnlessDarwin +    def test (self): +        """Test that we can backtrace correctly with _sigtramp on the stack""" +        self.build() +        self.setTearDownCleanup() + +        exe = os.path.join(os.getcwd(), "a.out") +        target = self.dbg.CreateTarget(exe) +        self.assertTrue(target, VALID_TARGET) + + +        lldbutil.run_break_set_by_file_and_line (self, "main.c", line_number('main.c', '// Set breakpoint here'), num_expected_locations=1) + +        process = target.LaunchSimple (None, None, self.get_process_working_directory()) + +        if not process: +            self.fail("SBTarget.Launch() failed") + +        if process.GetState() != lldb.eStateStopped: +            self.fail("Process should be in the 'stopped' state, " +                      "instead the actual state is: '%s'" % +                      lldbutil.state_type_to_str(process.GetState())) + +        self.expect("pro handle  -n false -p true -s false SIGUSR1", "Have lldb pass SIGUSR1 signals", +            substrs = ["SIGUSR1", "true", "false", "false"]) + +        lldbutil.run_break_set_by_symbol (self, "handler", num_expected_locations=1, module_name="a.out") + +        self.runCmd("continue") + +        thread = process.GetThreadAtIndex(0) + +        found_handler = False +        found_sigtramp = False +        found_kill = False +        found_main = False + +        for f in thread.frames: +            if f.GetFunctionName() == "handler": +                found_handler = True +            if f.GetFunctionName() == "_sigtramp": +                found_sigtramp = True +            if f.GetFunctionName() == "__kill": +                found_kill = True +            if f.GetFunctionName() == "main": +                found_main = True + +        if self.TraceOn(): +            print("Backtrace once we're stopped:") +            for f in thread.frames: +                print("  %d %s" % (f.GetFrameID(), f.GetFunctionName())) + +        if found_handler == False: +            self.fail("Unable to find handler() in backtrace.") + +        if found_sigtramp == False: +            self.fail("Unable to find _sigtramp() in backtrace.") + +        if found_kill == False: +            self.fail("Unable to find kill() in backtrace.") + +        if found_main == False: +            self.fail("Unable to find main() in backtrace.") diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/main.c b/packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/main.c new file mode 100644 index 0000000000000..aaa03e7aa843d --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/main.c @@ -0,0 +1,27 @@ +#include <stdlib.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + +void handler (int in) +{ +    puts ("in handler routine"); +    while (1) +        ; +} + +void +foo () +{ +    puts ("in foo ()"); +    kill (getpid(), SIGUSR1); +} +int main () +{ +    puts ("in main");           // Set breakpoint here +    signal (SIGUSR1, handler); +    puts ("signal handler set up"); +    foo(); +    puts ("exiting"); +    return 0; +} diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/standard/Makefile b/packages/Python/lldbsuite/test/functionalities/unwind/standard/Makefile new file mode 100644 index 0000000000000..146da30b12cb8 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/standard/Makefile @@ -0,0 +1,3 @@ +LEVEL = ../../../make + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/standard/TestStandardUnwind.py b/packages/Python/lldbsuite/test/functionalities/unwind/standard/TestStandardUnwind.py new file mode 100644 index 0000000000000..3f88e7b6e1aa1 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/standard/TestStandardUnwind.py @@ -0,0 +1,145 @@ +""" +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). +""" + +from __future__ import print_function + + + +import unittest2 +import os, time +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as 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 +            ] +            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 +            ] +        elif re.match("aarch64-.*-.*-android", triple): +            base_function_names = [ +                "do_arm64_start",         # Base function on the stack +            ] +            no_step_function_names = [ +                None, +                "__cxa_guard_acquire",    # Uses ldxr and stxr what interferes with the software single stepping +                "__cxa_guard_release",    # Uses ldxr and stxr what interferes with the software single stepping +                "pthread_mutex_lock",     # Uses ldxr and stxr what interferes with the software single stepping +                "pthread_mutex_unlock",   # Uses ldxr and stxr what interferes with the software single stepping +                "pthread_once",           # Uses ldxr and stxr 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"): +        @add_test_categories(["dwarf"]) +        @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) diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/standard/hand_written/divmod.cpp b/packages/Python/lldbsuite/test/functionalities/unwind/standard/hand_written/divmod.cpp new file mode 100644 index 0000000000000..75df6ba89372b --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/standard/hand_written/divmod.cpp @@ -0,0 +1,15 @@ +//===-- divmod.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[]) +{ +    signed long long a = 123456789, b = 12, c = a / b, d = a % b; +    unsigned long long e = 123456789, f = 12, g = e / f, h = e % f; +} diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/standard/hand_written/fprintf.cpp b/packages/Python/lldbsuite/test/functionalities/unwind/standard/hand_written/fprintf.cpp new file mode 100644 index 0000000000000..188738cb9babf --- /dev/null +++ b/packages/Python/lldbsuite/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 <cstdio> + +int +main(int argc, char const *argv[]) +{ +    fprintf(stderr, "%d %p %s\n", argc, argv, argv[0]); +} diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/standard/hand_written/new_delete.cpp b/packages/Python/lldbsuite/test/functionalities/unwind/standard/hand_written/new_delete.cpp new file mode 100644 index 0000000000000..d240b89e50abb --- /dev/null +++ b/packages/Python/lldbsuite/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; +} | 
