A trace might contain events traced during the target's execution. For example, a thread might be paused for some period of time due to context switches or breakpoints, which actually force a context switch. Not only that, a trace might be paused because the CPU decides to trace only a specific part of the target, like the address filtering provided by intel pt, which will cause pause events. Besides this case, other kinds of events might exist. This patch adds the method `TraceCursor::GetEvents()`` that returns the list of events that happened right before the instruction being pointed at by the cursor. Some refactors were done to make this change simpler. Besides this new API, the instruction dumper now supports the -e flag which shows pause events, like in the following example, where pauses happened due to breakpoints. ``` thread #1: tid = 2717361 a.out`main + 20 at main.cpp:27:20 0: 0x00000000004023d9 leaq -0x1200(%rbp), %rax [paused] 1: 0x00000000004023e0 movq %rax, %rdi [paused] 2: 0x00000000004023e3 callq 0x403a62 ; std::vector<int, std::allocator<int> >::vector at stl_vector.h:391:7 a.out`std::vector<int, std::allocator<int> >::vector() at stl_vector.h:391:7 3: 0x0000000000403a62 pushq %rbp 4: 0x0000000000403a63 movq %rsp, %rbp ``` The `dump info` command has also been updated and now it shows the number of instructions that have associated events. Differential Revision: https://reviews.llvm.org/D123982
116 lines
4.1 KiB
Python
116 lines
4.1 KiB
Python
import lldb
|
|
from intelpt_testcase import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
from lldbsuite.test.decorators import *
|
|
|
|
class TestTraceLoad(TraceIntelPTTestCaseBase):
|
|
|
|
mydir = TestBase.compute_mydir(__file__)
|
|
NO_DEBUG_INFO_TESTCASE = True
|
|
|
|
def testLoadTrace(self):
|
|
src_dir = self.getSourceDir()
|
|
trace_definition_file = os.path.join(src_dir, "intelpt-trace", "trace.json")
|
|
self.expect("trace load -v " + trace_definition_file, substrs=["intel-pt"])
|
|
|
|
target = self.dbg.GetSelectedTarget()
|
|
process = target.GetProcess()
|
|
self.assertEqual(process.GetProcessID(), 1234)
|
|
|
|
self.assertEqual(process.GetNumThreads(), 1)
|
|
self.assertEqual(process.GetThreadAtIndex(0).GetThreadID(), 3842849)
|
|
|
|
self.assertEqual(target.GetNumModules(), 1)
|
|
module = target.GetModuleAtIndex(0)
|
|
path = module.GetFileSpec()
|
|
self.assertEqual(path.fullpath, os.path.join(src_dir, "intelpt-trace", "a.out"))
|
|
self.assertGreater(module.GetNumSections(), 0)
|
|
self.assertEqual(module.GetSectionAtIndex(0).GetFileAddress(), 0x400000)
|
|
|
|
self.assertEqual("6AA9A4E2-6F28-2F33-377D-59FECE874C71-5B41261A", module.GetUUIDString())
|
|
|
|
# check that the Process and Thread objects were created correctly
|
|
self.expect("thread info", substrs=["tid = 3842849"])
|
|
self.expect("thread list", substrs=["Process 1234 stopped", "tid = 3842849"])
|
|
self.expect("thread trace dump info", substrs=['''Trace technology: intel-pt
|
|
|
|
thread #1: tid = 3842849
|
|
Total number of instructions: 21
|
|
|
|
Memory usage:
|
|
Raw trace size: 4 KiB
|
|
Total approximate memory usage (excluding raw trace): 1.27 KiB
|
|
Average memory usage per instruction (excluding raw trace): 61.76 bytes
|
|
|
|
Timing:
|
|
Decoding instructions: ''', '''s
|
|
|
|
Events:
|
|
Number of instructions with events: 1
|
|
Number of individual events: 1
|
|
paused: 1
|
|
|
|
Errors:
|
|
Number of TSC decoding errors: 0'''])
|
|
|
|
def testLoadInvalidTraces(self):
|
|
src_dir = self.getSourceDir()
|
|
# We test first an invalid type
|
|
self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad.json"), error=True,
|
|
substrs=['''error: expected object at traceSession.processes[0]
|
|
|
|
Context:
|
|
{
|
|
"processes": [
|
|
/* error: expected object */
|
|
123
|
|
],
|
|
"trace": { ... }
|
|
}
|
|
|
|
Schema:
|
|
{
|
|
"trace": {
|
|
"type": "intel-pt",
|
|
"cpuInfo": {
|
|
"vendor": "intel" | "unknown",
|
|
"family": integer,
|
|
"model": integer,
|
|
"stepping": integer
|
|
}
|
|
},'''])
|
|
|
|
# Now we test a missing field in the global session file
|
|
self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad2.json"), error=True,
|
|
substrs=['error: missing value at traceSession.processes[1].triple', "Context", "Schema"])
|
|
|
|
# Now we test a missing field in the intel-pt settings
|
|
self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad4.json"), error=True,
|
|
substrs=['''error: missing value at traceSession.trace.cpuInfo.family
|
|
|
|
Context:
|
|
{
|
|
"processes": [],
|
|
"trace": {
|
|
"cpuInfo": /* error: missing value */ {
|
|
"model": 79,
|
|
"stepping": 1,
|
|
"vendor": "intel"
|
|
},
|
|
"type": "intel-pt"
|
|
}
|
|
}''', "Schema"])
|
|
|
|
# Now we test an incorrect load address in the intel-pt settings
|
|
self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad5.json"), error=True,
|
|
substrs=['error: expected numeric string at traceSession.processes[0].modules[0].loadAddress',
|
|
'"loadAddress": /* error: expected numeric string */ 400000,', "Schema"])
|
|
|
|
# The following wrong schema will have a valid target and an invalid one. In the case of failure,
|
|
# no targets should be created.
|
|
self.assertEqual(self.dbg.GetNumTargets(), 0)
|
|
self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad3.json"), error=True,
|
|
substrs=['error: missing value at traceSession.processes[1].pid'])
|
|
self.assertEqual(self.dbg.GetNumTargets(), 0)
|