reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
"""Test that lldb functions correctly after the inferior has crashed while in a recursive routine."""

from __future__ import print_function


import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbplatformutil
from lldbsuite.test import lldbutil


class CrashingRecursiveInferiorTestCase(TestBase):

    mydir = TestBase.compute_mydir(__file__)

    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778")
    @expectedFailureNetBSD
    def test_recursive_inferior_crashing(self):
        """Test that lldb reliably catches the inferior crashing (command)."""
        self.build()
        self.recursive_inferior_crashing()

    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778")
    def test_recursive_inferior_crashing_register(self):
        """Test that lldb reliably reads registers from the inferior after crashing (command)."""
        self.build()
        self.recursive_inferior_crashing_registers()

    @add_test_categories(['pyapi'])
    def test_recursive_inferior_crashing_python(self):
        """Test that lldb reliably catches the inferior crashing (Python API)."""
        self.build()
        self.recursive_inferior_crashing_python()

    def test_recursive_inferior_crashing_expr(self):
        """Test that the lldb expression interpreter can read from the inferior after crashing (command)."""
        self.build()
        self.recursive_inferior_crashing_expr()

    def set_breakpoint(self, line):
        lldbutil.run_break_set_by_file_and_line(
            self, "main.c", line, num_expected_locations=1, loc_exact=True)

    def check_stop_reason(self):
        # We should have one crashing thread
        self.assertEqual(
            len(lldbutil.get_crashed_threads(self, self.dbg.GetSelectedTarget().GetProcess())),
            1,
            STOPPED_DUE_TO_EXC_BAD_ACCESS)

    def setUp(self):
        # Call super's setUp().
        TestBase.setUp(self)
        # Find the line number of the crash.
        self.line = line_number('main.c', '// Crash here.')

    def recursive_inferior_crashing(self):
        """Inferior crashes upon launching; lldb should catch the event and stop."""
        exe = self.getBuildArtifact("a.out")
        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)

        self.runCmd("run", RUN_SUCCEEDED)

        # The exact stop reason depends on the platform
        if self.platformIsDarwin():
            stop_reason = 'stop reason = EXC_BAD_ACCESS'
        elif self.getPlatform() == "linux" or self.getPlatform() == "freebsd":
            stop_reason = 'stop reason = signal SIGSEGV'
        else:
            stop_reason = 'stop reason = invalid address'
        self.expect("thread list", STOPPED_DUE_TO_EXC_BAD_ACCESS,
                    substrs=['stopped',
                             stop_reason])

        # And it should report a backtrace that includes main and the crash
        # site.
        self.expect(
            "thread backtrace all",
            substrs=[
                stop_reason,
                'main',
                'argc',
                'argv',
                'recursive_function'])

        # And it should report the correct line number.
        self.expect("thread backtrace all",
                    substrs=[stop_reason,
                             'main.c:%d' % self.line])

    def recursive_inferior_crashing_python(self):
        """Inferior crashes upon launching; lldb should catch the event and stop."""
        exe = self.getBuildArtifact("a.out")

        target = self.dbg.CreateTarget(exe)
        self.assertTrue(target, VALID_TARGET)

        # Now launch the process, and do not stop at entry point.
        # Both argv and envp are null.
        process = target.LaunchSimple(
            None, None, self.get_process_working_directory())

        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()))

        threads = lldbutil.get_crashed_threads(self, process)
        self.assertEqual(
            len(threads),
            1,
            "Failed to stop the thread upon bad access exception")

        if self.TraceOn():
            lldbutil.print_stacktrace(threads[0])

    def recursive_inferior_crashing_registers(self):
        """Test that lldb can read registers after crashing."""
        exe = self.getBuildArtifact("a.out")
        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)

        self.runCmd("run", RUN_SUCCEEDED)
        self.check_stop_reason()

        # lldb should be able to read from registers from the inferior after
        # crashing.
        lldbplatformutil.check_first_register_readable(self)

    def recursive_inferior_crashing_expr(self):
        """Test that the lldb expression interpreter can read symbols after crashing."""
        exe = self.getBuildArtifact("a.out")
        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)

        self.runCmd("run", RUN_SUCCEEDED)
        self.check_stop_reason()

        # The lldb expression interpreter should be able to read from addresses
        # of the inferior after a crash.
        self.expect("p i",
                    startstr='(int) $0 =')