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
"""
Test thread creation after process attach.
"""

from __future__ import print_function


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


class CreateAfterAttachTestCase(TestBase):

    mydir = TestBase.compute_mydir(__file__)

    @skipIfFreeBSD  # Hangs.  May be the same as Linux issue llvm.org/pr16229 but
    # not yet investigated.  Revisit once required functionality
    # is implemented for FreeBSD.
    # Occasionally hangs on Windows, may be same as other issues.
    @skipIfWindows
    @skipIfiOSSimulator
    @expectedFailureNetBSD
    def test_create_after_attach_with_popen(self):
        """Test thread creation after process attach."""
        self.build(dictionary=self.getBuildFlags(use_cpp11=False))
        self.create_after_attach(use_fork=False)

    @skipIfFreeBSD  # Hangs. Revisit once required functionality is implemented
    # for FreeBSD.
    @skipIfRemote
    @skipIfWindows  # Windows doesn't have fork.
    @skipIfiOSSimulator
    @expectedFailureNetBSD
    def test_create_after_attach_with_fork(self):
        """Test thread creation after process attach."""
        self.build(dictionary=self.getBuildFlags(use_cpp11=False))
        self.create_after_attach(use_fork=True)

    def setUp(self):
        # Call super's setUp().
        TestBase.setUp(self)
        # Find the line numbers for our breakpoints.
        self.break_1 = line_number('main.cpp', '// Set first breakpoint here')
        self.break_2 = line_number('main.cpp', '// Set second breakpoint here')
        self.break_3 = line_number('main.cpp', '// Set third breakpoint here')

    def create_after_attach(self, use_fork):
        """Test thread creation after process attach."""

        exe = self.getBuildArtifact("a.out")

        # Spawn a new process
        if use_fork:
            pid = self.forkSubprocess(exe)
        else:
            popen = self.spawnSubprocess(exe)
            pid = popen.pid
        self.addTearDownHook(self.cleanupSubprocesses)

        # Attach to the spawned process
        self.runCmd("process attach -p " + str(pid))

        target = self.dbg.GetSelectedTarget()

        process = target.GetProcess()
        self.assertTrue(process, PROCESS_IS_VALID)

        # This should create a breakpoint in the main thread.
        lldbutil.run_break_set_by_file_and_line(
            self, "main.cpp", self.break_1, num_expected_locations=1)

        # This should create a breakpoint in the second child thread.
        lldbutil.run_break_set_by_file_and_line(
            self, "main.cpp", self.break_2, num_expected_locations=1)

        # This should create a breakpoint in the first child thread.
        lldbutil.run_break_set_by_file_and_line(
            self, "main.cpp", self.break_3, num_expected_locations=1)

        # Note:  With std::thread, we cannot rely on particular thread numbers.  Using
        # std::thread may cause the program to spin up a thread pool (and it does on
        # Windows), so the thread numbers are non-deterministic.

        # Run to the first breakpoint
        self.runCmd("continue")

        # The stop reason of the thread should be breakpoint.
        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
                    substrs=['stopped',
                             '* thread #',
                             'main',
                             'stop reason = breakpoint'])

        # Change a variable to escape the loop
        self.runCmd("expression main_thread_continue = 1")

        # Run to the second breakpoint
        self.runCmd("continue")

        # The stop reason of the thread should be breakpoint.
        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
                    substrs=['stopped',
                             '* thread #',
                             'thread_2_func',
                             'stop reason = breakpoint'])

        # Change a variable to escape the loop
        self.runCmd("expression child_thread_continue = 1")

        # Run to the third breakpoint
        self.runCmd("continue")

        # The stop reason of the thread should be breakpoint.
        # Thread 3 may or may not have already exited.
        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
                    substrs=['stopped',
                             '* thread #',
                             'thread_1_func',
                             'stop reason = breakpoint'])

        # Run to completion
        self.runCmd("continue")

        # At this point, the inferior process should have exited.
        self.assertTrue(
            process.GetState() == lldb.eStateExited,
            PROCESS_EXITED)