535 lines
20 KiB
Python
535 lines
20 KiB
Python
"""
|
|
Test SBFrameExtensions API.
|
|
"""
|
|
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
|
|
|
|
class TestSBFrameExtensions(TestBase):
|
|
NO_DEBUG_INFO_TESTCASE = True
|
|
|
|
def setUp(self):
|
|
TestBase.setUp(self)
|
|
self.source = "main.c"
|
|
|
|
def _get_frame(self):
|
|
"""Helper method to get a valid frame for testing."""
|
|
self.build()
|
|
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
|
|
self, "Set breakpoint here", lldb.SBFileSpec(self.source)
|
|
)
|
|
frame = thread.GetFrameAtIndex(0)
|
|
self.assertTrue(frame.IsValid(), "Frame should be valid")
|
|
return frame, thread
|
|
|
|
def test_property_pc(self):
|
|
"""Test SBFrame extension property: pc"""
|
|
frame, _ = self._get_frame()
|
|
|
|
pc = frame.pc
|
|
self.assertIsInstance(pc, int, "pc should be an integer")
|
|
self.assertGreater(pc, 0, "pc should be greater than 0")
|
|
self.assertEqual(pc, frame.GetPC(), "pc property should match GetPC()")
|
|
|
|
def test_property_addr(self):
|
|
"""Test SBFrame extension property: addr"""
|
|
frame, _ = self._get_frame()
|
|
|
|
addr = frame.addr
|
|
self.assertTrue(addr.IsValid(), "addr should be valid")
|
|
self.assertEqual(addr, frame.GetPCAddress(), "addr should match GetPCAddress()")
|
|
|
|
def test_property_fp(self):
|
|
"""Test SBFrame extension property: fp"""
|
|
frame, _ = self._get_frame()
|
|
|
|
fp = frame.fp
|
|
self.assertIsInstance(fp, int, "fp should be an integer")
|
|
self.assertEqual(fp, frame.GetFP(), "fp property should match GetFP()")
|
|
|
|
def test_property_sp(self):
|
|
"""Test SBFrame extension property: sp"""
|
|
frame, _ = self._get_frame()
|
|
|
|
sp = frame.sp
|
|
self.assertIsInstance(sp, int, "sp should be an integer")
|
|
self.assertEqual(sp, frame.GetSP(), "sp property should match GetSP()")
|
|
|
|
def test_property_module(self):
|
|
"""Test SBFrame extension property: module"""
|
|
frame, _ = self._get_frame()
|
|
|
|
module = frame.module
|
|
self.assertTrue(module.IsValid(), "module should be valid")
|
|
self.assertEqual(module, frame.GetModule(), "module should match GetModule()")
|
|
|
|
def test_property_compile_unit(self):
|
|
"""Test SBFrame extension property: compile_unit"""
|
|
frame, _ = self._get_frame()
|
|
|
|
compile_unit = frame.compile_unit
|
|
self.assertTrue(compile_unit.IsValid(), "compile_unit should be valid")
|
|
self.assertEqual(
|
|
compile_unit,
|
|
frame.GetCompileUnit(),
|
|
"compile_unit should match GetCompileUnit()",
|
|
)
|
|
|
|
def test_property_function(self):
|
|
"""Test SBFrame extension property: function"""
|
|
frame, _ = self._get_frame()
|
|
|
|
function = frame.function
|
|
self.assertTrue(function.IsValid(), "function should be valid")
|
|
self.assertEqual(
|
|
function, frame.GetFunction(), "function should match GetFunction()"
|
|
)
|
|
|
|
def test_property_symbol(self):
|
|
"""Test SBFrame extension property: symbol"""
|
|
frame, _ = self._get_frame()
|
|
|
|
symbol = frame.symbol
|
|
self.assertTrue(symbol.IsValid(), "symbol should be valid")
|
|
self.assertEqual(symbol, frame.GetSymbol(), "symbol should match GetSymbol()")
|
|
|
|
def test_property_block(self):
|
|
"""Test SBFrame extension property: block"""
|
|
frame, _ = self._get_frame()
|
|
|
|
block = frame.block
|
|
self.assertTrue(block.IsValid(), "block should be valid")
|
|
block_direct = frame.GetBlock()
|
|
self.assertTrue(block_direct.IsValid(), "GetBlock() should return valid block")
|
|
# Verify both blocks are valid and have the same ranges
|
|
# by comparing their first range start address.
|
|
block_ranges = block.GetRanges()
|
|
block_direct_ranges = block_direct.GetRanges()
|
|
if block_ranges.GetSize() > 0 and block_direct_ranges.GetSize() > 0:
|
|
self.assertEqual(
|
|
block.GetRangeStartAddress(0),
|
|
block_direct.GetRangeStartAddress(0),
|
|
"block should match GetBlock() start address",
|
|
)
|
|
|
|
def test_property_is_inlined(self):
|
|
"""Test SBFrame extension property: is_inlined"""
|
|
frame, _ = self._get_frame()
|
|
|
|
is_inlined = frame.is_inlined
|
|
self.assertIsInstance(is_inlined, bool, "is_inlined should be a boolean")
|
|
self.assertEqual(
|
|
is_inlined, frame.IsInlined(), "is_inlined should match IsInlined()"
|
|
)
|
|
|
|
def test_property_name(self):
|
|
"""Test SBFrame extension property: name"""
|
|
frame, _ = self._get_frame()
|
|
|
|
name = frame.name
|
|
self.assertIsInstance(name, str, "name should be a string")
|
|
self.assertEqual(
|
|
name, frame.GetFunctionName(), "name should match GetFunctionName()"
|
|
)
|
|
# Should be one of our functions.
|
|
self.assertIn(
|
|
name, ["func1", "func2", "main"], "name should be a known function"
|
|
)
|
|
|
|
def test_property_line_entry(self):
|
|
"""Test SBFrame extension property: line_entry"""
|
|
frame, _ = self._get_frame()
|
|
|
|
line_entry = frame.line_entry
|
|
self.assertTrue(line_entry.IsValid(), "line_entry should be valid")
|
|
self.assertEqual(
|
|
line_entry, frame.GetLineEntry(), "line_entry should match GetLineEntry()"
|
|
)
|
|
|
|
def test_property_thread(self):
|
|
"""Test SBFrame extension property: thread"""
|
|
frame, thread = self._get_frame()
|
|
|
|
thread_prop = frame.thread
|
|
self.assertTrue(thread_prop.IsValid(), "thread should be valid")
|
|
self.assertEqual(
|
|
thread_prop, frame.GetThread(), "thread should match GetThread()"
|
|
)
|
|
self.assertEqual(
|
|
thread_prop.GetThreadID(),
|
|
thread.GetThreadID(),
|
|
"thread should be the same thread",
|
|
)
|
|
|
|
def test_property_disassembly(self):
|
|
"""Test SBFrame extension property: disassembly"""
|
|
frame, _ = self._get_frame()
|
|
|
|
disassembly = frame.disassembly
|
|
self.assertIsInstance(disassembly, str, "disassembly should be a string")
|
|
self.assertGreater(len(disassembly), 0, "disassembly should not be empty")
|
|
self.assertEqual(
|
|
disassembly, frame.Disassemble(), "disassembly should match Disassemble()"
|
|
)
|
|
|
|
def test_property_idx(self):
|
|
"""Test SBFrame extension property: idx"""
|
|
frame, _ = self._get_frame()
|
|
|
|
idx = frame.idx
|
|
self.assertIsInstance(idx, int, "idx should be an integer")
|
|
self.assertEqual(idx, frame.GetFrameID(), "idx should match GetFrameID()")
|
|
self.assertEqual(idx, 0, "First frame should have idx 0")
|
|
|
|
def test_property_variables(self):
|
|
"""Test SBFrame extension property: variables"""
|
|
frame, _ = self._get_frame()
|
|
|
|
variables = frame.variables
|
|
self.assertIsInstance(
|
|
variables, lldb.SBValueList, "variables should be SBValueList"
|
|
)
|
|
all_vars = frame.GetVariables(True, True, True, True)
|
|
self.assertEqual(
|
|
variables.GetSize(),
|
|
all_vars.GetSize(),
|
|
"variables should match GetVariables(True, True, True, True)",
|
|
)
|
|
|
|
def test_property_vars(self):
|
|
"""Test SBFrame extension property: vars (alias for variables)"""
|
|
frame, _ = self._get_frame()
|
|
|
|
vars_prop = frame.vars
|
|
self.assertIsInstance(vars_prop, lldb.SBValueList, "vars should be SBValueList")
|
|
variables = frame.variables
|
|
self.assertEqual(
|
|
vars_prop.GetSize(),
|
|
variables.GetSize(),
|
|
"vars should match variables",
|
|
)
|
|
|
|
def test_property_locals(self):
|
|
"""Test SBFrame extension property: locals"""
|
|
frame, _ = self._get_frame()
|
|
|
|
locals_prop = frame.locals
|
|
self.assertIsInstance(
|
|
locals_prop, lldb.SBValueList, "locals should be SBValueList"
|
|
)
|
|
locals_direct = frame.GetVariables(False, True, False, False)
|
|
self.assertEqual(
|
|
locals_prop.GetSize(),
|
|
locals_direct.GetSize(),
|
|
"locals should match GetVariables(False, True, False, False)",
|
|
)
|
|
|
|
def test_property_args(self):
|
|
"""Test SBFrame extension property: args"""
|
|
frame, _ = self._get_frame()
|
|
|
|
args_prop = frame.args
|
|
self.assertIsInstance(args_prop, lldb.SBValueList, "args should be SBValueList")
|
|
args_direct = frame.GetVariables(True, False, False, False)
|
|
self.assertEqual(
|
|
args_prop.GetSize(),
|
|
args_direct.GetSize(),
|
|
"args should match GetVariables(True, False, False, False)",
|
|
)
|
|
|
|
def test_property_arguments(self):
|
|
"""Test SBFrame extension property: arguments (alias for args)"""
|
|
frame, _ = self._get_frame()
|
|
|
|
arguments_prop = frame.arguments
|
|
self.assertIsInstance(
|
|
arguments_prop, lldb.SBValueList, "arguments should be SBValueList"
|
|
)
|
|
args_prop = frame.args
|
|
self.assertEqual(
|
|
arguments_prop.GetSize(),
|
|
args_prop.GetSize(),
|
|
"arguments should match args",
|
|
)
|
|
|
|
def test_property_statics(self):
|
|
"""Test SBFrame extension property: statics"""
|
|
frame, _ = self._get_frame()
|
|
|
|
statics_prop = frame.statics
|
|
self.assertIsInstance(
|
|
statics_prop, lldb.SBValueList, "statics should be SBValueList"
|
|
)
|
|
statics_direct = frame.GetVariables(False, False, True, False)
|
|
self.assertEqual(
|
|
statics_prop.GetSize(),
|
|
statics_direct.GetSize(),
|
|
"statics should match GetVariables(False, False, True, False)",
|
|
)
|
|
|
|
def test_property_registers(self):
|
|
"""Test SBFrame extension property: registers"""
|
|
frame, _ = self._get_frame()
|
|
|
|
registers = frame.registers
|
|
# registers returns an SBValueList that can be iterated.
|
|
self.assertTrue(hasattr(registers, "__iter__"), "registers should be iterable")
|
|
registers_direct = frame.GetRegisters()
|
|
# Compare by iterating and counting.
|
|
registers_count = sum(1 for _ in registers)
|
|
registers_direct_count = sum(1 for _ in registers_direct)
|
|
self.assertEqual(
|
|
registers_count,
|
|
registers_direct_count,
|
|
"registers should match GetRegisters()",
|
|
)
|
|
|
|
def test_property_regs(self):
|
|
"""Test SBFrame extension property: regs (alias for registers)"""
|
|
frame, _ = self._get_frame()
|
|
|
|
regs = frame.regs
|
|
self.assertTrue(hasattr(regs, "__iter__"), "regs should be iterable")
|
|
registers = frame.registers
|
|
regs_count = sum(1 for _ in regs)
|
|
registers_count = sum(1 for _ in registers)
|
|
self.assertEqual(regs_count, registers_count, "regs should match registers")
|
|
|
|
def test_property_register(self):
|
|
"""Test SBFrame extension property: register (flattened view)"""
|
|
frame, _ = self._get_frame()
|
|
|
|
register = frame.register
|
|
self.assertIsNotNone(register, "register should not be None")
|
|
# register is a helper object with __iter__ and __getitem__.
|
|
reg_names = set()
|
|
for reg in register:
|
|
self.assertTrue(reg.IsValid(), "Register should be valid")
|
|
reg_names.add(reg.name)
|
|
|
|
# Test register indexing by name.
|
|
if len(reg_names) > 0:
|
|
first_reg_name = list(reg_names)[0]
|
|
reg_by_name = register[first_reg_name]
|
|
self.assertTrue(reg_by_name.IsValid(), "Register by name should be valid")
|
|
self.assertEqual(
|
|
reg_by_name.name, first_reg_name, "Register name should match"
|
|
)
|
|
|
|
def test_property_reg(self):
|
|
"""Test SBFrame extension property: reg (alias for register)"""
|
|
frame, _ = self._get_frame()
|
|
|
|
reg = frame.reg
|
|
self.assertIsNotNone(reg, "reg should not be None")
|
|
register = frame.register
|
|
reg_names = set()
|
|
for r in reg:
|
|
reg_names.add(r.name)
|
|
reg_names2 = set()
|
|
for r in register:
|
|
reg_names2.add(r.name)
|
|
self.assertEqual(reg_names, reg_names2, "reg should match register")
|
|
|
|
def test_property_parent(self):
|
|
"""Test SBFrame extension property: parent"""
|
|
frame0, thread = self._get_frame()
|
|
|
|
# If there's a parent frame (frame 1), test parent property.
|
|
if thread.GetNumFrames() > 1:
|
|
frame1 = thread.GetFrameAtIndex(1)
|
|
parent = frame0.parent
|
|
self.assertTrue(parent.IsValid(), "parent should be valid")
|
|
self.assertEqual(
|
|
parent.GetFrameID(),
|
|
frame1.GetFrameID(),
|
|
"parent should be the next frame",
|
|
)
|
|
self.assertEqual(
|
|
parent.pc, frame1.GetPC(), "parent PC should match frame 1"
|
|
)
|
|
|
|
def test_property_child(self):
|
|
"""Test SBFrame extension property: child"""
|
|
frame0, thread = self._get_frame()
|
|
|
|
# Test child property (should be frame -1, which doesn't exist, so should return invalid).
|
|
child = frame0.child
|
|
# Child of frame 0 would be frame -1, which doesn't exist.
|
|
# So it should return an invalid frame.
|
|
if thread.GetNumFrames() == 1:
|
|
self.assertFalse(child.IsValid(), "child of only frame should be invalid")
|
|
|
|
def test_method_get_all_variables(self):
|
|
"""Test SBFrame extension method: get_all_variables()"""
|
|
frame, _ = self._get_frame()
|
|
|
|
all_vars = frame.get_all_variables()
|
|
self.assertIsInstance(
|
|
all_vars, lldb.SBValueList, "get_all_variables should return SBValueList"
|
|
)
|
|
all_vars_direct = frame.GetVariables(True, True, True, True)
|
|
self.assertEqual(
|
|
all_vars.GetSize(),
|
|
all_vars_direct.GetSize(),
|
|
"get_all_variables should match GetVariables(True, True, True, True)",
|
|
)
|
|
|
|
def test_method_get_arguments(self):
|
|
"""Test SBFrame extension method: get_arguments()"""
|
|
frame, _ = self._get_frame()
|
|
|
|
args = frame.get_arguments()
|
|
self.assertIsInstance(
|
|
args, lldb.SBValueList, "get_arguments should return SBValueList"
|
|
)
|
|
args_direct = frame.GetVariables(True, False, False, False)
|
|
self.assertEqual(
|
|
args.GetSize(),
|
|
args_direct.GetSize(),
|
|
"get_arguments should match GetVariables(True, False, False, False)",
|
|
)
|
|
|
|
def test_method_get_locals(self):
|
|
"""Test SBFrame extension method: get_locals()"""
|
|
frame, _ = self._get_frame()
|
|
|
|
locals = frame.get_locals()
|
|
self.assertIsInstance(
|
|
locals, lldb.SBValueList, "get_locals should return SBValueList"
|
|
)
|
|
locals_direct = frame.GetVariables(False, True, False, False)
|
|
self.assertEqual(
|
|
locals.GetSize(),
|
|
locals_direct.GetSize(),
|
|
"get_locals should match GetVariables(False, True, False, False)",
|
|
)
|
|
|
|
def test_method_get_statics(self):
|
|
"""Test SBFrame extension method: get_statics()"""
|
|
frame, _ = self._get_frame()
|
|
|
|
statics = frame.get_statics()
|
|
self.assertIsInstance(
|
|
statics, lldb.SBValueList, "get_statics should return SBValueList"
|
|
)
|
|
statics_direct = frame.GetVariables(False, False, True, False)
|
|
self.assertEqual(
|
|
statics.GetSize(),
|
|
statics_direct.GetSize(),
|
|
"get_statics should match GetVariables(False, False, True, False)",
|
|
)
|
|
|
|
def test_method_var(self):
|
|
"""Test SBFrame extension method: var()"""
|
|
frame, _ = self._get_frame()
|
|
|
|
# Test var() method with a variable that should exist.
|
|
# First, let's see what variables are available.
|
|
all_vars = frame.GetVariables(True, True, True, True)
|
|
if all_vars.GetSize() > 0:
|
|
var_name = all_vars.GetValueAtIndex(0).GetName()
|
|
var_value = frame.var(var_name)
|
|
self.assertTrue(var_value.IsValid(), f"var('{var_name}') should be valid")
|
|
self.assertEqual(
|
|
var_value.GetName(),
|
|
var_name,
|
|
f"var('{var_name}') should return the correct variable",
|
|
)
|
|
# Compare with GetValueForVariablePath.
|
|
var_direct = frame.GetValueForVariablePath(var_name)
|
|
self.assertEqual(
|
|
var_value.GetName(),
|
|
var_direct.GetName(),
|
|
"var() should match GetValueForVariablePath()",
|
|
)
|
|
|
|
# Test var() with non-existent variable.
|
|
invalid_var = frame.var("NonExistentVariable12345")
|
|
self.assertFalse(
|
|
invalid_var.IsValid(), "var() with non-existent variable should be invalid"
|
|
)
|
|
|
|
def test_method_get_parent_frame(self):
|
|
"""Test SBFrame extension method: get_parent_frame()"""
|
|
frame0, thread = self._get_frame()
|
|
|
|
# Test get_parent_frame.
|
|
if thread.GetNumFrames() > 1:
|
|
parent = frame0.get_parent_frame()
|
|
self.assertTrue(
|
|
parent.IsValid(), "get_parent_frame should return valid frame"
|
|
)
|
|
frame1 = thread.GetFrameAtIndex(1)
|
|
self.assertEqual(
|
|
parent.GetFrameID(),
|
|
frame1.GetFrameID(),
|
|
"get_parent_frame should return frame 1",
|
|
)
|
|
else:
|
|
# If there's only one frame, parent should be invalid.
|
|
parent = frame0.get_parent_frame()
|
|
# Note: get_parent_frame might return an invalid frame if idx+1 is out of bounds.
|
|
|
|
def test_method_get_child_frame(self):
|
|
"""Test SBFrame extension method: get_child_frame()"""
|
|
frame0, thread = self._get_frame()
|
|
|
|
# Test get_child_frame (frame -1 doesn't exist, so should be invalid).
|
|
child = frame0.get_child_frame()
|
|
if thread.GetNumFrames() == 1:
|
|
self.assertFalse(
|
|
child.IsValid(), "get_child_frame of only frame should be invalid"
|
|
)
|
|
|
|
def test_special_method_int(self):
|
|
"""Test SBFrame extension special method: __int__"""
|
|
frame0, _ = self._get_frame()
|
|
|
|
# Test __int__ (converts frame to its frame ID).
|
|
frame_id = int(frame0)
|
|
self.assertIsInstance(frame_id, int, "__int__ should return an integer")
|
|
self.assertEqual(
|
|
frame_id, frame0.GetFrameID(), "__int__ should return frame ID"
|
|
)
|
|
|
|
def test_special_method_hex(self):
|
|
"""Test SBFrame extension special method: __hex__"""
|
|
frame0, _ = self._get_frame()
|
|
|
|
# Test __hex__ (converts frame to its PC).
|
|
# Note: __hex__ returns the PC as an integer, not a hex string.
|
|
# In Python 3, hex() builtin calls __index__ if __hex__ doesn't exist,
|
|
# but since __hex__ is defined, it will be called.
|
|
pc_hex = frame0.__hex__()
|
|
self.assertIsInstance(pc_hex, int, "__hex__ should return an integer (PC)")
|
|
self.assertEqual(pc_hex, frame0.GetPC(), "__hex__ should return PC")
|
|
|
|
def test_special_method_eq(self):
|
|
"""Test SBFrame extension special method: __eq__ and __ne__"""
|
|
frame0, thread = self._get_frame()
|
|
|
|
# Test __eq__ and __ne__.
|
|
frame0_copy = thread.GetFrameAtIndex(0)
|
|
self.assertTrue(frame0 == frame0_copy, "Same frame should be equal")
|
|
self.assertFalse(frame0 != frame0_copy, "Same frame should not be not-equal")
|
|
|
|
if thread.GetNumFrames() > 1:
|
|
frame1 = thread.GetFrameAtIndex(1)
|
|
self.assertFalse(frame0 == frame1, "Different frames should not be equal")
|
|
self.assertTrue(frame0 != frame1, "Different frames should be not-equal")
|
|
|
|
def test_pc_property_settable(self):
|
|
"""Test that pc property is settable"""
|
|
frame, _ = self._get_frame()
|
|
|
|
original_pc = frame.GetPC()
|
|
# Test that we can set pc (though this might not work on all platforms).
|
|
# We'll just verify the property exists and can be read.
|
|
pc = frame.pc
|
|
self.assertIsInstance(pc, int, "pc should be readable")
|
|
# Note: Setting pc might not be supported on all platforms, so we just test reading.
|