Browse Source

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
main
John-Mark Gurney 1 month ago
parent
commit
cbedeb3594
1 changed files with 64 additions and 38 deletions
  1. +64
    -38
      ctf.py

+ 64
- 38
ctf.py View File

@@ -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')

Loading…
Cancel
Save