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
|
import py
import sys, re
from rpython.translator.c.gcc.trackgcroot import LOC_NOWHERE, LOC_REG
from rpython.translator.c.gcc.trackgcroot import LOC_EBP_PLUS, LOC_EBP_MINUS
from rpython.translator.c.gcc.trackgcroot import LOC_ESP_PLUS
from rpython.translator.c.gcc.trackgcroot import ElfAssemblerParser
from rpython.translator.c.gcc.trackgcroot import DarwinAssemblerParser
from rpython.translator.c.gcc.trackgcroot import PARSERS
from rpython.translator.c.gcc.trackgcroot import ElfFunctionGcRootTracker32
from StringIO import StringIO
import py.test
this_dir = py.path.local(__file__).dirpath()
def test_format_location():
cls = ElfFunctionGcRootTracker32
assert cls.format_location(LOC_NOWHERE) == '?'
assert cls.format_location(LOC_REG | (1<<2)) == '%ebx'
assert cls.format_location(LOC_REG | (2<<2)) == '%esi'
assert cls.format_location(LOC_REG | (3<<2)) == '%edi'
assert cls.format_location(LOC_REG | (4<<2)) == '%ebp'
assert cls.format_location(LOC_EBP_PLUS + 0) == '(%ebp)'
assert cls.format_location(LOC_EBP_PLUS + 4) == '4(%ebp)'
assert cls.format_location(LOC_EBP_MINUS + 4) == '-4(%ebp)'
assert cls.format_location(LOC_ESP_PLUS + 0) == '(%esp)'
assert cls.format_location(LOC_ESP_PLUS + 4) == '4(%esp)'
def test_format_callshape():
cls = ElfFunctionGcRootTracker32
expected = ('{4(%ebp) ' # position of the return address
'| 8(%ebp), 12(%ebp), 16(%ebp), 20(%ebp) ' # 4 saved regs
'| 24(%ebp), 28(%ebp)}') # GC roots
assert cls.format_callshape((LOC_EBP_PLUS+4,
LOC_EBP_PLUS+8,
LOC_EBP_PLUS+12,
LOC_EBP_PLUS+16,
LOC_EBP_PLUS+20,
LOC_EBP_PLUS+24,
LOC_EBP_PLUS+28)) == expected
def test_compress_callshape():
cls = ElfFunctionGcRootTracker32
shape = (1, 127, 0x1234, 0x5678, 0x234567,
0x765432, 0x61626364, 0x41424344)
bytes = list(cls.compress_callshape(shape))
print bytes
assert len(bytes) == 1+1+2+3+4+4+5+5+1
assert cls.decompress_callshape(bytes) == list(shape)
def test_find_functions_elf():
source = """\
\t.p2align 4,,15
.globl pypy_g_make_tree
\t.type\tpypy_g_make_tree, @function
\tFOO
\t.size\tpypy_g_make_tree, .-pypy_g_make_tree
\t.p2align 4,,15
.globl pypy_fn2
\t.type\tpypy_fn2, @function
\tBAR
\t.size\tpypy_fn2, .-pypy_fn2
\tMORE STUFF
"""
lines = source.splitlines(True)
parts = list(ElfAssemblerParser().find_functions(iter(lines)))
assert len(parts) == 5
assert parts[0] == (False, lines[:2])
assert parts[1] == (True, lines[2:5])
assert parts[2] == (False, lines[5:8])
assert parts[3] == (True, lines[8:11])
assert parts[4] == (False, lines[11:])
def test_find_functions_darwin():
source = """\
\t.text
\t.align 4,0x90
.globl _pypy_g_ll_str__StringR_Ptr_GcStruct_rpy_strin_rpy_strin
_pypy_g_ll_str__StringR_Ptr_GcStruct_rpy_strin_rpy_strin:
L0:
\tFOO
\t.align 4,0x90
_static:
\tSTATIC
\t.align 4,0x90
.globl _pypy_g_ll_issubclass__object_vtablePtr_object_vtablePtr
_pypy_g_ll_issubclass__object_vtablePtr_object_vtablePtr:
\tBAR
\t.cstring
\t.ascii "foo"
\t.text
\t.align 4,0x90
.globl _pypy_g_RPyRaiseException
_pypy_g_RPyRaiseException:
\tBAZ
\t.section stuff
"""
lines = source.splitlines(True)
parts = list(DarwinAssemblerParser().find_functions(iter(lines)))
assert len(parts) == 6
assert parts[0] == (False, lines[:3])
assert parts[1] == (True, lines[3:7])
assert parts[2] == (True, lines[7:11])
assert parts[3] == (True, lines[11:18])
assert parts[4] == (True, lines[18:20])
assert parts[5] == (False, lines[20:])
def test_computegcmaptable():
tests = []
for format in ('elf', 'elf64', 'darwin', 'darwin64', 'msvc'):
for path in this_dir.join(format).listdir("track*.s"):
n = path.purebasename[5:]
try:
n = int(n)
except ValueError:
pass
tests.append((format, n, path))
tests.sort()
for format, _, path in tests:
yield check_computegcmaptable, format, path
r_expected = re.compile(r"\s*;;\s*expected\s+([{].+[}])")
r_gcroot_constant = re.compile(r";\tmov\t.+, .+_constant_always_one_")
def check_computegcmaptable(format, path):
if format == 'msvc':
r_globallabel = re.compile(r"([\w]+)::")
elif format == 'darwin' or format == 'darwin64':
py.test.skip("disabled on OS/X's terribly old gcc")
else:
r_globallabel = re.compile(r"([\w.]+)=[.]+")
print
print path.dirpath().basename + '/' + path.basename
lines = path.readlines()
expectedlines = lines[:]
tracker = PARSERS[format].FunctionGcRootTracker(lines)
table = tracker.computegcmaptable(verbose=sys.maxint)
tabledict = {}
seen = {}
for entry in table:
print '%s: %s' % (entry[0], tracker.format_callshape(entry[1]))
tabledict[entry[0]] = entry[1]
# find the ";; expected" lines
prevline = ""
for i, line in enumerate(lines):
match = r_expected.match(line)
if match:
expected = match.group(1)
prevmatch = r_globallabel.match(prevline)
assert prevmatch, "the computed table is not complete"
label = prevmatch.group(1)
assert label in tabledict
got = tabledict[label]
assert tracker.format_callshape(got) == expected
seen[label] = True
if format == 'msvc':
expectedlines.insert(i-2, 'PUBLIC\t%s\n' % (label,))
expectedlines.insert(i-1, '%s::\n' % (label,))
else:
expectedlines.insert(i-3, '\t.globl\t%s\n' % (label,))
expectedlines.insert(i-2, '\t.hidden\t%s\n' % (label,))
expectedlines.insert(i-1, '%s=.+%d\n' % (label,
tracker.OFFSET_LABELS))
if format == 'msvc' and r_gcroot_constant.match(line):
expectedlines[i] = ';' + expectedlines[i]
expectedlines[i+1] = (expectedlines[i+1]
.replace('\timul\t', '\tmov\t')
+ '\t; GCROOT\n')
prevline = line
assert len(seen) == len(tabledict), (
"computed table contains unexpected entries:\n%r" %
[key for key in tabledict if key not in seen])
print '--------------- got ---------------'
print ''.join(lines)
print '------------- expected ------------'
print ''.join(expectedlines)
print '-----------------------------------'
assert lines == expectedlines
|