1import lldb 2from lldbsuite.test.lldbtest import * 3from lldbsuite.test import lldbutil 4from lldbsuite.test.decorators import * 5 6ADDRESS_REGEX = '0x[0-9a-fA-F]*' 7 8class TestTraceStartStop(TestBase): 9 10 mydir = TestBase.compute_mydir(__file__) 11 NO_DEBUG_INFO_TESTCASE = True 12 13 def setUp(self): 14 TestBase.setUp(self) 15 if 'intel-pt' not in configuration.enabled_plugins: 16 self.skipTest("The intel-pt test plugin is not enabled") 17 18 def expectGenericHelpMessageForStartCommand(self): 19 self.expect("help thread trace start", 20 substrs=["Syntax: thread trace start [<trace-options>]"]) 21 22 def testStartStopSessionFileThreads(self): 23 # it should fail for processes from json session files 24 self.expect("trace load -v " + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json")) 25 self.expect("thread trace start", error=True, 26 substrs=["error: Process must be alive"]) 27 28 # the help command should be the generic one, as it's not a live process 29 self.expectGenericHelpMessageForStartCommand() 30 31 self.expect("thread trace stop", error=True) 32 33 def testStartWithNoProcess(self): 34 self.expect("thread trace start", error=True, 35 substrs=["error: Process not available."]) 36 37 38 def testStartSessionWithWrongSize(self): 39 self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) 40 self.expect("b main") 41 self.expect("r") 42 self.expect("thread trace start -s 2000", error=True, 43 substrs=["The trace buffer size must be a power of 2", "It was 2000"]) 44 self.expect("thread trace start -s 5000", error=True, 45 substrs=["The trace buffer size must be a power of 2", "It was 5000"]) 46 self.expect("thread trace start -s 0", error=True, 47 substrs=["The trace buffer size must be a power of 2", "It was 0"]) 48 self.expect("thread trace start -s 1048576") 49 50 51 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 52 def testStartStopLiveThreads(self): 53 # The help command should be the generic one if there's no process running 54 self.expectGenericHelpMessageForStartCommand() 55 56 self.expect("thread trace start", error=True, 57 substrs=["error: Process not available"]) 58 59 self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) 60 self.expect("b main") 61 62 self.expect("thread trace start", error=True, 63 substrs=["error: Process not available"]) 64 65 # The help command should be the generic one if there's still no process running 66 self.expectGenericHelpMessageForStartCommand() 67 68 self.expect("r") 69 70 # This fails because "trace start" hasn't been called yet 71 self.expect("thread trace stop", error=True, 72 substrs=["error: Process is not being traced"]) 73 74 75 # the help command should be the intel-pt one now 76 self.expect("help thread trace start", 77 substrs=["Start tracing one or more threads with intel-pt.", 78 "Syntax: thread trace start [<thread-index> <thread-index> ...] [<intel-pt-options>]"]) 79 80 # We start tracing with a small buffer size 81 self.expect("thread trace start 1 --size 4096") 82 83 # We fail if we try to trace again 84 self.expect("thread trace start", error=True, 85 substrs=["error: Thread ", "already traced"]) 86 87 # We can reconstruct the single instruction executed in the first line 88 self.expect("n") 89 self.expect("thread trace dump instructions", 90 patterns=[f'''thread #1: tid = .*, total instructions = 1 91 a.out`main \+ 4 at main.cpp:2 92 \[0\] {ADDRESS_REGEX} movl''']) 93 94 # We can reconstruct the instructions up to the second line 95 self.expect("n") 96 self.expect("thread trace dump instructions", 97 patterns=[f'''thread #1: tid = .*, total instructions = 5 98 a.out`main \+ 4 at main.cpp:2 99 \[0\] {ADDRESS_REGEX} movl .* 100 a.out`main \+ 11 at main.cpp:4 101 \[1\] {ADDRESS_REGEX} movl .* 102 \[2\] {ADDRESS_REGEX} jmp .* ; <\+28> at main.cpp:4 103 a.out`main \+ 28 at main.cpp:4 104 \[3\] {ADDRESS_REGEX} cmpl .* 105 \[4\] {ADDRESS_REGEX} jle .* ; <\+20> at main.cpp:5''']) 106 107 # We stop tracing 108 self.expect("thread trace stop") 109 110 # We can't stop twice 111 self.expect("thread trace stop", error=True, 112 substrs=["error: Thread ", "not currently traced"]) 113 114 # We trace again from scratch, this time letting LLDB to pick the current 115 # thread 116 self.expect("thread trace start") 117 self.expect("n") 118 self.expect("thread trace dump instructions", 119 patterns=[f'''thread #1: tid = .*, total instructions = 1 120 a.out`main \+ 20 at main.cpp:5 121 \[0\] {ADDRESS_REGEX} xorl''']) 122 123 self.expect("c") 124 # Now the process has finished, so the commands should fail 125 self.expect("thread trace start", error=True, 126 substrs=["error: Process must be launched"]) 127 128 self.expect("thread trace stop", error=True, 129 substrs=["error: Process must be launched"]) 130