From cbedeb35940379cece5c37df1b24442a552b6522 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Mon, 12 Oct 2026 18:02:17 -0700 Subject: [PATCH] update to python 3, clean things up... It'd be best to generate sample ctf data and use that for the tests, but that involves making this into a real project.. not yet --- ctf.py | 102 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 38 deletions(-) diff --git a/ctf.py b/ctf.py index 54e4f04..3dc690a 100644 --- a/ctf.py +++ b/ctf.py @@ -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 '' % ', '.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')