xref: /llvm-project/lldb/test/API/python_api/formatters/TestFormattersSBAPI.py (revision 82af55983d75d4a821b76ee926b19725ec7fa889)
1"""Test Python APIs for working with formatters"""
2
3import lldb
4from lldbsuite.test.decorators import *
5from lldbsuite.test.lldbtest import *
6from lldbsuite.test import lldbutil
7
8
9class SBFormattersAPITestCase(TestBase):
10    NO_DEBUG_INFO_TESTCASE = True
11
12    def setUp(self):
13        # Call super's setUp().
14        TestBase.setUp(self)
15        self.line = line_number("main.cpp", "// Set break point at this line.")
16
17    def test_formatters_api(self):
18        """Test Python APIs for working with formatters"""
19        self.build()
20        self.setTearDownCleanup()
21
22        """Test Python APIs for working with formatters"""
23        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
24
25        lldbutil.run_break_set_by_file_and_line(
26            self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True
27        )
28
29        self.runCmd("run", RUN_SUCCEEDED)
30
31        # The stop reason of the thread should be breakpoint.
32        self.expect(
33            "thread list",
34            STOPPED_DUE_TO_BREAKPOINT,
35            substrs=["stopped", "stop reason = breakpoint"],
36        )
37
38        # This is the function to remove the custom formats in order to have a
39        # clean slate for the next test case.
40        def cleanup():
41            self.runCmd("type format clear", check=False)
42            self.runCmd("type summary clear", check=False)
43            self.runCmd("type filter clear", check=False)
44            self.runCmd("type synthetic clear", check=False)
45            self.runCmd("type category delete foobar", check=False)
46            self.runCmd("type category delete JASSynth", check=False)
47            self.runCmd("type category delete newbar", check=False)
48
49        # Execute the cleanup function during test case tear down.
50        self.addTearDownHook(cleanup)
51
52        format = lldb.SBTypeFormat(lldb.eFormatHex)
53        category = self.dbg.GetDefaultCategory()
54        category.AddTypeFormat(lldb.SBTypeNameSpecifier("int"), format)
55
56        self.expect("frame variable foo.A", substrs=["0x00000001"])
57        self.expect("frame variable foo.E", matching=False, substrs=["b8cca70a"])
58
59        category.AddTypeFormat(lldb.SBTypeNameSpecifier("long"), format)
60        self.expect("frame variable foo.A", substrs=["0x00000001"])
61        self.expect("frame variable foo.E", substrs=["b8cca70a"])
62
63        format.SetFormat(lldb.eFormatOctal)
64        category.AddTypeFormat(lldb.SBTypeNameSpecifier("int"), format)
65        self.expect("frame variable foo.A", substrs=[" 01"])
66        self.expect("frame variable foo.E", substrs=["b8cca70a"])
67
68        category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("int"))
69        category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("long"))
70        self.expect("frame variable foo.A", matching=False, substrs=[" 01"])
71        self.expect("frame variable foo.E", matching=False, substrs=["b8cca70a"])
72
73        summary = lldb.SBTypeSummary.CreateWithSummaryString(
74            "the hello world you'll never see"
75        )
76        summary.SetSummaryString("hello world")
77        new_category = self.dbg.GetCategory("foobar")
78        self.assertFalse(
79            new_category.IsValid(), "getting a non-existing category worked"
80        )
81        new_category = self.dbg.CreateCategory("foobar")
82        new_category.SetEnabled(True)
83        new_category.AddTypeSummary(
84            lldb.SBTypeNameSpecifier(
85                "^.*t$",
86                True,  # is_regexp
87            ),
88            summary,
89        )
90
91        self.expect("frame variable foo.A", substrs=["hello world"])
92        self.expect("frame variable foo.E", matching=False, substrs=["hello world"])
93        self.expect("frame variable foo.B", substrs=["hello world"])
94        self.expect("frame variable foo.F", substrs=["hello world"])
95        new_category.SetEnabled(False)
96        self.expect("frame variable foo.A", matching=False, substrs=["hello world"])
97        self.expect("frame variable foo.E", matching=False, substrs=["hello world"])
98        self.expect("frame variable foo.B", matching=False, substrs=["hello world"])
99        self.expect("frame variable foo.F", matching=False, substrs=["hello world"])
100        self.dbg.DeleteCategory(new_category.GetName())
101        self.expect("frame variable foo.A", matching=False, substrs=["hello world"])
102        self.expect("frame variable foo.E", matching=False, substrs=["hello world"])
103        self.expect("frame variable foo.B", matching=False, substrs=["hello world"])
104        self.expect("frame variable foo.F", matching=False, substrs=["hello world"])
105
106        filter = lldb.SBTypeFilter(0)
107        filter.AppendExpressionPath("A")
108        filter.AppendExpressionPath("D")
109        self.assertEqual(
110            filter.GetNumberOfExpressionPaths(),
111            2,
112            "filter with two items does not have two items",
113        )
114
115        category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter)
116        self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"])
117        self.expect(
118            "frame variable foo",
119            matching=False,
120            substrs=["B = ", "C = ", "E = ", "F = "],
121        )
122
123        category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct", True))
124        self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"])
125        self.expect(
126            "frame variable foo",
127            matching=False,
128            substrs=["B = ", "C = ", "E = ", "F = "],
129        )
130
131        category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct", False))
132        self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"])
133        self.expect(
134            "frame variable foo",
135            matching=True,
136            substrs=["B = ", "C = ", "E = ", "F = "],
137        )
138
139        self.runCmd("command script import --allow-reload ./synth.py")
140
141        self.expect("frame variable foo", matching=False, substrs=["X = 1"])
142
143        self.dbg.GetCategory("JASSynth").SetEnabled(True)
144        self.expect("frame variable foo", matching=True, substrs=["X = 1"])
145
146        self.dbg.GetCategory("CCCSynth2").SetEnabled(True)
147        self.expect(
148            "frame variable ccc",
149            matching=True,
150            substrs=[
151                "CCC object with leading synthetic value (int) b = 222",
152                "a = 111",
153                "b = 222",
154                "c = 333",
155            ],
156        )
157        self.dbg.GetCategory("CCCSynth2").SetEnabled(False)
158
159        self.dbg.GetCategory("CCCSynth").SetEnabled(True)
160        self.expect(
161            "frame variable ccc",
162            matching=True,
163            substrs=[
164                "CCC object with leading value (int) a = 111",
165                "a = 111",
166                "b = 222",
167                "c = 333",
168            ],
169        )
170
171        self.dbg.GetCategory("BarIntSynth").SetEnabled(True)
172        self.expect(
173            "frame variable bar_int",
174            matching=True,
175            substrs=[
176                "(int) bar_int = 20 bar_int synthetic: No value",
177            ],
178        )
179
180        foo_var = (
181            self.dbg.GetSelectedTarget()
182            .GetProcess()
183            .GetSelectedThread()
184            .GetSelectedFrame()
185            .FindVariable("foo")
186        )
187        self.assertTrue(foo_var.IsValid(), "could not find foo")
188        self.assertTrue(
189            foo_var.GetDeclaration().IsValid(), "foo declaration is invalid"
190        )
191
192        self.assertEqual(
193            foo_var.GetNumChildren(),
194            2,
195            "synthetic value has wrong number of child items (synth)",
196        )
197        self.assertEqual(
198            foo_var.GetChildMemberWithName("X").GetValueAsUnsigned(),
199            1,
200            "foo_synth.X has wrong value (synth)",
201        )
202        self.assertFalse(
203            foo_var.GetChildMemberWithName("B").IsValid(),
204            "foo_synth.B is valid but should not (synth)",
205        )
206
207        self.dbg.GetCategory("JASSynth").SetEnabled(False)
208        foo_var = (
209            self.dbg.GetSelectedTarget()
210            .GetProcess()
211            .GetSelectedThread()
212            .GetSelectedFrame()
213            .FindVariable("foo")
214        )
215        self.assertTrue(foo_var.IsValid(), "could not find foo")
216
217        self.assertNotEqual(foo_var.GetNumChildren(), 2, "still seeing synthetic value")
218
219        filter = lldb.SBTypeFilter(0)
220        filter.AppendExpressionPath("A")
221        filter.AppendExpressionPath("D")
222        category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter)
223        self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"])
224
225        foo_var = (
226            self.dbg.GetSelectedTarget()
227            .GetProcess()
228            .GetSelectedThread()
229            .GetSelectedFrame()
230            .FindVariable("foo")
231        )
232        self.assertTrue(foo_var.IsValid(), "could not find foo")
233
234        self.assertEqual(
235            foo_var.GetNumChildren(),
236            2,
237            "synthetic value has wrong number of child items (filter)",
238        )
239        self.assertEqual(
240            foo_var.GetChildMemberWithName("X").GetValueAsUnsigned(),
241            0,
242            "foo_synth.X has wrong value (filter)",
243        )
244        self.assertEqual(
245            foo_var.GetChildMemberWithName("A").GetValueAsUnsigned(),
246            1,
247            "foo_synth.A has wrong value (filter)",
248        )
249
250        self.assertTrue(
251            filter.ReplaceExpressionPathAtIndex(0, "C"),
252            "failed to replace an expression path in filter",
253        )
254        self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"])
255        category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter)
256        self.expect("frame variable foo", substrs=["C = 'e'", "D = 6.28"])
257        category.AddTypeFilter(lldb.SBTypeNameSpecifier("FooType"), filter)
258        filter.ReplaceExpressionPathAtIndex(1, "F")
259        self.expect("frame variable foo", substrs=["C = 'e'", "D = 6.28"])
260        category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter)
261        self.expect("frame variable foo", substrs=["C = 'e'", "F = 0"])
262        self.expect("frame variable bar", substrs=["C = 'e'", "D = 6.28"])
263
264        foo_var = (
265            self.dbg.GetSelectedTarget()
266            .GetProcess()
267            .GetSelectedThread()
268            .GetSelectedFrame()
269            .FindVariable("foo")
270        )
271        self.assertTrue(foo_var.IsValid(), "could not find foo")
272        self.assertEqual(
273            foo_var.GetChildMemberWithName("C").GetValueAsUnsigned(),
274            ord("e"),
275            "foo_synth.C has wrong value (filter)",
276        )
277
278        chosen = self.dbg.GetFilterForType(lldb.SBTypeNameSpecifier("JustAStruct"))
279        self.assertEqual(chosen.count, 2, "wrong filter found for JustAStruct")
280        self.assertEqual(
281            chosen.GetExpressionPathAtIndex(0),
282            "C",
283            "wrong item at index 0 for JustAStruct",
284        )
285        self.assertEqual(
286            chosen.GetExpressionPathAtIndex(1),
287            "F",
288            "wrong item at index 1 for JustAStruct",
289        )
290
291        self.assertFalse(
292            category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("NoSuchType")),
293            "deleting a non-existing filter worked",
294        )
295        self.assertFalse(
296            category.DeleteTypeSummary(lldb.SBTypeNameSpecifier("NoSuchType")),
297            "deleting a non-existing summary worked",
298        )
299        self.assertFalse(
300            category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("NoSuchType")),
301            "deleting a non-existing format worked",
302        )
303        self.assertFalse(
304            category.DeleteTypeSynthetic(lldb.SBTypeNameSpecifier("NoSuchType")),
305            "deleting a non-existing synthetic worked",
306        )
307
308        self.assertFalse(
309            category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("")),
310            "deleting a filter for '' worked",
311        )
312        self.assertFalse(
313            category.DeleteTypeSummary(lldb.SBTypeNameSpecifier("")),
314            "deleting a summary for '' worked",
315        )
316        self.assertFalse(
317            category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("")),
318            "deleting a format for '' worked",
319        )
320        self.assertFalse(
321            category.DeleteTypeSynthetic(lldb.SBTypeNameSpecifier("")),
322            "deleting a synthetic for '' worked",
323        )
324
325        try:
326            self.assertFalse(
327                category.AddTypeSummary(lldb.SBTypeNameSpecifier("NoneSuchType"), None),
328                "adding a summary valued None worked",
329            )
330        except:
331            pass
332        else:
333            self.assertFalse(True, "adding a summary valued None worked")
334
335        try:
336            self.assertFalse(
337                category.AddTypeFilter(lldb.SBTypeNameSpecifier("NoneSuchType"), None),
338                "adding a filter valued None worked",
339            )
340        except:
341            pass
342        else:
343            self.assertFalse(True, "adding a filter valued None worked")
344
345        try:
346            self.assertFalse(
347                category.AddTypeSynthetic(
348                    lldb.SBTypeNameSpecifier("NoneSuchType"), None
349                ),
350                "adding a synthetic valued None worked",
351            )
352        except:
353            pass
354        else:
355            self.assertFalse(True, "adding a synthetic valued None worked")
356
357        try:
358            self.assertFalse(
359                category.AddTypeFormat(lldb.SBTypeNameSpecifier("NoneSuchType"), None),
360                "adding a format valued None worked",
361            )
362        except:
363            pass
364        else:
365            self.assertFalse(True, "adding a format valued None worked")
366
367        self.assertFalse(
368            category.AddTypeSummary(
369                lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeSummary()
370            ),
371            "adding a summary without value worked",
372        )
373        self.assertFalse(
374            category.AddTypeFilter(
375                lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeFilter()
376            ),
377            "adding a filter without value worked",
378        )
379        self.assertFalse(
380            category.AddTypeSynthetic(
381                lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeSynthetic()
382            ),
383            "adding a synthetic without value worked",
384        )
385        self.assertFalse(
386            category.AddTypeFormat(
387                lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeFormat()
388            ),
389            "adding a format without value worked",
390        )
391
392        self.assertFalse(
393            category.AddTypeSummary(
394                lldb.SBTypeNameSpecifier(""),
395                lldb.SBTypeSummary.CreateWithSummaryString(""),
396            ),
397            "adding a summary for an invalid type worked",
398        )
399        self.assertFalse(
400            category.AddTypeFilter(lldb.SBTypeNameSpecifier(""), lldb.SBTypeFilter(0)),
401            "adding a filter for an invalid type worked",
402        )
403        self.assertFalse(
404            category.AddTypeSynthetic(
405                lldb.SBTypeNameSpecifier(""),
406                lldb.SBTypeSynthetic.CreateWithClassName(""),
407            ),
408            "adding a synthetic for an invalid type worked",
409        )
410        self.assertFalse(
411            category.AddTypeFormat(
412                lldb.SBTypeNameSpecifier(""), lldb.SBTypeFormat(lldb.eFormatHex)
413            ),
414            "adding a format for an invalid type worked",
415        )
416
417        new_category = self.dbg.CreateCategory("newbar")
418        new_category.AddTypeSummary(
419            lldb.SBTypeNameSpecifier("JustAStruct"),
420            lldb.SBTypeSummary.CreateWithScriptCode("return 'hello scripted world';"),
421        )
422        self.expect(
423            "frame variable foo", matching=False, substrs=["hello scripted world"]
424        )
425        new_category.SetEnabled(True)
426        self.expect(
427            "frame variable foo", matching=True, substrs=["hello scripted world"]
428        )
429
430        self.expect(
431            "frame variable foo_ptr", matching=True, substrs=["hello scripted world"]
432        )
433        new_category.AddTypeSummary(
434            lldb.SBTypeNameSpecifier("JustAStruct"),
435            lldb.SBTypeSummary.CreateWithScriptCode(
436                "return 'hello scripted world';", lldb.eTypeOptionSkipPointers
437            ),
438        )
439        self.expect(
440            "frame variable foo", matching=True, substrs=["hello scripted world"]
441        )
442
443        frame = (
444            self.dbg.GetSelectedTarget()
445            .GetProcess()
446            .GetSelectedThread()
447            .GetSelectedFrame()
448        )
449        foo_ptr = frame.FindVariable("foo_ptr")
450        summary = foo_ptr.GetTypeSummary()
451
452        self.assertFalse(
453            summary.IsValid(), "summary found for foo* when none was planned"
454        )
455
456        self.expect(
457            "frame variable foo_ptr", matching=False, substrs=["hello scripted world"]
458        )
459
460        new_category.AddTypeSummary(
461            lldb.SBTypeNameSpecifier("JustAStruct"),
462            lldb.SBTypeSummary.CreateWithSummaryString(
463                "hello static world", lldb.eTypeOptionNone
464            ),
465        )
466
467        summary = foo_ptr.GetTypeSummary()
468
469        self.assertTrue(
470            summary.IsValid(), "no summary found for foo* when one was in place"
471        )
472        self.assertEqual(
473            summary.GetData(), "hello static world", "wrong summary found for foo*"
474        )
475
476        self.expect("frame variable e1", substrs=["I am an empty Empty1 {}"])
477        self.expect("frame variable e2", substrs=["I am an empty Empty2"])
478        self.expect(
479            "frame variable e2", substrs=["I am an empty Empty2 {}"], matching=False
480        )
481
482        self.assertIsNotNone(
483            self.dbg.GetCategory(lldb.eLanguageTypeObjC), "ObjC category is None"
484        )
485
486    def test_force_synth_off(self):
487        """Test that one can have the public API return non-synthetic SBValues if desired"""
488        self.build(dictionary={"EXE": "no_synth"})
489        self.setTearDownCleanup()
490
491        self.runCmd("file " + self.getBuildArtifact("no_synth"), CURRENT_EXECUTABLE_SET)
492
493        lldbutil.run_break_set_by_file_and_line(
494            self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True
495        )
496
497        self.runCmd("run", RUN_SUCCEEDED)
498
499        # The stop reason of the thread should be breakpoint.
500        self.expect(
501            "thread list",
502            STOPPED_DUE_TO_BREAKPOINT,
503            substrs=["stopped", "stop reason = breakpoint"],
504        )
505
506        # This is the function to remove the custom formats in order to have a
507        # clean slate for the next test case.
508        def cleanup():
509            self.runCmd("type format clear", check=False)
510            self.runCmd("type summary clear", check=False)
511            self.runCmd("type filter clear", check=False)
512            self.runCmd("type synthetic clear", check=False)
513            self.runCmd("type category delete foobar", check=False)
514            self.runCmd("type category delete JASSynth", check=False)
515            self.runCmd("type category delete newbar", check=False)
516            self.runCmd("settings set target.enable-synthetic-value true")
517
518        # Execute the cleanup function during test case tear down.
519        self.addTearDownHook(cleanup)
520
521        frame = (
522            self.dbg.GetSelectedTarget()
523            .GetProcess()
524            .GetSelectedThread()
525            .GetSelectedFrame()
526        )
527        int_vector = frame.FindVariable("int_vector")
528        if self.TraceOn():
529            print(int_vector)
530        self.assertEqual(int_vector.GetNumChildren(), 0, "synthetic vector is empty")
531
532        self.runCmd("settings set target.enable-synthetic-value false")
533        frame = (
534            self.dbg.GetSelectedTarget()
535            .GetProcess()
536            .GetSelectedThread()
537            .GetSelectedFrame()
538        )
539        int_vector = frame.FindVariable("int_vector")
540        if self.TraceOn():
541            print(int_vector)
542        self.assertNotEqual(
543            int_vector.GetNumChildren(), 0, '"physical" vector is not empty'
544        )
545
546        self.runCmd("settings set target.enable-synthetic-value true")
547        frame = (
548            self.dbg.GetSelectedTarget()
549            .GetProcess()
550            .GetSelectedThread()
551            .GetSelectedFrame()
552        )
553        int_vector = frame.FindVariable("int_vector")
554        if self.TraceOn():
555            print(int_vector)
556        self.assertEqual(
557            int_vector.GetNumChildren(), 0, "synthetic vector is still empty"
558        )
559