File: TestVTableValue.py

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (186 lines) | stat: -rw-r--r-- 7,831 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
"""
Make sure the getting a variable path works and doesn't crash.
"""


import lldb
import lldbsuite.test.lldbutil as lldbutil
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *

class TestVTableValue(TestBase):
    # If your test case doesn't stress debug info, then
    # set this to true.  That way it won't be run once for
    # each debug info format.
    NO_DEBUG_INFO_TESTCASE = True

    @skipUnlessPlatform(["linux", "macosx"])
    def test_vtable(self):
        self.build()
        lldbutil.run_to_source_breakpoint(
            self, "At the end", lldb.SBFileSpec("main.cpp")
        )

        # Test a shape instance to make sure we get the vtable correctly.
        shape = self.frame().FindVariable("shape")
        vtable = shape.GetVTable()
        self.assertEqual(vtable.GetName(), "vtable for Shape")
        self.assertEqual(vtable.GetTypeName(), "vtable for Shape")
        # Make sure we have the right number of virtual functions in our vtable
        # for the shape class.
        self.assertEqual(vtable.GetNumChildren(), 4)

        # Verify vtable address
        vtable_addr = vtable.GetValueAsUnsigned(0)
        expected_addr = self.expected_vtable_addr(shape)
        self.assertEqual(vtable_addr, expected_addr)

        for (idx, vtable_entry) in enumerate(vtable.children):
            self.verify_vtable_entry(vtable_entry, vtable_addr, idx)

        # Test a shape reference to make sure we get the vtable correctly.
        shape = self.frame().FindVariable("shape_ref")
        vtable = shape.GetVTable()
        self.assertEqual(vtable.GetName(), "vtable for Shape")
        self.assertEqual(vtable.GetTypeName(), "vtable for Shape")
        # Make sure we have the right number of virtual functions in our vtable
        # for the shape class.
        self.assertEqual(vtable.GetNumChildren(), 4)

        # Verify vtable address
        vtable_addr = vtable.GetValueAsUnsigned(0)
        expected_addr = self.expected_vtable_addr(shape)
        self.assertEqual(vtable_addr, expected_addr)

        for (idx, vtable_entry) in enumerate(vtable.children):
            self.verify_vtable_entry(vtable_entry, vtable_addr, idx)


        # Test we get the right vtable for the Rectangle instance.
        rect = self.frame().FindVariable("rect")
        vtable = rect.GetVTable()
        self.assertEqual(vtable.GetName(), "vtable for Rectangle")
        self.assertEqual(vtable.GetTypeName(), "vtable for Rectangle")

        # Make sure we have the right number of virtual functions in our vtable
        # with the extra virtual function added by the Rectangle class
        self.assertEqual(vtable.GetNumChildren(), 5)

        # Verify vtable address
        vtable_addr = vtable.GetValueAsUnsigned()
        expected_addr = self.expected_vtable_addr(rect)
        self.assertEqual(vtable_addr, expected_addr)

        for (idx, vtable_entry) in enumerate(vtable.children):
            self.verify_vtable_entry(vtable_entry, vtable_addr, idx)

    @skipUnlessPlatform(["linux", "macosx"])
    def test_base_class_ptr(self):
        self.build()
        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
            self, "Shape is Rectangle", lldb.SBFileSpec("main.cpp")
        )

        shape = self.frame().FindVariable("shape")
        rect = self.frame().FindVariable("rect")

        shape_ptr = self.frame().FindVariable("shape_ptr")
        shape_ptr_vtable = shape_ptr.GetVTable()
        self.assertEqual(shape_ptr_vtable.GetName(), "vtable for Rectangle")
        self.assertEqual(shape_ptr_vtable.GetNumChildren(), 5)
        self.assertEqual(shape_ptr.GetValueAsUnsigned(0),
                          rect.GetLoadAddress())
        lldbutil.continue_to_source_breakpoint(
            self, process, "Shape is Shape", lldb.SBFileSpec("main.cpp")
        )
        self.assertEqual(shape_ptr.GetValueAsUnsigned(0),
                          shape.GetLoadAddress())
        self.assertEqual(shape_ptr_vtable.GetNumChildren(), 4)
        self.assertEqual(shape_ptr_vtable.GetName(), "vtable for Shape")

    @skipUnlessPlatform(["linux", "macosx"])
    def test_no_vtable(self):
        self.build()
        lldbutil.run_to_source_breakpoint(
            self, "At the end", lldb.SBFileSpec("main.cpp")
        )

        var = self.frame().FindVariable("not_virtual")
        self.assertEqual(var.GetVTable().GetError().GetCString(),
                         'type "NotVirtual" doesn\'t have a vtable')

        var = self.frame().FindVariable("argc")
        self.assertEqual(var.GetVTable().GetError().GetCString(),
                         'no language runtime support for the language "c"')

    @skipUnlessPlatform(["linux", "macosx"])
    def test_overwrite_vtable(self):
        self.build()
        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
            self, "At the end", lldb.SBFileSpec("main.cpp")
        )

        # Test a shape instance to make sure we get the vtable correctly.
        shape = self.frame().FindVariable("shape")
        vtable = shape.GetVTable()
        self.assertEqual(vtable.GetName(), "vtable for Shape")
        self.assertEqual(vtable.GetTypeName(), "vtable for Shape")
        # Make sure we have the right number of virtual functions in our vtable
        # for the shape class.
        self.assertEqual(vtable.GetNumChildren(), 4)

        # Overwrite the first entry in the vtable and make sure we can still
        # see the bogus value which should have no summary
        vtable_addr = vtable.GetValueAsUnsigned()
        data = str("\x01\x01\x01\x01\x01\x01\x01\x01")
        error = lldb.SBError()
        process.WriteMemory(vtable_addr, data, error)

        scribbled_child = vtable.GetChildAtIndex(0)
        self.assertEqual(scribbled_child.GetValueAsUnsigned(0),
                          0x0101010101010101)
        self.assertEqual(scribbled_child.GetSummary(), None)

    def expected_vtable_addr(self, var: lldb.SBValue) -> int:
        load_addr = var.GetLoadAddress()
        read_from_memory_error = lldb.SBError()
        vtable_addr = self.process().ReadPointerFromMemory(
            load_addr, read_from_memory_error
        )
        self.assertTrue(read_from_memory_error.Success())
        return vtable_addr

    def expected_vtable_entry_func_ptr(self, vtable_addr: int, idx: int):
        vtable_entry_addr = vtable_addr + idx * self.process().GetAddressByteSize()
        read_func_ptr_error = lldb.SBError()
        func_ptr = self.process().ReadPointerFromMemory(vtable_entry_addr,
                                                        read_func_ptr_error)
        self.assertTrue(read_func_ptr_error.Success())
        return func_ptr

    def verify_vtable_entry(self, vtable_entry: lldb.SBValue, vtable_addr: int,
                            idx: int):
        """Verify the vtable entry looks something like:

        (double ()) [0] = 0x0000000100003a10 a.out`Rectangle::Area() at main.cpp:14

        """
        # Check function ptr
        vtable_entry_func_ptr = vtable_entry.GetValueAsUnsigned(0)
        self.assertEqual(
            vtable_entry_func_ptr,
            self.expected_vtable_entry_func_ptr(vtable_addr, idx),
        )

        sb_addr = self.target().ResolveLoadAddress(vtable_entry_func_ptr)
        sym_ctx = sb_addr.GetSymbolContext(lldb.eSymbolContextEverything)

        # Make sure the type is the same as the function type
        func_type = sym_ctx.GetFunction().GetType()
        if func_type.IsValid():
            self.assertEqual(vtable_entry.GetType(),
                              func_type.GetPointerType())

        # The summary should be the address description of the function pointer
        summary = vtable_entry.GetSummary()
        self.assertEqual(str(sb_addr), summary)