mirror of
https://github.com/intel/llvm.git
synced 2026-01-23 07:58:23 +08:00
Revert "[lldb] Introduce ScriptedFrameProvider for real threads" (#167662)
The new test fails on x86 and arm64 public macOS bots: ``` 09:27:59 ====================================================================== 09:27:59 FAIL: test_append_frames (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that we can add frames after real stack. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 122, in test_append_frames 09:27:59 self.assertEqual(new_frame_count, original_frame_count + 1) 09:27:59 AssertionError: 5 != 6 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ====================================================================== 09:27:59 FAIL: test_applies_to_thread (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that applies_to_thread filters which threads get the provider. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 218, in test_applies_to_thread 09:27:59 self.assertEqual( 09:27:59 AssertionError: 5 != 1 : Thread with ID 1 should have 1 synthetic frame 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ====================================================================== 09:27:59 FAIL: test_prepend_frames (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that we can add frames before real stack. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 84, in test_prepend_frames 09:27:59 self.assertEqual(new_frame_count, original_frame_count + 2) 09:27:59 AssertionError: 5 != 7 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ====================================================================== 09:27:59 FAIL: test_remove_frame_provider_by_id (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that RemoveScriptedFrameProvider removes a specific provider by ID. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 272, in test_remove_frame_provider_by_id 09:27:59 self.assertEqual(thread.GetNumFrames(), 3, "Should have 3 synthetic frames") 09:27:59 AssertionError: 5 != 3 : Should have 3 synthetic frames 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ====================================================================== 09:27:59 FAIL: test_replace_all_frames (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that we can replace the entire stack. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 41, in test_replace_all_frames 09:27:59 self.assertEqual(thread.GetNumFrames(), 3, "Should have 3 synthetic frames") 09:27:59 AssertionError: 5 != 3 : Should have 3 synthetic frames 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ====================================================================== 09:27:59 FAIL: test_scripted_frame_objects (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that provider can return ScriptedFrame objects. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 159, in test_scripted_frame_objects 09:27:59 self.assertEqual(frame0.GetFunctionName(), "custom_scripted_frame_0") 09:27:59 AssertionError: 'thread_func(int)' != 'custom_scripted_frame_0' 09:27:59 - thread_func(int) 09:27:59 + custom_scripted_frame_0 09:27:59 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ---------------------------------------------------------------------- 09:27:59 Ran 6 tests in 14.242s 09:27:59 09:27:59 FAILED (failures=6) ``` Reverts llvm/llvm-project#161870
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
||||
@@ -1,339 +0,0 @@
|
||||
"""
|
||||
Test scripted frame provider functionality.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.lldbtest import TestBase
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class ScriptedFrameProviderTestCase(TestBase):
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
def setUp(self):
|
||||
TestBase.setUp(self)
|
||||
self.source = "main.cpp"
|
||||
|
||||
def test_replace_all_frames(self):
|
||||
"""Test that we can replace the entire stack."""
|
||||
self.build()
|
||||
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
|
||||
self, "Break here", lldb.SBFileSpec(self.source), only_one_thread=False
|
||||
)
|
||||
|
||||
# Import the test frame provider
|
||||
script_path = os.path.join(self.getSourceDir(), "test_frame_providers.py")
|
||||
self.runCmd("command script import " + script_path)
|
||||
|
||||
# Attach the Replace provider
|
||||
error = lldb.SBError()
|
||||
provider_id = target.RegisterScriptedFrameProvider(
|
||||
"test_frame_providers.ReplaceFrameProvider",
|
||||
lldb.SBStructuredData(),
|
||||
error,
|
||||
)
|
||||
self.assertTrue(error.Success(), f"Failed to register provider: {error}")
|
||||
self.assertNotEqual(provider_id, 0, "Provider ID should be non-zero")
|
||||
|
||||
# Verify we have exactly 3 synthetic frames
|
||||
self.assertEqual(thread.GetNumFrames(), 3, "Should have 3 synthetic frames")
|
||||
|
||||
# Verify frame indices and PCs (dictionary-based frames don't have custom function names)
|
||||
frame0 = thread.GetFrameAtIndex(0)
|
||||
self.assertIsNotNone(frame0)
|
||||
self.assertEqual(frame0.GetPC(), 0x1000)
|
||||
|
||||
frame1 = thread.GetFrameAtIndex(1)
|
||||
self.assertIsNotNone(frame1)
|
||||
self.assertIn("thread_func", frame1.GetFunctionName())
|
||||
|
||||
frame2 = thread.GetFrameAtIndex(2)
|
||||
self.assertIsNotNone(frame2)
|
||||
self.assertEqual(frame2.GetPC(), 0x3000)
|
||||
|
||||
def test_prepend_frames(self):
|
||||
"""Test that we can add frames before real stack."""
|
||||
self.build()
|
||||
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
|
||||
self, "Break here", lldb.SBFileSpec(self.source), only_one_thread=False
|
||||
)
|
||||
|
||||
# Get original frame count and PC
|
||||
original_frame_count = thread.GetNumFrames()
|
||||
self.assertGreaterEqual(
|
||||
original_frame_count, 2, "Should have at least 2 real frames"
|
||||
)
|
||||
|
||||
# Import and attach Prepend provider
|
||||
script_path = os.path.join(self.getSourceDir(), "test_frame_providers.py")
|
||||
self.runCmd("command script import " + script_path)
|
||||
|
||||
error = lldb.SBError()
|
||||
provider_id = target.RegisterScriptedFrameProvider(
|
||||
"test_frame_providers.PrependFrameProvider",
|
||||
lldb.SBStructuredData(),
|
||||
error,
|
||||
)
|
||||
self.assertTrue(error.Success(), f"Failed to register provider: {error}")
|
||||
self.assertNotEqual(provider_id, 0, "Provider ID should be non-zero")
|
||||
|
||||
# Verify we have 2 more frames
|
||||
new_frame_count = thread.GetNumFrames()
|
||||
self.assertEqual(new_frame_count, original_frame_count + 2)
|
||||
|
||||
# Verify first 2 frames are synthetic (check PCs, not function names)
|
||||
frame0 = thread.GetFrameAtIndex(0)
|
||||
self.assertEqual(frame0.GetPC(), 0x9000)
|
||||
|
||||
frame1 = thread.GetFrameAtIndex(1)
|
||||
self.assertEqual(frame1.GetPC(), 0xA000)
|
||||
|
||||
# Verify frame 2 is the original real frame 0
|
||||
frame2 = thread.GetFrameAtIndex(2)
|
||||
self.assertIn("thread_func", frame2.GetFunctionName())
|
||||
|
||||
def test_append_frames(self):
|
||||
"""Test that we can add frames after real stack."""
|
||||
self.build()
|
||||
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
|
||||
self, "Break here", lldb.SBFileSpec(self.source), only_one_thread=False
|
||||
)
|
||||
|
||||
# Get original frame count
|
||||
original_frame_count = thread.GetNumFrames()
|
||||
|
||||
# Import and attach Append provider
|
||||
script_path = os.path.join(self.getSourceDir(), "test_frame_providers.py")
|
||||
self.runCmd("command script import " + script_path)
|
||||
|
||||
error = lldb.SBError()
|
||||
provider_id = target.RegisterScriptedFrameProvider(
|
||||
"test_frame_providers.AppendFrameProvider",
|
||||
lldb.SBStructuredData(),
|
||||
error,
|
||||
)
|
||||
self.assertTrue(error.Success(), f"Failed to register provider: {error}")
|
||||
self.assertNotEqual(provider_id, 0, "Provider ID should be non-zero")
|
||||
|
||||
# Verify we have 1 more frame
|
||||
new_frame_count = thread.GetNumFrames()
|
||||
self.assertEqual(new_frame_count, original_frame_count + 1)
|
||||
|
||||
# Verify first frames are still real
|
||||
frame0 = thread.GetFrameAtIndex(0)
|
||||
self.assertIn("thread_func", frame0.GetFunctionName())
|
||||
|
||||
frame_n_plus_1 = thread.GetFrameAtIndex(new_frame_count - 1)
|
||||
self.assertEqual(frame_n_plus_1.GetPC(), 0x10)
|
||||
|
||||
def test_scripted_frame_objects(self):
|
||||
"""Test that provider can return ScriptedFrame objects."""
|
||||
self.build()
|
||||
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
|
||||
self, "Break here", lldb.SBFileSpec(self.source), only_one_thread=False
|
||||
)
|
||||
|
||||
# Import the provider that returns ScriptedFrame objects
|
||||
script_path = os.path.join(self.getSourceDir(), "test_frame_providers.py")
|
||||
self.runCmd("command script import " + script_path)
|
||||
|
||||
error = lldb.SBError()
|
||||
provider_id = target.RegisterScriptedFrameProvider(
|
||||
"test_frame_providers.ScriptedFrameObjectProvider",
|
||||
lldb.SBStructuredData(),
|
||||
error,
|
||||
)
|
||||
self.assertTrue(error.Success(), f"Failed to register provider: {error}")
|
||||
self.assertNotEqual(provider_id, 0, "Provider ID should be non-zero")
|
||||
|
||||
# Verify we have 5 frames
|
||||
self.assertEqual(
|
||||
thread.GetNumFrames(), 5, "Should have 5 custom scripted frames"
|
||||
)
|
||||
|
||||
# Verify frame properties from CustomScriptedFrame
|
||||
frame0 = thread.GetFrameAtIndex(0)
|
||||
self.assertIsNotNone(frame0)
|
||||
self.assertEqual(frame0.GetFunctionName(), "custom_scripted_frame_0")
|
||||
self.assertEqual(frame0.GetPC(), 0x5000)
|
||||
self.assertTrue(frame0.IsSynthetic(), "Frame should be marked as synthetic")
|
||||
|
||||
frame1 = thread.GetFrameAtIndex(1)
|
||||
self.assertIsNotNone(frame1)
|
||||
self.assertEqual(frame1.GetPC(), 0x6000)
|
||||
|
||||
frame2 = thread.GetFrameAtIndex(2)
|
||||
self.assertIsNotNone(frame2)
|
||||
self.assertEqual(frame2.GetFunctionName(), "custom_scripted_frame_2")
|
||||
self.assertEqual(frame2.GetPC(), 0x7000)
|
||||
self.assertTrue(frame2.IsSynthetic(), "Frame should be marked as synthetic")
|
||||
|
||||
def test_applies_to_thread(self):
|
||||
"""Test that applies_to_thread filters which threads get the provider."""
|
||||
self.build()
|
||||
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
|
||||
self, "Break here", lldb.SBFileSpec(self.source), only_one_thread=False
|
||||
)
|
||||
|
||||
# We should have at least 2 threads (worker threads) at the breakpoint
|
||||
num_threads = process.GetNumThreads()
|
||||
self.assertGreaterEqual(
|
||||
num_threads, 2, "Should have at least 2 threads at breakpoint"
|
||||
)
|
||||
|
||||
# Import the test frame provider
|
||||
script_path = os.path.join(self.getSourceDir(), "test_frame_providers.py")
|
||||
self.runCmd("command script import " + script_path)
|
||||
|
||||
# Collect original thread info before applying provider
|
||||
thread_info = {}
|
||||
for i in range(num_threads):
|
||||
t = process.GetThreadAtIndex(i)
|
||||
thread_info[t.GetIndexID()] = {
|
||||
"frame_count": t.GetNumFrames(),
|
||||
"pc": t.GetFrameAtIndex(0).GetPC(),
|
||||
}
|
||||
|
||||
# Register the ThreadFilterFrameProvider which only applies to thread ID 1
|
||||
error = lldb.SBError()
|
||||
provider_id = target.RegisterScriptedFrameProvider(
|
||||
"test_frame_providers.ThreadFilterFrameProvider",
|
||||
lldb.SBStructuredData(),
|
||||
error,
|
||||
)
|
||||
self.assertTrue(error.Success(), f"Failed to register provider: {error}")
|
||||
self.assertNotEqual(provider_id, 0, "Provider ID should be non-zero")
|
||||
|
||||
# Check each thread
|
||||
thread_id_1_found = False
|
||||
for i in range(num_threads):
|
||||
t = process.GetThreadAtIndex(i)
|
||||
thread_id = t.GetIndexID()
|
||||
|
||||
if thread_id == 1:
|
||||
# Thread with ID 1 should have synthetic frame
|
||||
thread_id_1_found = True
|
||||
self.assertEqual(
|
||||
t.GetNumFrames(),
|
||||
1,
|
||||
f"Thread with ID 1 should have 1 synthetic frame",
|
||||
)
|
||||
self.assertEqual(
|
||||
t.GetFrameAtIndex(0).GetPC(),
|
||||
0xFFFF,
|
||||
f"Thread with ID 1 should have synthetic PC 0xFFFF",
|
||||
)
|
||||
else:
|
||||
# Other threads should keep their original frames
|
||||
self.assertEqual(
|
||||
t.GetNumFrames(),
|
||||
thread_info[thread_id]["frame_count"],
|
||||
f"Thread with ID {thread_id} should not be affected by provider",
|
||||
)
|
||||
self.assertEqual(
|
||||
t.GetFrameAtIndex(0).GetPC(),
|
||||
thread_info[thread_id]["pc"],
|
||||
f"Thread with ID {thread_id} should have its original PC",
|
||||
)
|
||||
|
||||
# We should have found at least one thread with ID 1
|
||||
self.assertTrue(
|
||||
thread_id_1_found,
|
||||
"Should have found a thread with ID 1 to test filtering",
|
||||
)
|
||||
|
||||
def test_remove_frame_provider_by_id(self):
|
||||
"""Test that RemoveScriptedFrameProvider removes a specific provider by ID."""
|
||||
self.build()
|
||||
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
|
||||
self, "Break here", lldb.SBFileSpec(self.source), only_one_thread=False
|
||||
)
|
||||
|
||||
# Import the test frame providers
|
||||
script_path = os.path.join(self.getSourceDir(), "test_frame_providers.py")
|
||||
self.runCmd("command script import " + script_path)
|
||||
|
||||
# Get original frame count
|
||||
original_frame_count = thread.GetNumFrames()
|
||||
original_pc = thread.GetFrameAtIndex(0).GetPC()
|
||||
|
||||
# Register the first provider and get its ID
|
||||
error = lldb.SBError()
|
||||
provider_id_1 = target.RegisterScriptedFrameProvider(
|
||||
"test_frame_providers.ReplaceFrameProvider",
|
||||
lldb.SBStructuredData(),
|
||||
error,
|
||||
)
|
||||
self.assertTrue(error.Success(), f"Failed to register provider 1: {error}")
|
||||
|
||||
# Verify first provider is active (3 synthetic frames)
|
||||
self.assertEqual(thread.GetNumFrames(), 3, "Should have 3 synthetic frames")
|
||||
self.assertEqual(
|
||||
thread.GetFrameAtIndex(0).GetPC(), 0x1000, "Should have first provider's PC"
|
||||
)
|
||||
|
||||
# Register a second provider and get its ID
|
||||
provider_id_2 = target.RegisterScriptedFrameProvider(
|
||||
"test_frame_providers.PrependFrameProvider",
|
||||
lldb.SBStructuredData(),
|
||||
error,
|
||||
)
|
||||
self.assertTrue(error.Success(), f"Failed to register provider 2: {error}")
|
||||
|
||||
# Verify IDs are different
|
||||
self.assertNotEqual(
|
||||
provider_id_1, provider_id_2, "Provider IDs should be unique"
|
||||
)
|
||||
|
||||
# Now remove the first provider by ID
|
||||
result = target.RemoveScriptedFrameProvider(provider_id_1)
|
||||
self.assertSuccess(
|
||||
result, f"Should successfully remove provider with ID {provider_id_1}"
|
||||
)
|
||||
|
||||
# After removing the first provider, the second provider should still be active
|
||||
# The PrependFrameProvider adds 2 frames before the real stack
|
||||
# Since ReplaceFrameProvider had 3 frames, and we removed it, we should now
|
||||
# have the original frames (from real stack) with PrependFrameProvider applied
|
||||
new_frame_count = thread.GetNumFrames()
|
||||
self.assertEqual(
|
||||
new_frame_count,
|
||||
original_frame_count + 2,
|
||||
"Should have original frames + 2 prepended frames",
|
||||
)
|
||||
|
||||
# First two frames should be from PrependFrameProvider
|
||||
self.assertEqual(
|
||||
thread.GetFrameAtIndex(0).GetPC(),
|
||||
0x9000,
|
||||
"First frame should be from PrependFrameProvider",
|
||||
)
|
||||
self.assertEqual(
|
||||
thread.GetFrameAtIndex(1).GetPC(),
|
||||
0xA000,
|
||||
"Second frame should be from PrependFrameProvider",
|
||||
)
|
||||
|
||||
# Remove the second provider
|
||||
result = target.RemoveScriptedFrameProvider(provider_id_2)
|
||||
self.assertSuccess(
|
||||
result, f"Should successfully remove provider with ID {provider_id_2}"
|
||||
)
|
||||
|
||||
# After removing both providers, frames should be back to original
|
||||
self.assertEqual(
|
||||
thread.GetNumFrames(),
|
||||
original_frame_count,
|
||||
"Should restore original frame count",
|
||||
)
|
||||
self.assertEqual(
|
||||
thread.GetFrameAtIndex(0).GetPC(),
|
||||
original_pc,
|
||||
"Should restore original PC",
|
||||
)
|
||||
|
||||
# Try to remove a provider that doesn't exist
|
||||
result = target.RemoveScriptedFrameProvider(999999)
|
||||
self.assertTrue(result.Fail(), "Should fail to remove non-existent provider")
|
||||
@@ -1,55 +0,0 @@
|
||||
// Multi-threaded test program for testing frame providers.
|
||||
|
||||
#include <condition_variable>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
int ready_count = 0;
|
||||
constexpr int NUM_THREADS = 2;
|
||||
|
||||
void thread_func(int thread_num) {
|
||||
std::cout << "Thread " << thread_num << " started\n";
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
ready_count++;
|
||||
if (ready_count == NUM_THREADS + 1) {
|
||||
cv.notify_all();
|
||||
} else {
|
||||
cv.wait(lock, [] { return ready_count == NUM_THREADS + 1; });
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Thread " << thread_num << " at breakpoint\n"; // Break here
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::thread threads[NUM_THREADS];
|
||||
|
||||
for (int i = 0; i < NUM_THREADS; i++) {
|
||||
threads[i] = std::thread(thread_func, i);
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
ready_count++;
|
||||
if (ready_count == NUM_THREADS + 1) {
|
||||
cv.notify_all();
|
||||
} else {
|
||||
cv.wait(lock, [] { return ready_count == NUM_THREADS + 1; });
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Main thread at barrier\n";
|
||||
|
||||
// Join threads
|
||||
for (int i = 0; i < NUM_THREADS; i++) {
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
std::cout << "All threads completed\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
"""
|
||||
Test frame providers for scripted frame provider functionality.
|
||||
|
||||
These providers demonstrate various merge strategies:
|
||||
- Replace: Replace entire stack
|
||||
- Prepend: Add frames before real stack
|
||||
- Append: Add frames after real stack
|
||||
|
||||
It also shows the ability to mix a dictionary, a ScriptedFrame or an SBFrame
|
||||
index to create stackframes
|
||||
"""
|
||||
|
||||
import lldb
|
||||
from lldb.plugins.scripted_process import ScriptedFrame
|
||||
from lldb.plugins.scripted_frame_provider import ScriptedFrameProvider
|
||||
|
||||
|
||||
class ReplaceFrameProvider(ScriptedFrameProvider):
|
||||
"""Replace entire stack with custom frames."""
|
||||
|
||||
def __init__(self, input_frames, args):
|
||||
super().__init__(input_frames, args)
|
||||
self.frames = [
|
||||
{
|
||||
"idx": 0,
|
||||
"pc": 0x1000,
|
||||
},
|
||||
0,
|
||||
{
|
||||
"idx": 2,
|
||||
"pc": 0x3000,
|
||||
},
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def get_description():
|
||||
"""Return a description of this provider."""
|
||||
return "Replace entire stack with 3 custom frames"
|
||||
|
||||
def get_frame_at_index(self, index):
|
||||
if index >= len(self.frames):
|
||||
return None
|
||||
return self.frames[index]
|
||||
|
||||
|
||||
class PrependFrameProvider(ScriptedFrameProvider):
|
||||
"""Prepend synthetic frames before real stack."""
|
||||
|
||||
def __init__(self, input_frames, args):
|
||||
super().__init__(input_frames, args)
|
||||
|
||||
@staticmethod
|
||||
def get_description():
|
||||
"""Return a description of this provider."""
|
||||
return "Prepend 2 synthetic frames before real stack"
|
||||
|
||||
def get_frame_at_index(self, index):
|
||||
if index == 0:
|
||||
return {"pc": 0x9000}
|
||||
elif index == 1:
|
||||
return {"pc": 0xA000}
|
||||
elif index - 2 < len(self.input_frames):
|
||||
return index - 2 # Return real frame index
|
||||
return None
|
||||
|
||||
|
||||
class AppendFrameProvider(ScriptedFrameProvider):
|
||||
"""Append synthetic frames after real stack."""
|
||||
|
||||
def __init__(self, input_frames, args):
|
||||
super().__init__(input_frames, args)
|
||||
|
||||
@staticmethod
|
||||
def get_description():
|
||||
"""Return a description of this provider."""
|
||||
return "Append 1 synthetic frame after real stack"
|
||||
|
||||
def get_frame_at_index(self, index):
|
||||
if index < len(self.input_frames):
|
||||
return index # Return real frame index
|
||||
elif index == len(self.input_frames):
|
||||
return {
|
||||
"idx": 1,
|
||||
"pc": 0x10,
|
||||
}
|
||||
return None
|
||||
|
||||
|
||||
class CustomScriptedFrame(ScriptedFrame):
|
||||
"""Custom scripted frame with full control over frame behavior."""
|
||||
|
||||
def __init__(self, thread, idx, pc, function_name):
|
||||
# Initialize structured data args
|
||||
args = lldb.SBStructuredData()
|
||||
super().__init__(thread, args)
|
||||
|
||||
self.idx = idx
|
||||
self.pc = pc
|
||||
self.function_name = function_name
|
||||
|
||||
def get_id(self):
|
||||
"""Return the frame index."""
|
||||
return self.idx
|
||||
|
||||
def get_pc(self):
|
||||
"""Return the program counter."""
|
||||
return self.pc
|
||||
|
||||
def get_function_name(self):
|
||||
"""Return the function name."""
|
||||
return self.function_name
|
||||
|
||||
def is_artificial(self):
|
||||
"""Mark as artificial frame."""
|
||||
return False
|
||||
|
||||
def is_hidden(self):
|
||||
"""Not hidden."""
|
||||
return False
|
||||
|
||||
def get_register_context(self):
|
||||
"""No register context for this test."""
|
||||
return None
|
||||
|
||||
|
||||
class ScriptedFrameObjectProvider(ScriptedFrameProvider):
|
||||
"""Provider that returns ScriptedFrame objects instead of dictionaries."""
|
||||
|
||||
def __init__(self, input_frames, args):
|
||||
super().__init__(input_frames, args)
|
||||
|
||||
@staticmethod
|
||||
def get_description():
|
||||
"""Return a description of this provider."""
|
||||
return "Provider returning custom ScriptedFrame objects"
|
||||
|
||||
def get_frame_at_index(self, index):
|
||||
"""Return ScriptedFrame objects or dictionaries based on index."""
|
||||
if index == 0:
|
||||
return CustomScriptedFrame(
|
||||
self.thread, 0, 0x5000, "custom_scripted_frame_0"
|
||||
)
|
||||
elif index == 1:
|
||||
return {"pc": 0x6000}
|
||||
elif index == 2:
|
||||
return CustomScriptedFrame(
|
||||
self.thread, 2, 0x7000, "custom_scripted_frame_2"
|
||||
)
|
||||
elif index == 3:
|
||||
return len(self.input_frames) - 2 # Real frame index
|
||||
elif index == 4:
|
||||
return len(self.input_frames) - 1 # Real frame index
|
||||
return None
|
||||
|
||||
|
||||
class ThreadFilterFrameProvider(ScriptedFrameProvider):
|
||||
"""Provider that only applies to thread with ID 1."""
|
||||
|
||||
@staticmethod
|
||||
def applies_to_thread(thread):
|
||||
"""Only apply to thread with index ID 1."""
|
||||
return thread.GetIndexID() == 1
|
||||
|
||||
def __init__(self, input_frames, args):
|
||||
super().__init__(input_frames, args)
|
||||
|
||||
@staticmethod
|
||||
def get_description():
|
||||
"""Return a description of this provider."""
|
||||
return "Provider that only applies to thread ID 1"
|
||||
|
||||
def get_frame_at_index(self, index):
|
||||
"""Return a single synthetic frame."""
|
||||
if index == 0:
|
||||
return {"pc": 0xFFFF}
|
||||
return None
|
||||
Reference in New Issue
Block a user