326 lines
9.6 KiB
Python
326 lines
9.6 KiB
Python
from intelpt_testcase import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test.decorators import *
|
|
|
|
class TestTraceDumpInfo(TraceIntelPTTestCaseBase):
|
|
def testDumpSimpleFunctionCalls(self):
|
|
self.expect("trace load -v " +
|
|
os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"))
|
|
|
|
self.expect("thread trace dump function-calls 2",
|
|
error=True, substrs=['error: no thread with index: "2"'])
|
|
|
|
self.expect("thread trace dump function-calls 1 -j",
|
|
substrs=['[{"tracedSegments":[{"firstInstructionId":"3","lastInstructionId":"26"}]}]'])
|
|
|
|
self.expect("thread trace dump function-calls 1 -J",
|
|
substrs=['''[
|
|
{
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "3",
|
|
"lastInstructionId": "26"
|
|
}
|
|
]
|
|
}
|
|
]'''])
|
|
|
|
# We test first some code without function call
|
|
self.expect("thread trace dump function-calls 1",
|
|
substrs=['''thread #1: tid = 3842849
|
|
|
|
[call tree #0]
|
|
a.out`main + 4 at main.cpp:2 to 4:0 [3, 26]'''])
|
|
|
|
def testFunctionCallsWithErrors(self):
|
|
self.expect("trace load -v " +
|
|
os.path.join(self.getSourceDir(), "intelpt-multi-core-trace", "trace.json"))
|
|
|
|
# We expect that tracing errors appear as a different tree
|
|
self.expect("thread trace dump function-calls 2",
|
|
substrs=['''thread #2: tid = 3497496
|
|
|
|
[call tree #0]
|
|
m.out`foo() + 65 at multi_thread.cpp:12:21 to 12:21 [4, 19524]
|
|
|
|
[call tree #1]
|
|
<tracing errors> [19526, 19526]'''])
|
|
|
|
self.expect("thread trace dump function-calls 2 -J",
|
|
substrs=['''[
|
|
{
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "4",
|
|
"lastInstructionId": "19524"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "19526",
|
|
"lastInstructionId": "19526"
|
|
}
|
|
]
|
|
}
|
|
]'''])
|
|
|
|
self.expect("thread trace dump function-calls 3",
|
|
substrs=['''thread #3: tid = 3497497
|
|
|
|
[call tree #0]
|
|
m.out`bar() + 30 at multi_thread.cpp:19:3 to 20:6 [5, 61831]
|
|
|
|
[call tree #1]
|
|
<tracing errors> [61833, 61833]'''])
|
|
|
|
self.expect("thread trace dump function-calls 3 -J",
|
|
substrs=['''[
|
|
{
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "5",
|
|
"lastInstructionId": "61831"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "61833",
|
|
"lastInstructionId": "61833"
|
|
}
|
|
]
|
|
}
|
|
]'''])
|
|
|
|
def testInlineFunctionCalls(self):
|
|
self.expect("file " + os.path.join(self.getSourceDir(), "inline-function", "a.out"))
|
|
self.expect("b main") # we'll trace from the beginning of main
|
|
self.expect("b 17")
|
|
self.expect("r")
|
|
self.expect("thread trace start")
|
|
self.expect("c")
|
|
self.expect("thread trace dump function-calls",
|
|
substrs=['''[call tree #0]
|
|
a.out`main + 8 at inline.cpp:15:7 to 16:14 [2, 6]
|
|
a.out`foo(int) at inline.cpp:8:16 to 9:15 [7, 14]
|
|
a.out`foo(int) + 22 [inlined] mult(int, int) at inline.cpp:2:7 to 5:10 [15, 22]
|
|
a.out`foo(int) + 49 at inline.cpp:9:15 to 12:1 [23, 27]
|
|
a.out`main + 25 at inline.cpp:16:14 to 16:14 [28, 28]'''])
|
|
|
|
self.expect("thread trace dump function-calls -J",
|
|
substrs=['''[
|
|
{
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "2",
|
|
"lastInstructionId": "6",
|
|
"nestedCall": {
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "7",
|
|
"lastInstructionId": "14",
|
|
"nestedCall": {
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "15",
|
|
"lastInstructionId": "22"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"firstInstructionId": "23",
|
|
"lastInstructionId": "27"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"firstInstructionId": "28",
|
|
"lastInstructionId": "28"
|
|
}
|
|
]
|
|
}
|
|
]'''])
|
|
|
|
def testIncompleteInlineFunctionCalls(self):
|
|
self.expect("file " + os.path.join(self.getSourceDir(), "inline-function", "a.out"))
|
|
self.expect("b 4") # we'll trace from the middle of the inline method
|
|
self.expect("b 17")
|
|
self.expect("r")
|
|
self.expect("thread trace start")
|
|
self.expect("c")
|
|
self.expect("thread trace dump function-calls",
|
|
substrs=['''[call tree #0]
|
|
a.out`main
|
|
a.out`foo(int)
|
|
a.out`foo(int) + 36 [inlined] mult(int, int) + 14 at inline.cpp:4:5 to 5:10 [2, 6]
|
|
a.out`foo(int) + 49 at inline.cpp:9:15 to 12:1 [7, 11]
|
|
a.out`main + 25 at inline.cpp:16:14 to 16:14 [12, 12]'''])
|
|
|
|
self.expect("thread trace dump function-calls -J",
|
|
substrs=['''[
|
|
{
|
|
"untracedPrefixSegment": {
|
|
"nestedCall": {
|
|
"untracedPrefixSegment": {
|
|
"nestedCall": {
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "2",
|
|
"lastInstructionId": "6"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "7",
|
|
"lastInstructionId": "11"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "12",
|
|
"lastInstructionId": "12"
|
|
}
|
|
]
|
|
}
|
|
]'''])
|
|
|
|
def testMultifileFunctionCalls(self):
|
|
# This test is extremely important because it first calls the method foo() which requires going through the dynamic linking.
|
|
# You'll see the entry "a.out`symbol stub for: foo()" which will invoke the ld linker, which will in turn find the actual foo
|
|
# function and eventually invoke it. However, we don't have the image of the linker in the trace bundle, so we'll see errors
|
|
# because the decoder couldn't find the linker binary! After those failures, the linker will resume right where we return to
|
|
# main after foo() finished.
|
|
# Then, we call foo() again, but because it has already been loaded by the linker, we don't invoke the linker anymore! And
|
|
# we'll see a nice tree without errors in this second invocation. Something interesting happens here. We still have an
|
|
# invocation to the symbol stub for foo(), but it modifies the stack so that when we return from foo() we don't stop again
|
|
# at the symbol stub, but instead we return directly to main. This is an example of returning several levels up in the
|
|
# call stack.
|
|
# Not only that, we also have an inline method in between.
|
|
self.expect("trace load " + os.path.join(self.getSourceDir(), "intelpt-trace-multi-file", "multi-file-no-ld.json"))
|
|
self.expect("thread trace dump function-calls",
|
|
substrs=['''thread #1: tid = 815455
|
|
|
|
[call tree #0]
|
|
a.out`main + 15 at main.cpp:10 to 10:0 [3, 3]
|
|
a.out`symbol stub for: foo() to <+11> [7, 9]
|
|
a.out`a.out[0x0000000000400510] to a.out[0x0000000000400516] [10, 11]
|
|
|
|
[call tree #1]
|
|
<tracing errors> [12, 12]
|
|
|
|
[call tree #2]
|
|
a.out`main + 20 at main.cpp:10 to 12:0 [16, 22]
|
|
a.out`main + 34 [inlined] inline_function() at main.cpp:4 to 6:0 [26, 30]
|
|
a.out`main + 55 at main.cpp:14 to 16:0 [31, 37]
|
|
a.out`symbol stub for: foo() to <+0> [38, 38]
|
|
libfoo.so`foo() at foo.cpp:3 to 4:0 [39, 42]
|
|
libfoo.so`symbol stub for: bar() to <+0> [43, 43]
|
|
libbar.so`bar() at bar.cpp:1 to 4:0 [44, 52]
|
|
libfoo.so`foo() + 13 at foo.cpp:4 to 6:0 [53, 60]
|
|
a.out`main + 68 at main.cpp:16 to 16:0 [61, 63]'''])
|
|
|
|
self.expect("thread trace dump function-calls -J",
|
|
substrs=['''[
|
|
{
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "3",
|
|
"lastInstructionId": "3",
|
|
"nestedCall": {
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "7",
|
|
"lastInstructionId": "9",
|
|
"nestedCall": {
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "10",
|
|
"lastInstructionId": "11"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "12",
|
|
"lastInstructionId": "12"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "16",
|
|
"lastInstructionId": "22",
|
|
"nestedCall": {
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "26",
|
|
"lastInstructionId": "30"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"firstInstructionId": "31",
|
|
"lastInstructionId": "37",
|
|
"nestedCall": {
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "38",
|
|
"lastInstructionId": "38",
|
|
"nestedCall": {
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "39",
|
|
"lastInstructionId": "42",
|
|
"nestedCall": {
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "43",
|
|
"lastInstructionId": "43",
|
|
"nestedCall": {
|
|
"tracedSegments": [
|
|
{
|
|
"firstInstructionId": "44",
|
|
"lastInstructionId": "52"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"firstInstructionId": "53",
|
|
"lastInstructionId": "60"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"firstInstructionId": "61",
|
|
"lastInstructionId": "63"
|
|
}
|
|
]
|
|
}
|
|
]'''])
|