1import lldb
2from intelpt_testcase import *
3from lldbsuite.test.lldbtest import *
4from lldbsuite.test import lldbutil
5from lldbsuite.test.decorators import *
6
7class TestTraceLoad(TraceIntelPTTestCaseBase):
8    NO_DEBUG_INFO_TESTCASE = True
9
10    @testSBAPIAndCommands
11    def testLoadMultiCoreTrace(self):
12        src_dir = self.getSourceDir()
13        trace_description_file_path = os.path.join(src_dir, "intelpt-multi-core-trace", "trace.json")
14        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, substrs=["intel-pt"])
15        self.expect("thread trace dump instructions 2 -t",
16          substrs=["19531: [20456511.000 ns] (error) expected tracing enabled event",
17                   "m.out`foo() + 65 at multi_thread.cpp:12:21",
18                   "19523: [19691630.216 ns] 0x0000000000400ba7    jg     0x400bb3"])
19        self.expect("thread trace dump instructions 3 -t",
20          substrs=["67919: [19736130.084 ns] 0x0000000000400bd7    addl   $0x1, -0x4(%rbp)",
21                   "m.out`bar() + 26 at multi_thread.cpp:20:6"])
22
23        self.expect("thread trace dump info --json",
24          substrs=['''{
25  "traceTechnology": "intel-pt",
26  "threadStats": {
27    "tid": 3497234,
28    "traceItemsCount": 0,
29    "memoryUsage": {
30      "totalInBytes": "0",
31      "avgPerItemInBytes": null
32    },
33    "timingInSeconds": {
34      "Decoding instructions": ''', '''
35    },
36    "events": {
37      "totalCount": 0,
38      "individualCounts": {}
39    },
40    "continuousExecutions": 0,
41    "PSBBlocks": 0,
42    "errorItems": {
43      "total": 0,
44      "individualErrors": {}
45    }
46  },
47  "globalStats": {
48    "timingInSeconds": {
49      "Context switch and Intel PT traces correlation": 0
50    },
51    "totalUnattributedPSBBlocks": 0,
52    "totalCountinuosExecutions": 153,
53    "totalPSBBlocks": 5,
54    "totalContinuousExecutions": 153
55  }
56}'''])
57
58        self.expect("thread trace dump info 2 --json",
59          substrs=['''{
60  "traceTechnology": "intel-pt",
61  "threadStats": {
62    "tid": 3497496,
63    "traceItemsCount": 19533,
64    "memoryUsage": {
65      "totalInBytes": "176097",
66      "avgPerItemInBytes": 9.''', '''},
67    "timingInSeconds": {
68      "Decoding instructions": ''', '''
69    },
70    "events": {
71      "totalCount": 11,
72      "individualCounts": {
73        "software disabled tracing": 1,
74        "HW clock tick": 9,
75        "CPU core changed": 1
76      }
77    },
78    "continuousExecutions": 1,
79    "PSBBlocks": 1,
80    "errorItems": {
81      "total": 0,
82      "individualErrors": {}
83    }
84  },
85  "globalStats": {
86    "timingInSeconds": {
87      "Context switch and Intel PT traces correlation": 0''', '''},
88    "totalUnattributedPSBBlocks": 0,
89    "totalCountinuosExecutions": 153,
90    "totalPSBBlocks": 5,
91    "totalContinuousExecutions": 153
92  }
93}'''])
94
95    @testSBAPIAndCommands
96    def testLoadCompactMultiCoreTrace(self):
97        src_dir = self.getSourceDir()
98        trace_description_file_path = os.path.join(src_dir, "intelpt-multi-core-trace", "trace.json")
99        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, substrs=["intel-pt"])
100
101        self.expect("thread trace dump info 2", substrs=["Total number of continuous executions found: 153"])
102
103        # we'll save the trace in compact format
104        compact_trace_bundle_dir = os.path.join(self.getBuildDir(), "intelpt-multi-core-trace-compact")
105        self.traceSave(compact_trace_bundle_dir, compact=True)
106
107        # we'll delete the previous target and make sure it's trace object is deleted
108        self.dbg.DeleteTarget(self.dbg.GetTargetAtIndex(0))
109        self.expect("thread trace dump instructions 2 -t", substrs=["error: invalid target"], error=True)
110
111        # we'll load the compact trace and make sure it works
112        self.traceLoad(os.path.join(compact_trace_bundle_dir, "trace.json"), substrs=["intel-pt"])
113        self.expect("thread trace dump instructions 2 -t",
114          substrs=["19531: [20456511.000 ns] (error) expected tracing enabled event",
115                   "m.out`foo() + 65 at multi_thread.cpp:12:21",
116                   "19523: [19691630.216 ns] 0x0000000000400ba7    jg     0x400bb3"])
117        self.expect("thread trace dump instructions 3 -t",
118          substrs=["67919: [19736130.084 ns] 0x0000000000400bd7    addl   $0x1, -0x4(%rbp)",
119                   "m.out`bar() + 26 at multi_thread.cpp:20:6"])
120
121        # This reduced the number of continuous executions to look at
122        self.expect("thread trace dump info 2", substrs=["Total number of continuous executions found: 3"])
123
124        # We clean up for the next run of this test
125        self.dbg.DeleteTarget(self.dbg.GetTargetAtIndex(0))
126
127    @testSBAPIAndCommands
128    def testLoadMultiCoreTraceWithStringNumbers(self):
129        src_dir = self.getSourceDir()
130        trace_description_file_path = os.path.join(src_dir, "intelpt-multi-core-trace", "trace_with_string_numbers.json")
131        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, substrs=["intel-pt"])
132        self.expect("thread trace dump instructions 2 -t",
133          substrs=["19531: [20456511.000 ns] (error) expected tracing enabled event",
134                   "m.out`foo() + 65 at multi_thread.cpp:12:21",
135                   "19523: [19691630.216 ns] 0x0000000000400ba7    jg     0x400bb3"])
136        self.expect("thread trace dump instructions 3 -t",
137          substrs=["67919: [19736130.084 ns] 0x0000000000400bd7    addl   $0x1, -0x4(%rbp)",
138                   "m.out`bar() + 26 at multi_thread.cpp:20:6"])
139
140    @testSBAPIAndCommands
141    def testLoadMultiCoreTraceWithMissingThreads(self):
142        src_dir = self.getSourceDir()
143        trace_description_file_path = os.path.join(src_dir, "intelpt-multi-core-trace", "trace_missing_threads.json")
144        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, substrs=["intel-pt"])
145        self.expect("thread trace dump instructions 3 -t",
146          substrs=["19531: [20456511.000 ns] (error) expected tracing enabled event",
147                   "m.out`foo() + 65 at multi_thread.cpp:12:21",
148                   "19523: [19691630.216 ns] 0x0000000000400ba7    jg     0x400bb3"])
149        self.expect("thread trace dump instructions 2 -t",
150          substrs=["67919: [19736130.084 ns] 0x0000000000400bd7    addl   $0x1, -0x4(%rbp)",
151                   "m.out`bar() + 26 at multi_thread.cpp:20:6"])
152
153    @testSBAPIAndCommands
154    def testLoadTrace(self):
155        src_dir = self.getSourceDir()
156        trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace.json")
157        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, substrs=["intel-pt"])
158
159        target = self.dbg.GetSelectedTarget()
160        process = target.GetProcess()
161        self.assertEqual(process.GetProcessID(), 1234)
162
163        self.assertEqual(process.GetNumThreads(), 1)
164        self.assertEqual(process.GetThreadAtIndex(0).GetThreadID(), 3842849)
165
166        self.assertEqual(target.GetNumModules(), 1)
167        module = target.GetModuleAtIndex(0)
168        path = module.GetFileSpec()
169        self.assertEqual(path.fullpath, os.path.join(src_dir, "intelpt-trace", "a.out"))
170        self.assertGreater(module.GetNumSections(), 0)
171        self.assertEqual(module.GetSectionAtIndex(0).GetFileAddress(), 0x400000)
172
173        self.assertEqual("6AA9A4E2-6F28-2F33-377D-59FECE874C71-5B41261A", module.GetUUIDString())
174
175        # check that the Process and Thread objects were created correctly
176        self.expect("thread info", substrs=["tid = 3842849"])
177        self.expect("thread list", substrs=["Process 1234 stopped", "tid = 3842849"])
178        self.expect("thread trace dump info", substrs=['''thread #1: tid = 3842849
179
180  Trace technology: intel-pt
181
182  Total number of trace items: 23
183
184  Memory usage:
185    Raw trace size: 4 KiB
186    Total approximate memory usage (excluding raw trace): 0.20 KiB
187    Average memory usage per item (excluding raw trace): 9.00 bytes
188
189  Timing for this thread:
190    Decoding instructions: ''', '''
191
192  Events:
193    Number of individual events: 2
194      software disabled tracing: 2
195
196  Errors:
197    Number of TSC decoding errors: 0'''])
198
199    @testSBAPIAndCommands
200    def testLoadInvalidTraces(self):
201        src_dir = self.getSourceDir()
202
203        # We test first an invalid type
204        trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace_bad.json")
205        expected_substrs = ['''error: expected object at traceBundle.processes[0]
206
207Context:
208{
209  "cpuInfo": { ... },
210  "processes": [
211    /* error: expected object */
212    123
213  ],
214  "type": "intel-pt"
215}
216
217Schema:
218{
219  "type": "intel-pt",
220  "cpuInfo": {
221    // CPU information gotten from, for example, /proc/cpuinfo.
222
223    "vendor": "GenuineIntel" | "unknown",
224    "family": integer,
225    "model": integer,
226    "stepping": integer
227  },''']
228        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
229
230
231        # Now we test a wrong cpu family field in the global bundle description file
232        trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace_bad2.json")
233        expected_substrs = ['error: expected uint64_t at traceBundle.cpuInfo.family', "Context", "Schema"]
234        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
235
236
237        # Now we test a missing field in the intel-pt settings
238        trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace_bad4.json")
239        expected_substrs = ['''error: missing value at traceBundle.cpuInfo.family
240
241Context:
242{
243  "cpuInfo": /* error: missing value */ {
244    "model": 79,
245    "stepping": 1,
246    "vendor": "GenuineIntel"
247  },
248  "processes": [],
249  "type": "intel-pt"
250}''', "Schema"]
251        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
252
253
254        # Now we test an incorrect load address in the intel-pt settings
255        trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace_bad5.json")
256        expected_substrs = ['error: missing value at traceBundle.processes[1].pid', "Schema"]
257        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
258
259
260        # The following wrong schema will have a valid target and an invalid one. In the case of failure,
261        # no targets should be created.
262        self.assertEqual(self.dbg.GetNumTargets(), 0)
263        trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace_bad3.json")
264        expected_substrs = ['error: missing value at traceBundle.processes[1].pid']
265        self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
266        self.assertEqual(self.dbg.GetNumTargets(), 0)
267