Set of scripts used for various projects.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

401 lines
11 KiB

  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2014 John-Mark Gurney.
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. # 1. Redistributions of source code must retain the above copyright
  10. # notice, this list of conditions and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. # notice, this list of conditions and the following disclaimer in the
  13. # documentation and/or other materials provided with the distribution.
  14. #
  15. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16. # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  19. # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. # SUCH DAMAGE.
  26. #
  27. #
  28. # $Id$
  29. #
  30. import struct
  31. import weakref
  32. from ctypes import CDLL, Structure, POINTER, pointer, create_string_buffer, sizeof, CFUNCTYPE
  33. from ctypes import c_int, c_uint, c_char_p, c_long, c_ulong, c_size_t, c_ssize_t, c_void_p
  34. __all__ = [ 'CTF' ]
  35. _ctflib = CDLL('libctf.so.2')
  36. #_ctflib = CDLL('/usr/obj/arm.armeb/usr/src.avila/tmp/usr/src.avila/cddl/lib/libctf/libctf.so.2')
  37. class CTFError(Exception):
  38. pass
  39. class HexInt(long):
  40. def __str__(self):
  41. return '%#x' % self
  42. __repr__ = __str__
  43. models = {
  44. 'CTF_MODEL_ILP32': 1,
  45. 'CTF_MODEL_LP64': 2,
  46. }
  47. models.update((v, k) for k, v in models.items())
  48. # From: sys/ctf.h
  49. kinds = {
  50. 'CTF_K_UNKNOWN': 0,
  51. 'CTF_K_INTEGER': 1,
  52. 'CTF_K_FLOAT': 2,
  53. 'CTF_K_POINTER': 3,
  54. 'CTF_K_ARRAY': 4,
  55. 'CTF_K_FUNCTION': 5,
  56. 'CTF_K_STRUCT': 6,
  57. 'CTF_K_UNION': 7,
  58. 'CTF_K_ENUM': 8,
  59. 'CTF_K_FORWARD': 9,
  60. 'CTF_K_TYPEDEF': 10,
  61. 'CTF_K_VOLATILE': 11,
  62. 'CTF_K_CONST': 12,
  63. 'CTF_K_RESTRICT': 13,
  64. }
  65. kinds.update((v, k) for k, v in kinds.items())
  66. intenc = {
  67. 'CTF_INT_SIGNED': 0x01,
  68. 'CTF_INT_CHAR': 0x02,
  69. 'CTF_INT_BOOL': 0x04,
  70. 'CTF_INT_VARARGS': 0x08,
  71. }
  72. intenc.update((v, k) for k, v in intenc.items())
  73. def lookupid(v, d):
  74. tv = d[v]
  75. try:
  76. return int(v)
  77. except ValueError:
  78. return tv
  79. def lookupstr(v, d):
  80. tv = d[v]
  81. if isinstance(tv, str):
  82. return tv
  83. else:
  84. return d[tv]
  85. class ctf_visit_f(Structure):
  86. pass
  87. class ctf_encoding_t(Structure):
  88. _fields_ = [ ('cte_format', c_uint),
  89. ('cte_offset', c_uint),
  90. ('cte_bits', c_uint),
  91. ]
  92. ctf_id_t = c_long
  93. # If c_int != 0, return immediately
  94. ctf_member_f = CFUNCTYPE(c_int, c_char_p, ctf_id_t, c_ulong, c_void_p)
  95. class ctf_file_t(Structure):
  96. pass
  97. ctf_file_t_p = POINTER(ctf_file_t)
  98. for r, f, a in (
  99. (ctf_file_t_p, 'ctf_open', (c_char_p, POINTER(c_int), )),
  100. (None, 'ctf_close', (ctf_file_t_p, )),
  101. (c_int, 'ctf_update', (ctf_file_t_p, )),
  102. (c_int, 'ctf_discard', (ctf_file_t_p, )),
  103. (c_int, 'ctf_write', (ctf_file_t_p, c_int, )),
  104. (ctf_file_t_p, 'ctf_parent_file', (ctf_file_t_p, )),
  105. (c_char_p, 'ctf_parent_name', (ctf_file_t_p, )),
  106. (c_int, 'ctf_setmodel', (ctf_file_t_p, c_int, )),
  107. (c_int, 'ctf_getmodel', (ctf_file_t_p, )),
  108. (c_int, 'ctf_errno', (ctf_file_t_p, )),
  109. (c_char_p, 'ctf_errmsg', (c_int, )),
  110. (c_int, 'ctf_version', (c_int, )),
  111. (ctf_id_t, 'ctf_lookup_by_name', (ctf_file_t_p, c_char_p, )),
  112. (ctf_id_t, 'ctf_lookup_by_symbol', (ctf_file_t_p, c_ulong, )),
  113. (ctf_id_t, 'ctf_type_resolve', (ctf_file_t_p, ctf_id_t, )),
  114. (c_ssize_t, 'ctf_type_lname', (ctf_file_t_p, ctf_id_t, c_char_p, c_size_t, )),
  115. (c_char_p, 'ctf_type_name', (ctf_file_t_p, ctf_id_t, c_char_p, c_size_t, )),
  116. (c_ssize_t, 'ctf_type_size', (ctf_file_t_p, ctf_id_t, )),
  117. (c_ssize_t, 'ctf_type_align', (ctf_file_t_p, ctf_id_t, )),
  118. (int, 'ctf_type_kind', (ctf_file_t_p, ctf_id_t, )),
  119. (ctf_id_t, 'ctf_type_reference', (ctf_file_t_p, ctf_id_t, )),
  120. (ctf_id_t, 'ctf_type_pointer', (ctf_file_t_p, ctf_id_t, )),
  121. (int, 'ctf_type_encoding', (ctf_file_t_p, ctf_id_t, POINTER(ctf_encoding_t), )),
  122. (int, 'ctf_type_visit', (ctf_file_t_p, ctf_id_t, POINTER(ctf_visit_f), c_void_p, )),
  123. (int, 'ctf_type_cmp', (ctf_file_t_p, ctf_id_t, ctf_file_t_p, ctf_id_t, )),
  124. (int, 'ctf_type_compat', (ctf_file_t_p, ctf_id_t, ctf_file_t_p, ctf_id_t, )),
  125. ):
  126. fun = getattr(_ctflib, f)
  127. setattr(fun, 'restype', r)
  128. setattr(fun, 'argtypes', a)
  129. class CTFID:
  130. def __init__(self, _ctfobj, id):
  131. self._ctfobj = _ctfobj
  132. self._ctf = _ctfobj._ctf
  133. self._id = id
  134. __int_sizes = {
  135. 1: 'B',
  136. 2: 'H',
  137. 4: 'I',
  138. 8: 'Q',
  139. }
  140. def __call__(self, s, endian='@'):
  141. size = self.getsize()
  142. if len(s) < size:
  143. raise ValueError('not enough bytes, needed %d', size)
  144. base = self.resolve()
  145. kind = base.getkind()
  146. src, rem = s[:size], s[size:]
  147. conv = endian
  148. if kind == 'CTF_K_INTEGER':
  149. enc = base.getencoding()
  150. if enc.cte_format & intenc['CTF_INT_CHAR']:
  151. assert size == 1
  152. val = src
  153. else:
  154. convfun = lambda x: x
  155. if enc.cte_format & intenc['CTF_INT_SIGNED']:
  156. convfun = lambda x: x.lower()
  157. if enc.cte_format & intenc['CTF_INT_BOOL']:
  158. convchar = '?'
  159. else:
  160. convchar = self.__int_sizes[size]
  161. conv += convfun(convchar)
  162. val = struct.unpack(conv, src)[0]
  163. elif kind == 'CTF_K_POINTER':
  164. val = HexInt(struct.unpack(endian + self.__int_sizes[size], src)[0])
  165. elif kind == 'CTF_K_ENUM':
  166. raise NotImplementedError(kind)
  167. elif kind in ('CTF_K_STRUCT', 'CTF_K_UNION'):
  168. members = []
  169. def addmember(*args):
  170. members.append(args)
  171. return 0
  172. self.memberiter(addmember)
  173. #print `kind`
  174. #print `members`
  175. val = {}
  176. for name, _type, off in members:
  177. if off % 8 != 0:
  178. raise NotImplementedError('bytes only for now')
  179. off /= 8
  180. #print 'h:', `src`, `off`, `_type.getsize()`
  181. val[name], trem = _type(src[off:off + _type.getsize()], endian)
  182. assert not trem, 'trem left? %s' % `trem`
  183. elif kind == 'CTF_K_UNION':
  184. raise NotImplementedError(kind)
  185. else:
  186. raise NotImplementedError(kind)
  187. return val, rem
  188. def memberiter(self, fun):
  189. iterfun = self._ctfobj.makeiterfun(fun)
  190. _ctflib.ctf_member_iter(self._ctf, self._id, iterfun, None)
  191. def resolve(self):
  192. return self._ctfobj.resolve(self._id)
  193. def reference(self):
  194. return self._ctfobj.reference(self._id)
  195. def getname(self):
  196. buf = create_string_buffer(64)
  197. rbuf = _ctflib.ctf_type_name(self._ctf, self._id, buf, sizeof(buf))
  198. return rbuf
  199. def getalign(self):
  200. return _ctflib.ctf_type_align(self._ctf, self._id)
  201. def getsize(self):
  202. return _ctflib.ctf_type_size(self._ctf, self._id)
  203. def getkind(self):
  204. return lookupstr(_ctflib.ctf_type_kind(self._ctf, self._id),
  205. kinds)
  206. def getencoding(self):
  207. enc = ctf_encoding_t()
  208. r = _ctflib.ctf_type_encoding(self._ctf, self._id, pointer(enc))
  209. if r != 0:
  210. raise self._ctfobj.geterror()
  211. return enc
  212. def __repr__(self):
  213. i = map(lambda x: ': '.join(x), [
  214. ('name', str(self.getname())),
  215. ('size', str(self.getsize())),
  216. ('kind', self.getkind()),
  217. ('align', str(self.getalign())),
  218. ])
  219. return '<CTFID: %s>' % ', '.join(i)
  220. class CTF:
  221. def __init__(self, f, model=None):
  222. i = c_int()
  223. self._ctf = _ctflib.ctf_open(f, pointer(i))
  224. if not bool(self._ctf):
  225. raise ValueError('%s: %s' % (`f`,
  226. _ctflib.ctf_errmsg(i)))
  227. self._ids = weakref.WeakValueDictionary()
  228. if model is not None:
  229. _ctflib.ctf_setmodel(self._ctf, lookupid(model, models))
  230. def makeiterfun(self, fun):
  231. def lfun(name, id, off, ptr):
  232. id = self._getid(id)
  233. return fun(name, id, off)
  234. return ctf_member_f(lfun)
  235. def resolve(self, id):
  236. if isinstance(id, CTFID):
  237. id = id._id
  238. nid = _ctflib.ctf_type_resolve(self._ctf, id)
  239. return self._getid(nid)
  240. def reference(self, id):
  241. if isinstance(id, CTFID):
  242. id = id._id
  243. nid = _ctflib.ctf_type_reference(self._ctf, id)
  244. return self._getid(nid)
  245. def geterror(self):
  246. err = _ctflib.ctf_errno(self._ctf)
  247. errmsg = _ctflib.ctf_errmsg(err)
  248. return CTFError((err, errmsg))
  249. def __getitem__(self, k):
  250. if isinstance(k, str):
  251. id = _ctflib.ctf_lookup_by_name(self._ctf, k)
  252. else:
  253. id = _ctflib.ctf_lookup_by_symbol(self._ctf, k)
  254. if id == -1:
  255. raise KeyError('unknown name: %s' % `k`)
  256. #print 'getitem:', `id`
  257. return self._getid(id)
  258. def _getid(self, id):
  259. try:
  260. return self._ids[id]
  261. except KeyError:
  262. obj = CTFID(self, id)
  263. self._ids[id] = obj
  264. return obj
  265. def __del__(self):
  266. try:
  267. _ctflib.ctf_close(self._ctf)
  268. except Exception:
  269. pass
  270. def dump(name, _type, off):
  271. _type = _type.resolve()
  272. print 'd:', `name, _type, off`
  273. return 0
  274. def parseddbw(s):
  275. listofchars = [ x.split(':', 1)[1].split() for x in s.split('\n') ]
  276. words = sum(listofchars, [])
  277. return struct.pack('>%dI' % len(words), *(int(x, 16) for x in words))
  278. def parseddb(s):
  279. listofchars = [ x.split(':', 1)[1].split() for x in s.split('\n') ]
  280. chars = sum(listofchars, [])
  281. #print chars
  282. l = ''.join(chr(int(x, 16)) for x in chars)
  283. return l
  284. if __name__ == '__main__':
  285. #ctf = CTF('/boot/kernel/kernel')
  286. ctf = CTF('/tmp/avila3.ctf', model='CTF_MODEL_ILP32')
  287. #ctf = CTF('/tftpboot/kernel.avila.avila')
  288. i = ctf['int']
  289. vm = ctf['vm_page_t']
  290. vmr = vm.resolve()
  291. vmrr = vmr.reference()
  292. print 'int:', `i`
  293. print 'vm_page_t:', `vm`
  294. print 'vm_page_t res:', `vmr`
  295. print 'vm_page_t resolve:', `vmrr`
  296. #vmrr.memberiter(dump)
  297. print 'sizeof(struct vm_page):', ctf['struct vm_page'].getsize()
  298. #print `vmrr('\x11' * vmrr.getsize())`
  299. r = parseddb('''0xc0805db0: 0 0 0 0 c0 6d 1f 64 c0 80 5e 0 c0 6d 18 a0
  300. 0xc0805dc0: c0 6d 18 78 0 0 0 0 0 0 0 0 0 0 d f4
  301. 0xc0805dd0: 1 f 40 0 0 0 0 0 0 0 0 0 c0 df 40 0
  302. 0xc0805de0: 0 0 0 0 c0 80 5d e0 0 0 0 1 0 0 0 1
  303. 0xc0805df0: 0 0 0 0 0 4 ff 1 9 0 0 ff ff 0 0 0
  304. 0xc0805e00: 0 0 0 0 c0 6d 1f 4c c0 80 5e 50 c0 80 5d b8
  305. 0xc0805e10: c0 6d 18 78 0 0 0 0 0 0 0 0 0 0 d f5
  306. 0xc0805e20: 1 f 50 0 0 0 0 0 0 0 0 0 c0 df 50 0''')
  307. r2 = parseddbw('''3229638064: 0 c06d1f64 c0805e00 c06d18a0
  308. 3229638080: c06d1878 0 0 df4
  309. 3229638096: 10f4000 0 0 c0df4000
  310. 3229638112: 0 c0805de0 1 1
  311. 3229638128: 0 4ff01 90000ff ff000000''')
  312. r2 = parseddbw('''0xc07e73b0: 0 c06e6a4c c07e7400 c06e63a0
  313. 0xc07e73c0: c06e6378 0 0 dfd
  314. 0xc07e73d0: 8fd000 0 0 c0dfd000
  315. 0xc07e73e0: 0 c07e73e0 1 1
  316. 0xc07e73f0: 0 4ff02 90000ff ff000000
  317. 0xc07e7400: 0 c06e6a58 c07e7450 c07e73b8''')
  318. print len(r), `r`
  319. import pprint
  320. s, r = vmrr(r, '>')
  321. pprint.pprint(s)
  322. s, r = vmrr(r2, '>')
  323. pprint.pprint(s)
  324. vm = ctf['vm_object_t'].resolve()
  325. print `vm`
  326. print 'sizeof(struct md_page):', ctf['struct md_page'].getsize()
  327. print 'sizeof(vm_object_t):', ctf['vm_object_t'].getsize()
  328. print 'sizeof(vm_pindex_t):', ctf['vm_pindex_t'].getsize()
  329. print 'sizeof(vm_paddr_t):', ctf['vm_paddr_t'].getsize()