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 @testSBAPIAndCommands 50 def testStartSessionWithSizeDeclarationInUnits(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 self.traceStartThread( 56 error=True, iptTraceSize="abc", 57 substrs=["invalid bytes expression for 'abc'"]) 58 59 self.traceStartThread( 60 error=True, iptTraceSize="123.12", 61 substrs=["invalid bytes expression for '123.12'"]) 62 63 self.traceStartThread( 64 error=True, iptTraceSize="\"\"", 65 substrs=["invalid bytes expression for ''"]) 66 67 self.traceStartThread( 68 error=True, iptTraceSize="2000B", 69 substrs=["The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 2000"]) 70 71 self.traceStartThread( 72 error=True, iptTraceSize="3MB", 73 substrs=["The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3145728"]) 74 75 self.traceStartThread( 76 error=True, iptTraceSize="3MiB", 77 substrs=["The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3145728"]) 78 79 self.traceStartThread( 80 error=True, iptTraceSize="3mib", 81 substrs=["The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3145728"]) 82 83 self.traceStartThread( 84 error=True, iptTraceSize="3M", 85 substrs=["The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3145728"]) 86 87 self.traceStartThread( 88 error=True, iptTraceSize="3KB", 89 substrs=["The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3072"]) 90 91 self.traceStartThread( 92 error=True, iptTraceSize="3KiB", 93 substrs=["The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3072"]) 94 95 self.traceStartThread( 96 error=True, iptTraceSize="3K", 97 substrs=["The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3072"]) 98 99 self.traceStartThread( 100 error=True, iptTraceSize="3MS", 101 substrs=["invalid bytes expression for '3MS'"]) 102 103 self.traceStartThread(iptTraceSize="1048576") 104 105 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 106 def testSBAPIHelp(self): 107 self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) 108 self.expect("b main") 109 self.expect("r") 110 111 help = self.getTraceOrCreate().GetStartConfigurationHelp() 112 self.assertIn("iptTraceSize", help) 113 self.assertIn("processBufferSizeLimit", help) 114 115 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 116 def testStoppingAThread(self): 117 self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) 118 self.expect("b main") 119 self.expect("r") 120 self.expect("thread trace start") 121 self.expect("n") 122 self.expect("thread trace dump instructions", substrs=["""0x0000000000400511 movl $0x0, -0x4(%rbp) 123 no more data"""]) 124 # process stopping should stop the thread 125 self.expect("process trace stop") 126 self.expect("n") 127 self.expect("thread trace dump instructions", substrs=["not traced"], error=True) 128 129 130 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 131 def testStartStopLiveThreads(self): 132 # The help command should be the generic one if there's no process running 133 self.expectGenericHelpMessageForStartCommand() 134 135 self.expect("thread trace start", error=True, 136 substrs=["error: Process not available"]) 137 138 self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) 139 self.expect("b main") 140 141 self.expect("thread trace start", error=True, 142 substrs=["error: Process not available"]) 143 144 # The help command should be the generic one if there's still no process running 145 self.expectGenericHelpMessageForStartCommand() 146 147 self.expect("r") 148 149 # This fails because "trace start" hasn't been called yet 150 self.expect("thread trace stop", error=True, 151 substrs=["error: Process is not being traced"]) 152 153 154 # the help command should be the intel-pt one now 155 self.expect("help thread trace start", 156 substrs=["Start tracing one or more threads with intel-pt.", 157 "Syntax: thread trace start [<thread-index> <thread-index> ...] [<intel-pt-options>]"]) 158 159 # We start tracing with a small buffer size 160 self.expect("thread trace start 1 --size 4096") 161 162 # We fail if we try to trace again 163 self.expect("thread trace start", error=True, 164 substrs=["error: Thread ", "already traced"]) 165 166 # We can reconstruct the single instruction executed in the first line 167 self.expect("n") 168 self.expect("thread trace dump instructions -f", 169 patterns=[f'''thread #1: tid = .* 170 a.out`main \+ 4 at main.cpp:2 171 0: {ADDRESS_REGEX} movl''']) 172 173 # We can reconstruct the instructions up to the second line 174 self.expect("n") 175 self.expect("thread trace dump instructions -f", 176 patterns=[f'''thread #1: tid = .* 177 a.out`main \+ 4 at main.cpp:2 178 0: {ADDRESS_REGEX} movl .* 179 a.out`main \+ 11 at main.cpp:4 180 2: {ADDRESS_REGEX} movl .* 181 4: {ADDRESS_REGEX} jmp .* ; <\+28> at main.cpp:4 182 6: {ADDRESS_REGEX} cmpl .* 183 8: {ADDRESS_REGEX} jle .* ; <\+20> at main.cpp:5''']) 184 185 self.expect("thread trace dump instructions", 186 patterns=[f'''thread #1: tid = .* 187 a.out`main \+ 32 at main.cpp:4 188 8: {ADDRESS_REGEX} jle .* ; <\+20> at main.cpp:5 189 6: {ADDRESS_REGEX} cmpl .* 190 4: {ADDRESS_REGEX} jmp .* ; <\+28> at main.cpp:4 191 2: {ADDRESS_REGEX} movl .* 192 a.out`main \+ 4 at main.cpp:2 193 0: {ADDRESS_REGEX} movl .* ''']) 194 195 # We stop tracing 196 self.expect("thread trace stop") 197 198 # We can't stop twice 199 self.expect("thread trace stop", error=True, 200 substrs=["error: Thread ", "not currently traced"]) 201 202 # We trace again from scratch, this time letting LLDB to pick the current 203 # thread 204 self.expect("thread trace start") 205 self.expect("n") 206 self.expect("thread trace dump instructions -f", 207 patterns=[f'''thread #1: tid = .* 208 a.out`main \+ 20 at main.cpp:5 209 0: {ADDRESS_REGEX} xorl''']) 210 211 self.expect("thread trace dump instructions", 212 patterns=[f'''thread #1: tid = .* 213 a.out`main \+ 20 at main.cpp:5 214 0: {ADDRESS_REGEX} xorl''']) 215 216 self.expect("c") 217 # Now the process has finished, so the commands should fail 218 self.expect("thread trace start", error=True, 219 substrs=["error: Process must be launched"]) 220 221 self.expect("thread trace stop", error=True, 222 substrs=["error: Process must be launched"]) 223 224 # We should be able to trace the program if we relaunch it 225 # For this, we'll trace starting at a different point in the new 226 # process. 227 self.expect("breakpoint disable") 228 self.expect("b main.cpp:4") 229 self.expect("r") 230 self.expect("thread trace start") 231 # We can reconstruct the single instruction executed in the first line 232 self.expect("si") 233 self.expect("thread trace dump instructions -c 1", 234 patterns=[f'''thread #1: tid = .* 235 a.out`main \+ 11 at main.cpp:4''']) 236