1import lldb 2from intelpt_testcase import * 3from lldbsuite.test.lldbtest import * 4from lldbsuite.test import lldbutil 5from lldbsuite.test.decorators import * 6 7class TestTraceStartStop(TraceIntelPTTestCaseBase): 8 9 def expectGenericHelpMessageForStartCommand(self): 10 self.expect("help thread trace start", 11 substrs=["Syntax: thread trace start [<trace-options>]"]) 12 13 @testSBAPIAndCommands 14 def testStartStopSessionFileThreads(self): 15 # it should fail for processes from json session files 16 self.expect("trace load -v " + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json")) 17 18 # the help command should be the generic one, as it's not a live process 19 self.expectGenericHelpMessageForStartCommand() 20 21 self.traceStartThread(error=True) 22 23 self.traceStopThread(error=True) 24 25 @testSBAPIAndCommands 26 def testStartWithNoProcess(self): 27 self.traceStartThread(error=True) 28 29 @testSBAPIAndCommands 30 def testStartSessionWithWrongSize(self): 31 self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) 32 self.expect("b main") 33 self.expect("r") 34 35 self.traceStartThread( 36 error=True, iptTraceSize=2000, 37 substrs=["The intel pt trace size must be a power of 2", "It was 2000"]) 38 39 self.traceStartThread( 40 error=True, iptTraceSize=5000, 41 substrs=["The intel pt trace size must be a power of 2", "It was 5000"]) 42 43 self.traceStartThread( 44 error=True, iptTraceSize=0, 45 substrs=["The intel pt trace size must be a power of 2", "It was 0"]) 46 47 self.traceStartThread(iptTraceSize=1048576) 48 49 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 50 def testSBAPIHelp(self): 51 self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) 52 self.expect("b main") 53 self.expect("r") 54 55 help = self.getTraceOrCreate().GetStartConfigurationHelp() 56 self.assertIn("iptTraceSize", help) 57 self.assertIn("processBufferSizeLimit", help) 58 59 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 60 def testStoppingAThread(self): 61 self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) 62 self.expect("b main") 63 self.expect("r") 64 self.expect("thread trace start") 65 self.expect("n") 66 self.expect("thread trace dump instructions", substrs=["""0x0000000000400511 movl $0x0, -0x4(%rbp) 67 no more data"""]) 68 # process stopping should stop the thread 69 self.expect("process trace stop") 70 self.expect("n") 71 self.expect("thread trace dump instructions", substrs=["not traced"], error=True) 72 73 74 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 75 def testStartStopLiveThreads(self): 76 # The help command should be the generic one if there's no process running 77 self.expectGenericHelpMessageForStartCommand() 78 79 self.expect("thread trace start", error=True, 80 substrs=["error: Process not available"]) 81 82 self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) 83 self.expect("b main") 84 85 self.expect("thread trace start", error=True, 86 substrs=["error: Process not available"]) 87 88 # The help command should be the generic one if there's still no process running 89 self.expectGenericHelpMessageForStartCommand() 90 91 self.expect("r") 92 93 # This fails because "trace start" hasn't been called yet 94 self.expect("thread trace stop", error=True, 95 substrs=["error: Process is not being traced"]) 96 97 98 # the help command should be the intel-pt one now 99 self.expect("help thread trace start", 100 substrs=["Start tracing one or more threads with intel-pt.", 101 "Syntax: thread trace start [<thread-index> <thread-index> ...] [<intel-pt-options>]"]) 102 103 # We start tracing with a small buffer size 104 self.expect("thread trace start 1 --size 4096") 105 106 # We fail if we try to trace again 107 self.expect("thread trace start", error=True, 108 substrs=["error: Thread ", "already traced"]) 109 110 # We can reconstruct the single instruction executed in the first line 111 self.expect("n") 112 self.expect("thread trace dump instructions -f", 113 patterns=[f'''thread #1: tid = .* 114 a.out`main \+ 4 at main.cpp:2 115 0: {ADDRESS_REGEX} movl''']) 116 117 # We can reconstruct the instructions up to the second line 118 self.expect("n") 119 self.expect("thread trace dump instructions -f", 120 patterns=[f'''thread #1: tid = .* 121 a.out`main \+ 4 at main.cpp:2 122 0: {ADDRESS_REGEX} movl .* 123 a.out`main \+ 11 at main.cpp:4 124 2: {ADDRESS_REGEX} movl .* 125 4: {ADDRESS_REGEX} jmp .* ; <\+28> at main.cpp:4 126 6: {ADDRESS_REGEX} cmpl .* 127 8: {ADDRESS_REGEX} jle .* ; <\+20> at main.cpp:5''']) 128 129 self.expect("thread trace dump instructions", 130 patterns=[f'''thread #1: tid = .* 131 a.out`main \+ 32 at main.cpp:4 132 8: {ADDRESS_REGEX} jle .* ; <\+20> at main.cpp:5 133 6: {ADDRESS_REGEX} cmpl .* 134 4: {ADDRESS_REGEX} jmp .* ; <\+28> at main.cpp:4 135 2: {ADDRESS_REGEX} movl .* 136 a.out`main \+ 4 at main.cpp:2 137 0: {ADDRESS_REGEX} movl .* ''']) 138 139 # We stop tracing 140 self.expect("thread trace stop") 141 142 # We can't stop twice 143 self.expect("thread trace stop", error=True, 144 substrs=["error: Thread ", "not currently traced"]) 145 146 # We trace again from scratch, this time letting LLDB to pick the current 147 # thread 148 self.expect("thread trace start") 149 self.expect("n") 150 self.expect("thread trace dump instructions -f", 151 patterns=[f'''thread #1: tid = .* 152 a.out`main \+ 20 at main.cpp:5 153 0: {ADDRESS_REGEX} xorl''']) 154 155 self.expect("thread trace dump instructions", 156 patterns=[f'''thread #1: tid = .* 157 a.out`main \+ 20 at main.cpp:5 158 0: {ADDRESS_REGEX} xorl''']) 159 160 self.expect("c") 161 # Now the process has finished, so the commands should fail 162 self.expect("thread trace start", error=True, 163 substrs=["error: Process must be launched"]) 164 165 self.expect("thread trace stop", error=True, 166 substrs=["error: Process must be launched"]) 167 168 # We should be able to trace the program if we relaunch it 169 # For this, we'll trace starting at a different point in the new 170 # process. 171 self.expect("breakpoint disable") 172 self.expect("b main.cpp:4") 173 self.expect("r") 174 self.expect("thread trace start") 175 # We can reconstruct the single instruction executed in the first line 176 self.expect("si") 177 self.expect("thread trace dump instructions -c 1", 178 patterns=[f'''thread #1: tid = .* 179 a.out`main \+ 11 at main.cpp:4''']) 180