|
|
|
@@ -1,6 +1,6 @@ |
|
|
|
#!/usr/bin/env python |
|
|
|
# |
|
|
|
# Copyright 2014 John-Mark Gurney. |
|
|
|
# Copyright 2014, 2026 John-Mark Gurney. |
|
|
|
# All rights reserved. |
|
|
|
# |
|
|
|
# Redistribution and use in source and binary forms, with or without |
|
|
|
@@ -24,12 +24,11 @@ |
|
|
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
|
|
# SUCH DAMAGE. |
|
|
|
# |
|
|
|
# |
|
|
|
# $Id$ |
|
|
|
# |
|
|
|
|
|
|
|
import enum |
|
|
|
import struct |
|
|
|
import weakref |
|
|
|
import unittest |
|
|
|
|
|
|
|
from ctypes import CDLL, Structure, POINTER, pointer, create_string_buffer, sizeof, CFUNCTYPE |
|
|
|
from ctypes import c_int, c_uint, c_char_p, c_long, c_ulong, c_size_t, c_ssize_t, c_void_p |
|
|
|
@@ -37,12 +36,11 @@ from ctypes import c_int, c_uint, c_char_p, c_long, c_ulong, c_size_t, c_ssize_t |
|
|
|
__all__ = [ 'CTF' ] |
|
|
|
|
|
|
|
_ctflib = CDLL('libctf.so.2') |
|
|
|
#_ctflib = CDLL('/usr/obj/arm.armeb/usr/src.avila/tmp/usr/src.avila/cddl/lib/libctf/libctf.so.2') |
|
|
|
|
|
|
|
class CTFError(Exception): |
|
|
|
pass |
|
|
|
|
|
|
|
class HexInt(long): |
|
|
|
class HexInt(int): |
|
|
|
def __str__(self): |
|
|
|
return '%#x' % self |
|
|
|
|
|
|
|
@@ -52,7 +50,8 @@ models = { |
|
|
|
'CTF_MODEL_ILP32': 1, |
|
|
|
'CTF_MODEL_LP64': 2, |
|
|
|
} |
|
|
|
models.update((v, k) for k, v in models.items()) |
|
|
|
globals().update(models) |
|
|
|
models.update((v, k) for k, v in tuple(models.items())) |
|
|
|
|
|
|
|
# From: sys/ctf.h |
|
|
|
kinds = { |
|
|
|
@@ -71,7 +70,8 @@ kinds = { |
|
|
|
'CTF_K_CONST': 12, |
|
|
|
'CTF_K_RESTRICT': 13, |
|
|
|
} |
|
|
|
kinds.update((v, k) for k, v in kinds.items()) |
|
|
|
globals().update(kinds) |
|
|
|
kinds.update((v, k) for k, v in tuple(kinds.items())) |
|
|
|
|
|
|
|
intenc = { |
|
|
|
'CTF_INT_SIGNED': 0x01, |
|
|
|
@@ -79,7 +79,8 @@ intenc = { |
|
|
|
'CTF_INT_BOOL': 0x04, |
|
|
|
'CTF_INT_VARARGS': 0x08, |
|
|
|
} |
|
|
|
intenc.update((v, k) for k, v in intenc.items()) |
|
|
|
globals().update(intenc) |
|
|
|
intenc.update((v, k) for k, v in tuple(intenc.items())) |
|
|
|
|
|
|
|
def lookupid(v, d): |
|
|
|
tv = d[v] |
|
|
|
@@ -165,13 +166,13 @@ class CTFID: |
|
|
|
} |
|
|
|
|
|
|
|
def __call__(self, s, endian='@'): |
|
|
|
size = self.getsize() |
|
|
|
size = self.tsize |
|
|
|
|
|
|
|
if len(s) < size: |
|
|
|
raise ValueError('not enough bytes, needed %d', size) |
|
|
|
|
|
|
|
base = self.resolve() |
|
|
|
kind = base.getkind() |
|
|
|
kind = base.kind |
|
|
|
|
|
|
|
src, rem = s[:size], s[size:] |
|
|
|
|
|
|
|
@@ -205,16 +206,16 @@ class CTFID: |
|
|
|
|
|
|
|
self.memberiter(addmember) |
|
|
|
|
|
|
|
#print `kind` |
|
|
|
#print `members` |
|
|
|
#print repr(kind) |
|
|
|
#print repr(members) |
|
|
|
val = {} |
|
|
|
for name, _type, off in members: |
|
|
|
if off % 8 != 0: |
|
|
|
raise NotImplementedError('bytes only for now') |
|
|
|
off /= 8 |
|
|
|
#print 'h:', `src`, `off`, `_type.getsize()` |
|
|
|
val[name], trem = _type(src[off:off + _type.getsize()], endian) |
|
|
|
assert not trem, 'trem left? %s' % `trem` |
|
|
|
#print 'h:', repr(src), repr(off), repr(_type.size) |
|
|
|
val[name], trem = _type(src[off:off + _type.size], endian) |
|
|
|
assert not trem, 'trem left? %s' % repr(trem) |
|
|
|
elif kind == 'CTF_K_UNION': |
|
|
|
raise NotImplementedError(kind) |
|
|
|
else: |
|
|
|
@@ -237,13 +238,16 @@ class CTFID: |
|
|
|
rbuf = _ctflib.ctf_type_name(self._ctf, self._id, buf, sizeof(buf)) |
|
|
|
return rbuf |
|
|
|
|
|
|
|
def getalign(self): |
|
|
|
@property |
|
|
|
def align(self): |
|
|
|
return _ctflib.ctf_type_align(self._ctf, self._id) |
|
|
|
|
|
|
|
def getsize(self): |
|
|
|
@property |
|
|
|
def size(self): |
|
|
|
return _ctflib.ctf_type_size(self._ctf, self._id) |
|
|
|
|
|
|
|
def getkind(self): |
|
|
|
@property |
|
|
|
def kind(self): |
|
|
|
return lookupstr(_ctflib.ctf_type_kind(self._ctf, self._id), |
|
|
|
kinds) |
|
|
|
|
|
|
|
@@ -258,18 +262,19 @@ class CTFID: |
|
|
|
def __repr__(self): |
|
|
|
i = map(lambda x: ': '.join(x), [ |
|
|
|
('name', str(self.getname())), |
|
|
|
('size', str(self.getsize())), |
|
|
|
('kind', self.getkind()), |
|
|
|
('align', str(self.getalign())), |
|
|
|
('size', str(self.size)), |
|
|
|
('kind', self.kind), |
|
|
|
('align', str(self.align)), |
|
|
|
]) |
|
|
|
return '<CTFID: %s>' % ', '.join(i) |
|
|
|
|
|
|
|
class CTF: |
|
|
|
def __init__(self, f, model=None): |
|
|
|
i = c_int() |
|
|
|
f = f.encode('utf-8') |
|
|
|
self._ctf = _ctflib.ctf_open(f, pointer(i)) |
|
|
|
if not bool(self._ctf): |
|
|
|
raise ValueError('%s: %s' % (`f`, |
|
|
|
raise ValueError('%s: %s' % (repr(f), |
|
|
|
_ctflib.ctf_errmsg(i))) |
|
|
|
|
|
|
|
self._ids = weakref.WeakValueDictionary() |
|
|
|
@@ -305,13 +310,16 @@ class CTF: |
|
|
|
|
|
|
|
def __getitem__(self, k): |
|
|
|
if isinstance(k, str): |
|
|
|
k = k.encode('utf-8') |
|
|
|
|
|
|
|
if isinstance(k, bytes): |
|
|
|
id = _ctflib.ctf_lookup_by_name(self._ctf, k) |
|
|
|
else: |
|
|
|
id = _ctflib.ctf_lookup_by_symbol(self._ctf, k) |
|
|
|
|
|
|
|
if id == -1: |
|
|
|
raise KeyError('unknown name: %s' % `k`) |
|
|
|
#print 'getitem:', `id` |
|
|
|
raise KeyError('unknown name: %s' % repr(k)) |
|
|
|
#print 'getitem:', repr(id) |
|
|
|
return self._getid(id) |
|
|
|
|
|
|
|
def _getid(self, id): |
|
|
|
@@ -331,7 +339,7 @@ class CTF: |
|
|
|
|
|
|
|
def dump(name, _type, off): |
|
|
|
_type = _type.resolve() |
|
|
|
print 'd:', `name, _type, off` |
|
|
|
print('d:', repr(name, _type, off)) |
|
|
|
return 0 |
|
|
|
|
|
|
|
def parseddbw(s): |
|
|
|
@@ -358,14 +366,14 @@ if __name__ == '__main__': |
|
|
|
vm = ctf['vm_page_t'] |
|
|
|
vmr = vm.resolve() |
|
|
|
vmrr = vmr.reference() |
|
|
|
print 'int:', `i` |
|
|
|
print 'vm_page_t:', `vm` |
|
|
|
print 'vm_page_t res:', `vmr` |
|
|
|
print 'vm_page_t resolve:', `vmrr` |
|
|
|
print('int:', repr(i)) |
|
|
|
print('vm_page_t:', repr(vm)) |
|
|
|
print('vm_page_t res:', repr(vmr)) |
|
|
|
print('vm_page_t resolve:', repr(vmrr)) |
|
|
|
#vmrr.memberiter(dump) |
|
|
|
|
|
|
|
print 'sizeof(struct vm_page):', ctf['struct vm_page'].getsize() |
|
|
|
#print `vmrr('\x11' * vmrr.getsize())` |
|
|
|
print('sizeof(struct vm_page):', ctf['struct vm_page'].size) |
|
|
|
#print(repr(vmrr('\x11' * vmrr.size))) |
|
|
|
r = parseddb('''0xc0805db0: 0 0 0 0 c0 6d 1f 64 c0 80 5e 0 c0 6d 18 a0 |
|
|
|
0xc0805dc0: c0 6d 18 78 0 0 0 0 0 0 0 0 0 0 d f4 |
|
|
|
0xc0805dd0: 1 f 40 0 0 0 0 0 0 0 0 0 c0 df 40 0 |
|
|
|
@@ -385,7 +393,7 @@ if __name__ == '__main__': |
|
|
|
0xc07e73e0: 0 c07e73e0 1 1 |
|
|
|
0xc07e73f0: 0 4ff02 90000ff ff000000 |
|
|
|
0xc07e7400: 0 c06e6a58 c07e7450 c07e73b8''') |
|
|
|
print len(r), `r` |
|
|
|
print(len(r), repr(r)) |
|
|
|
import pprint |
|
|
|
s, r = vmrr(r, '>') |
|
|
|
pprint.pprint(s) |
|
|
|
@@ -393,8 +401,26 @@ if __name__ == '__main__': |
|
|
|
pprint.pprint(s) |
|
|
|
|
|
|
|
vm = ctf['vm_object_t'].resolve() |
|
|
|
print `vm` |
|
|
|
print 'sizeof(struct md_page):', ctf['struct md_page'].getsize() |
|
|
|
print 'sizeof(vm_object_t):', ctf['vm_object_t'].getsize() |
|
|
|
print 'sizeof(vm_pindex_t):', ctf['vm_pindex_t'].getsize() |
|
|
|
print 'sizeof(vm_paddr_t):', ctf['vm_paddr_t'].getsize() |
|
|
|
print(repr(vm)) |
|
|
|
print('sizeof(struct md_page):', ctf['struct md_page'].size) |
|
|
|
print('sizeof(vm_object_t):', ctf['vm_object_t'].size) |
|
|
|
print('sizeof(vm_pindex_t):', ctf['vm_pindex_t'].size) |
|
|
|
print('sizeof(vm_paddr_t):', ctf['vm_paddr_t'].size) |
|
|
|
|
|
|
|
class CTCTests(unittest.TestCase): |
|
|
|
def test_basic(self): |
|
|
|
ctf = CTF('/boot/kernel/kernel') |
|
|
|
|
|
|
|
i = ctf['int'] |
|
|
|
|
|
|
|
self.assertEqual(i.size, 4) |
|
|
|
self.assertEqual(i.kind, 'CTF_K_INTEGER') |
|
|
|
|
|
|
|
vm = ctf['vm_page_t'] |
|
|
|
self.assertEqual(vm.kind, 'CTF_K_TYPEDEF') |
|
|
|
|
|
|
|
vmr = vm.resolve() |
|
|
|
self.assertEqual(vmr.kind, 'CTF_K_POINTER') |
|
|
|
|
|
|
|
vmrr = vmr.reference() |
|
|
|
self.assertEqual(vmrr.kind, 'CTF_K_STRUCT') |