CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
346 lines
11 KiB
Python
346 lines
11 KiB
Python
import lldb
|
|
from intelpt_testcase import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
from lldbsuite.test.decorators import *
|
|
|
|
|
|
@skipIfNoIntelPT
|
|
class TestTraceStartStop(TraceIntelPTTestCaseBase):
|
|
SHARED_BUILD_TESTCASE = False
|
|
|
|
def expectGenericHelpMessageForStartCommand(self):
|
|
self.expect(
|
|
"help thread trace start",
|
|
substrs=["Syntax: thread trace start [<trace-options>]"],
|
|
)
|
|
|
|
@testSBAPIAndCommands
|
|
def testStartStopSessionFileThreads(self):
|
|
# it should fail for processes from json session files
|
|
self.expect(
|
|
"trace load -v "
|
|
+ os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json")
|
|
)
|
|
|
|
# the help command should be the generic one, as it's not a live process
|
|
self.expectGenericHelpMessageForStartCommand()
|
|
|
|
self.traceStartThread(error=True)
|
|
|
|
self.traceStopThread(error=True)
|
|
|
|
@testSBAPIAndCommands
|
|
def testStartWithNoProcess(self):
|
|
self.traceStartThread(error=True)
|
|
|
|
@testSBAPIAndCommands
|
|
def testStartSessionWithWrongSize(self):
|
|
self.expect(
|
|
"file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")
|
|
)
|
|
self.expect("b main")
|
|
self.expect("r")
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize=2000,
|
|
substrs=["The intel pt trace size must be a power of 2", "It was 2000"],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize=5000,
|
|
substrs=["The intel pt trace size must be a power of 2", "It was 5000"],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize=0,
|
|
substrs=["The intel pt trace size must be a power of 2", "It was 0"],
|
|
)
|
|
|
|
self.traceStartThread(iptTraceSize=1048576)
|
|
|
|
@testSBAPIAndCommands
|
|
def testStartSessionWithSizeDeclarationInUnits(self):
|
|
self.expect(
|
|
"file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")
|
|
)
|
|
self.expect("b main")
|
|
self.expect("r")
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize="abc",
|
|
substrs=["invalid bytes expression for 'abc'"],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize="123.12",
|
|
substrs=["invalid bytes expression for '123.12'"],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True, iptTraceSize='""', substrs=["invalid bytes expression for ''"]
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize="2000B",
|
|
substrs=[
|
|
"The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 2000"
|
|
],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize="3MB",
|
|
substrs=[
|
|
"The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3145728"
|
|
],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize="3MiB",
|
|
substrs=[
|
|
"The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3145728"
|
|
],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize="3mib",
|
|
substrs=[
|
|
"The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3145728"
|
|
],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize="3M",
|
|
substrs=[
|
|
"The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3145728"
|
|
],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize="3KB",
|
|
substrs=[
|
|
"The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3072"
|
|
],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize="3KiB",
|
|
substrs=[
|
|
"The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3072"
|
|
],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize="3K",
|
|
substrs=[
|
|
"The intel pt trace size must be a power of 2 greater than or equal to 4096 (2^12) bytes. It was 3072"
|
|
],
|
|
)
|
|
|
|
self.traceStartThread(
|
|
error=True,
|
|
iptTraceSize="3MS",
|
|
substrs=["invalid bytes expression for '3MS'"],
|
|
)
|
|
|
|
self.traceStartThread(iptTraceSize="1048576")
|
|
|
|
@skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))
|
|
def testSBAPIHelp(self):
|
|
self.expect(
|
|
"file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")
|
|
)
|
|
self.expect("b main")
|
|
self.expect("r")
|
|
|
|
help = self.getTraceOrCreate().GetStartConfigurationHelp()
|
|
self.assertIn("iptTraceSize", help)
|
|
self.assertIn("processBufferSizeLimit", help)
|
|
|
|
@skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))
|
|
def testStoppingAThread(self):
|
|
self.expect(
|
|
"file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")
|
|
)
|
|
self.expect("b main")
|
|
self.expect("r")
|
|
self.expect("thread trace start")
|
|
self.expect("n")
|
|
self.expect(
|
|
"thread trace dump instructions",
|
|
substrs=[
|
|
"""0x0000000000400511 movl $0x0, -0x4(%rbp)
|
|
no more data"""
|
|
],
|
|
)
|
|
# process stopping should stop the thread
|
|
self.expect("process trace stop")
|
|
self.expect("n")
|
|
self.expect(
|
|
"thread trace dump instructions", substrs=["not traced"], error=True
|
|
)
|
|
|
|
@skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))
|
|
def testStartStopLiveThreads(self):
|
|
# The help command should be the generic one if there's no process running
|
|
self.expectGenericHelpMessageForStartCommand()
|
|
|
|
self.expect(
|
|
"thread trace start", error=True, substrs=["error: Process not available"]
|
|
)
|
|
|
|
self.expect(
|
|
"file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")
|
|
)
|
|
self.expect("b main")
|
|
|
|
self.expect(
|
|
"thread trace start", error=True, substrs=["error: Process not available"]
|
|
)
|
|
|
|
# The help command should be the generic one if there's still no process running
|
|
self.expectGenericHelpMessageForStartCommand()
|
|
|
|
self.expect("r")
|
|
|
|
# This fails because "trace start" hasn't been called yet
|
|
self.expect(
|
|
"thread trace stop",
|
|
error=True,
|
|
substrs=["error: Process is not being traced"],
|
|
)
|
|
|
|
# the help command should be the intel-pt one now
|
|
self.expect(
|
|
"help thread trace start",
|
|
substrs=[
|
|
"Start tracing one or more threads with intel-pt.",
|
|
"Syntax: thread trace start [<thread-index> <thread-index> ...] [<intel-pt-options>]",
|
|
],
|
|
)
|
|
|
|
# We start tracing with a small buffer size
|
|
self.expect("thread trace start 1 --size 4096")
|
|
|
|
# We fail if we try to trace again
|
|
self.expect(
|
|
"thread trace start",
|
|
error=True,
|
|
substrs=["error: Thread ", "already traced"],
|
|
)
|
|
|
|
# We can reconstruct the single instruction executed in the first line
|
|
self.expect("n")
|
|
self.expect(
|
|
"thread trace dump instructions -f",
|
|
patterns=[
|
|
rf"""thread #1: tid = .*
|
|
a.out`main \+ 4 at main.cpp:2
|
|
2: {ADDRESS_REGEX} movl"""
|
|
],
|
|
)
|
|
|
|
# We can reconstruct the instructions up to the second line
|
|
self.expect("n")
|
|
self.expect(
|
|
"thread trace dump instructions -f",
|
|
patterns=[
|
|
rf"""thread #1: tid = .*
|
|
a.out`main \+ 4 at main.cpp:2
|
|
2: {ADDRESS_REGEX} movl .*
|
|
a.out`main \+ 11 at main.cpp:4
|
|
4: {ADDRESS_REGEX} movl .*
|
|
6: {ADDRESS_REGEX} jmp .* ; <\+28> at main.cpp:4
|
|
8: {ADDRESS_REGEX} cmpl .*
|
|
10: {ADDRESS_REGEX} jle .* ; <\+20> at main.cpp:5"""
|
|
],
|
|
)
|
|
|
|
self.expect(
|
|
"thread trace dump instructions",
|
|
patterns=[
|
|
rf"""thread #1: tid = .*
|
|
a.out`main \+ 32 at main.cpp:4
|
|
10: {ADDRESS_REGEX} jle .* ; <\+20> at main.cpp:5
|
|
8: {ADDRESS_REGEX} cmpl .*
|
|
6: {ADDRESS_REGEX} jmp .* ; <\+28> at main.cpp:4
|
|
4: {ADDRESS_REGEX} movl .*
|
|
a.out`main \+ 4 at main.cpp:2
|
|
2: {ADDRESS_REGEX} movl .* """
|
|
],
|
|
)
|
|
|
|
# We stop tracing
|
|
self.expect("thread trace stop")
|
|
|
|
# We can't stop twice
|
|
self.expect(
|
|
"thread trace stop",
|
|
error=True,
|
|
substrs=["error: Thread ", "not currently traced"],
|
|
)
|
|
|
|
# We trace again from scratch, this time letting LLDB to pick the current
|
|
# thread
|
|
self.expect("thread trace start")
|
|
self.expect("n")
|
|
self.expect(
|
|
"thread trace dump instructions -f",
|
|
patterns=[
|
|
rf"""thread #1: tid = .*
|
|
a.out`main \+ 20 at main.cpp:5
|
|
2: {ADDRESS_REGEX} xorl"""
|
|
],
|
|
)
|
|
|
|
self.expect(
|
|
"thread trace dump instructions",
|
|
patterns=[
|
|
rf"""thread #1: tid = .*
|
|
a.out`main \+ 20 at main.cpp:5
|
|
2: {ADDRESS_REGEX} xorl"""
|
|
],
|
|
)
|
|
|
|
self.expect("c")
|
|
# Now the process has finished, so the commands should fail
|
|
self.expect(
|
|
"thread trace start",
|
|
error=True,
|
|
substrs=["error: Process must be launched"],
|
|
)
|
|
|
|
self.expect(
|
|
"thread trace stop", error=True, substrs=["error: Process must be launched"]
|
|
)
|
|
|
|
# We should be able to trace the program if we relaunch it
|
|
# For this, we'll trace starting at a different point in the new
|
|
# process.
|
|
self.expect("breakpoint disable")
|
|
self.expect("b main.cpp:4")
|
|
self.expect("r")
|
|
self.expect("thread trace start")
|
|
# We can reconstruct the single instruction executed in the first line
|
|
self.expect("si")
|
|
self.expect(
|
|
"thread trace dump instructions -c 1",
|
|
patterns=[
|
|
rf"""thread #1: tid = .*
|
|
a.out`main \+ 11 at main.cpp:4"""
|
|
],
|
|
)
|