| """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("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", |
| ], |
| ) |
| |
| 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.assertFalse(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.assertTrue( |
| self.dbg.GetCategory(lldb.eLanguageTypeObjC) is not None, |
| "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.assertFalse( |
| 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" |
| ) |