"""Test Python APIs for working with formatters"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class SBFormattersAPITestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
self.line = line_number("main.cpp", "// Set break point at this line.")
def test_formatters_api(self):
"""Test Python APIs for working with formatters"""
self.build()
self.setTearDownCleanup()
"""Test Python APIs for working with formatters"""
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
lldbutil.run_break_set_by_file_and_line(
self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True
)
self.runCmd("run", RUN_SUCCEEDED)
# The stop reason of the thread should be breakpoint.
self.expect(
"thread list",
STOPPED_DUE_TO_BREAKPOINT,
substrs=["stopped", "stop reason = breakpoint"],
)
# This is the function to remove the custom formats in order to have a
# clean slate for the next test case.
def cleanup():
self.runCmd("type format clear", check=False)
self.runCmd("type summary clear", check=False)
self.runCmd("type filter clear", check=False)
self.runCmd("type synthetic clear", check=False)
self.runCmd("type category delete foobar", check=False)
self.runCmd("type category delete JASSynth", check=False)
self.runCmd("type category delete newbar", check=False)
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
format = lldb.SBTypeFormat(lldb.eFormatHex)
category = self.dbg.GetDefaultCategory()
category.AddTypeFormat(lldb.SBTypeNameSpecifier("int"), format)
self.expect("frame variable foo.A", substrs=["0x00000001"])
self.expect("frame variable foo.E", matching=False, substrs=["b8cca70a"])
category.AddTypeFormat(lldb.SBTypeNameSpecifier("long"), format)
self.expect("frame variable foo.A", substrs=["0x00000001"])
self.expect("frame variable foo.E", substrs=["b8cca70a"])
format.SetFormat(lldb.eFormatOctal)
category.AddTypeFormat(lldb.SBTypeNameSpecifier("int"), format)
self.expect("frame variable foo.A", substrs=[" 01"])
self.expect("frame variable foo.E", substrs=["b8cca70a"])
category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("int"))
category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("long"))
self.expect("frame variable foo.A", matching=False, substrs=[" 01"])
self.expect("frame variable foo.E", matching=False, substrs=["b8cca70a"])
summary = lldb.SBTypeSummary.CreateWithSummaryString(
"the hello world you'll never see"
)
summary.SetSummaryString("hello world")
new_category = self.dbg.GetCategory("foobar")
self.assertFalse(
new_category.IsValid(), "getting a non-existing category worked"
)
new_category = self.dbg.CreateCategory("foobar")
new_category.SetEnabled(True)
new_category.AddTypeSummary(
lldb.SBTypeNameSpecifier(
"^.*t$",
True, # is_regexp
),
summary,
)
self.expect("frame variable foo.A", substrs=["hello world"])
self.expect("frame variable foo.E", matching=False, substrs=["hello world"])
self.expect("frame variable foo.B", substrs=["hello world"])
self.expect("frame variable foo.F", substrs=["hello world"])
new_category.SetEnabled(False)
self.expect("frame variable foo.A", matching=False, substrs=["hello world"])
self.expect("frame variable foo.E", matching=False, substrs=["hello world"])
self.expect("frame variable foo.B", matching=False, substrs=["hello world"])
self.expect("frame variable foo.F", matching=False, substrs=["hello world"])
self.dbg.DeleteCategory(new_category.GetName())
self.expect("frame variable foo.A", matching=False, substrs=["hello world"])
self.expect("frame variable foo.E", matching=False, substrs=["hello world"])
self.expect("frame variable foo.B", matching=False, substrs=["hello world"])
self.expect("frame variable foo.F", matching=False, substrs=["hello world"])
filter = lldb.SBTypeFilter(0)
filter.AppendExpressionPath("A")
filter.AppendExpressionPath("D")
self.assertEqual(
filter.GetNumberOfExpressionPaths(),
2,
"filter with two items does not have two items",
)
category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter)
self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"])
self.expect(
"frame variable foo",
matching=False,
substrs=["B = ", "C = ", "E = ", "F = "],
)
category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct", True))
self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"])
self.expect(
"frame variable foo",
matching=False,
substrs=["B = ", "C = ", "E = ", "F = "],
)
category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct", False))
self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"])
self.expect(
"frame variable foo",
matching=True,
substrs=["B = ", "C = ", "E = ", "F = "],
)
self.runCmd("command script import --allow-reload ./synth.py")
self.expect("frame variable foo", matching=False, substrs=["X = 1"])
self.dbg.GetCategory("JASSynth").SetEnabled(True)
self.expect("frame variable foo", matching=True, substrs=["X = 1"])
self.dbg.GetCategory("CCCSynth2").SetEnabled(True)
self.expect(
"frame variable ccc",
matching=True,
substrs=[
"CCC object with leading synthetic value (int) b = 222",
"a = 111",
"b = 222",
"c = 333",
],
)
self.dbg.GetCategory("CCCSynth2").SetEnabled(False)
self.dbg.GetCategory("CCCSynth").SetEnabled(True)
self.expect(
"frame variable ccc",
matching=True,
substrs=[
"CCC object with leading value (int) a = 111",
"a = 111",
"b = 222",
"c = 333",
],
)
self.dbg.GetCategory("BarIntSynth").SetEnabled(True)
self.expect(
"frame variable bar_int",
matching=True,
substrs=[
"(int) bar_int = 20 bar_int synthetic: No value",
],
)
foo_var = (
self.dbg.GetSelectedTarget()
.GetProcess()
.GetSelectedThread()
.GetSelectedFrame()
.FindVariable("foo")
)
self.assertTrue(foo_var.IsValid(), "could not find foo")
self.assertTrue(
foo_var.GetDeclaration().IsValid(), "foo declaration is invalid"
)
self.assertEqual(
foo_var.GetNumChildren(),
2,
"synthetic value has wrong number of child items (synth)",
)
self.assertEqual(
foo_var.GetChildMemberWithName("X").GetValueAsUnsigned(),
1,
"foo_synth.X has wrong value (synth)",
)
self.assertFalse(
foo_var.GetChildMemberWithName("B").IsValid(),
"foo_synth.B is valid but should not (synth)",
)
self.dbg.GetCategory("JASSynth").SetEnabled(False)
foo_var = (
self.dbg.GetSelectedTarget()
.GetProcess()
.GetSelectedThread()
.GetSelectedFrame()
.FindVariable("foo")
)
self.assertTrue(foo_var.IsValid(), "could not find foo")
self.assertNotEqual(foo_var.GetNumChildren(), 2, "still seeing synthetic value")
filter = lldb.SBTypeFilter(0)
filter.AppendExpressionPath("A")
filter.AppendExpressionPath("D")
category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter)
self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"])
foo_var = (
self.dbg.GetSelectedTarget()
.GetProcess()
.GetSelectedThread()
.GetSelectedFrame()
.FindVariable("foo")
)
self.assertTrue(foo_var.IsValid(), "could not find foo")
self.assertEqual(
foo_var.GetNumChildren(),
2,
"synthetic value has wrong number of child items (filter)",
)
self.assertEqual(
foo_var.GetChildMemberWithName("X").GetValueAsUnsigned(),
0,
"foo_synth.X has wrong value (filter)",
)
self.assertEqual(
foo_var.GetChildMemberWithName("A").GetValueAsUnsigned(),
1,
"foo_synth.A has wrong value (filter)",
)
self.assertTrue(
filter.ReplaceExpressionPathAtIndex(0, "C"),
"failed to replace an expression path in filter",
)
self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"])
category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter)
self.expect("frame variable foo", substrs=["C = 'e'", "D = 6.28"])
category.AddTypeFilter(lldb.SBTypeNameSpecifier("FooType"), filter)
filter.ReplaceExpressionPathAtIndex(1, "F")
self.expect("frame variable foo", substrs=["C = 'e'", "D = 6.28"])
category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter)
self.expect("frame variable foo", substrs=["C = 'e'", "F = 0"])
self.expect("frame variable bar", substrs=["C = 'e'", "D = 6.28"])
foo_var = (
self.dbg.GetSelectedTarget()
.GetProcess()
.GetSelectedThread()
.GetSelectedFrame()
.FindVariable("foo")
)
self.assertTrue(foo_var.IsValid(), "could not find foo")
self.assertEqual(
foo_var.GetChildMemberWithName("C").GetValueAsUnsigned(),
ord("e"),
"foo_synth.C has wrong value (filter)",
)
chosen = self.dbg.GetFilterForType(lldb.SBTypeNameSpecifier("JustAStruct"))
self.assertEqual(chosen.count, 2, "wrong filter found for JustAStruct")
self.assertEqual(
chosen.GetExpressionPathAtIndex(0),
"C",
"wrong item at index 0 for JustAStruct",
)
self.assertEqual(
chosen.GetExpressionPathAtIndex(1),
"F",
"wrong item at index 1 for JustAStruct",
)
self.assertFalse(
category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("NoSuchType")),
"deleting a non-existing filter worked",
)
self.assertFalse(
category.DeleteTypeSummary(lldb.SBTypeNameSpecifier("NoSuchType")),
"deleting a non-existing summary worked",
)
self.assertFalse(
category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("NoSuchType")),
"deleting a non-existing format worked",
)
self.assertFalse(
category.DeleteTypeSynthetic(lldb.SBTypeNameSpecifier("NoSuchType")),
"deleting a non-existing synthetic worked",
)
self.assertFalse(
category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("")),
"deleting a filter for '' worked",
)
self.assertFalse(
category.DeleteTypeSummary(lldb.SBTypeNameSpecifier("")),
"deleting a summary for '' worked",
)
self.assertFalse(
category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("")),
"deleting a format for '' worked",
)
self.assertFalse(
category.DeleteTypeSynthetic(lldb.SBTypeNameSpecifier("")),
"deleting a synthetic for '' worked",
)
try:
self.assertFalse(
category.AddTypeSummary(lldb.SBTypeNameSpecifier("NoneSuchType"), None),
"adding a summary valued None worked",
)
except:
pass
else:
self.assertFalse(True, "adding a summary valued None worked")
try:
self.assertFalse(
category.AddTypeFilter(lldb.SBTypeNameSpecifier("NoneSuchType"), None),
"adding a filter valued None worked",
)
except:
pass
else:
self.assertFalse(True, "adding a filter valued None worked")
try:
self.assertFalse(
category.AddTypeSynthetic(
lldb.SBTypeNameSpecifier("NoneSuchType"), None
),
"adding a synthetic valued None worked",
)
except:
pass
else:
self.assertFalse(True, "adding a synthetic valued None worked")
try:
self.assertFalse(
category.AddTypeFormat(lldb.SBTypeNameSpecifier("NoneSuchType"), None),
"adding a format valued None worked",
)
except:
pass
else:
self.assertFalse(True, "adding a format valued None worked")
self.assertFalse(
category.AddTypeSummary(
lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeSummary()
),
"adding a summary without value worked",
)
self.assertFalse(
category.AddTypeFilter(
lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeFilter()
),
"adding a filter without value worked",
)
self.assertFalse(
category.AddTypeSynthetic(
lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeSynthetic()
),
"adding a synthetic without value worked",
)
self.assertFalse(
category.AddTypeFormat(
lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeFormat()
),
"adding a format without value worked",
)
self.assertFalse(
category.AddTypeSummary(
lldb.SBTypeNameSpecifier(""),
lldb.SBTypeSummary.CreateWithSummaryString(""),
),
"adding a summary for an invalid type worked",
)
self.assertFalse(
category.AddTypeFilter(lldb.SBTypeNameSpecifier(""), lldb.SBTypeFilter(0)),
"adding a filter for an invalid type worked",
)
self.assertFalse(
category.AddTypeSynthetic(
lldb.SBTypeNameSpecifier(""),
lldb.SBTypeSynthetic.CreateWithClassName(""),
),
"adding a synthetic for an invalid type worked",
)
self.assertFalse(
category.AddTypeFormat(
lldb.SBTypeNameSpecifier(""), lldb.SBTypeFormat(lldb.eFormatHex)
),
"adding a format for an invalid type worked",
)
new_category = self.dbg.CreateCategory("newbar")
new_category.AddTypeSummary(
lldb.SBTypeNameSpecifier("JustAStruct"),
lldb.SBTypeSummary.CreateWithScriptCode("return 'hello scripted world';"),
)
self.expect(
"frame variable foo", matching=False, substrs=["hello scripted world"]
)
new_category.SetEnabled(True)
self.expect(
"frame variable foo", matching=True, substrs=["hello scripted world"]
)
self.expect(
"frame variable foo_ptr", matching=True, substrs=["hello scripted world"]
)
new_category.AddTypeSummary(
lldb.SBTypeNameSpecifier("JustAStruct"),
lldb.SBTypeSummary.CreateWithScriptCode(
"return 'hello scripted world';", lldb.eTypeOptionSkipPointers
),
)
self.expect(
"frame variable foo", matching=True, substrs=["hello scripted world"]
)
frame = (
self.dbg.GetSelectedTarget()
.GetProcess()
.GetSelectedThread()
.GetSelectedFrame()
)
foo_ptr = frame.FindVariable("foo_ptr")
summary = foo_ptr.GetTypeSummary()
self.assertFalse(
summary.IsValid(), "summary found for foo* when none was planned"
)
self.expect(
"frame variable foo_ptr", matching=False, substrs=["hello scripted world"]
)
new_category.AddTypeSummary(
lldb.SBTypeNameSpecifier("JustAStruct"),
lldb.SBTypeSummary.CreateWithSummaryString(
"hello static world", lldb.eTypeOptionNone
),
)
summary = foo_ptr.GetTypeSummary()
self.assertTrue(
summary.IsValid(), "no summary found for foo* when one was in place"
)
self.assertEqual(
summary.GetData(), "hello static world", "wrong summary found for foo*"
)
self.expect("frame variable e1", substrs=["I am an empty Empty1 {}"])
self.expect("frame variable e2", substrs=["I am an empty Empty2"])
self.expect(
"frame variable e2", substrs=["I am an empty Empty2 {}"], matching=False
)
self.assertIsNotNone(
self.dbg.GetCategory(lldb.eLanguageTypeObjC), "ObjC category is None"
)
def test_force_synth_off(self):
"""Test that one can have the public API return non-synthetic SBValues if desired"""
self.build(dictionary={"EXE": "no_synth"})
self.setTearDownCleanup()
self.runCmd("file " + self.getBuildArtifact("no_synth"), CURRENT_EXECUTABLE_SET)
lldbutil.run_break_set_by_file_and_line(
self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True
)
self.runCmd("run", RUN_SUCCEEDED)
# The stop reason of the thread should be breakpoint.
self.expect(
"thread list",
STOPPED_DUE_TO_BREAKPOINT,
substrs=["stopped", "stop reason = breakpoint"],
)
# This is the function to remove the custom formats in order to have a
# clean slate for the next test case.
def cleanup():
self.runCmd("type format clear", check=False)
self.runCmd("type summary clear", check=False)
self.runCmd("type filter clear", check=False)
self.runCmd("type synthetic clear", check=False)
self.runCmd("type category delete foobar", check=False)
self.runCmd("type category delete JASSynth", check=False)
self.runCmd("type category delete newbar", check=False)
self.runCmd("settings set target.enable-synthetic-value true")
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
frame = (
self.dbg.GetSelectedTarget()
.GetProcess()
.GetSelectedThread()
.GetSelectedFrame()
)
int_vector = frame.FindVariable("int_vector")
if self.TraceOn():
print(int_vector)
self.assertEqual(int_vector.GetNumChildren(), 0, "synthetic vector is empty")
self.runCmd("settings set target.enable-synthetic-value false")
frame = (
self.dbg.GetSelectedTarget()
.GetProcess()
.GetSelectedThread()
.GetSelectedFrame()
)
int_vector = frame.FindVariable("int_vector")
if self.TraceOn():
print(int_vector)
self.assertNotEqual(
int_vector.GetNumChildren(), 0, '"physical" vector is not empty'
)
self.runCmd("settings set target.enable-synthetic-value true")
frame = (
self.dbg.GetSelectedTarget()
.GetProcess()
.GetSelectedThread()
.GetSelectedFrame()
)
int_vector = frame.FindVariable("int_vector")
if self.TraceOn():
print(int_vector)
self.assertEqual(
int_vector.GetNumChildren(), 0, "synthetic vector is still empty"
)