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 0000000..ede25f0 --- /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 0000000..a419500 --- /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 0000000..7190e38 --- /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 0000000..b09a579 --- /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 0000000..ddfb112 --- /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 0000000..aaa03e7 --- /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 0000000..146da30 --- /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 0000000..3f88e7b --- /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 0000000..75df6ba --- /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 0000000..188738c --- /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 0000000..d240b89 --- /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; +} |