freemyipod r811 - Code Review

Jump to: navigation, search
Repository:freemyipod
Revision:r810‎ | r811 | r812 >
Date:20:33, 22 November 2011
Author:theseven
Status:new
Tags:
Comment:
New tool: TLSFanalyze
Modified paths:
  • /emcore/trunk/tools/misc.py (modified) (history)
  • /emcore/trunk/tools/tlsfanalyze.py (added) (history)

Diff [purge]

Index: emcore/trunk/tools/misc.py
@@ -235,7 +235,6 @@
236236 else:
237237 return self.value != other
238238
239 -
240239 class ExtendedCStruct(LittleEndianStructure):
241240 """
242241 This is a subclass of the LittleEndianStructure.
@@ -242,6 +241,19 @@
243242 It implements functions to easily convert
244243 structures to/from strings and Bunches.
245244 """
 245+ def __init__(self, data = None, base = 0, address = 0):
 246+ LittleEndianStructure.__init__(self)
 247+ if data != None:
 248+ self._data_ = data
 249+ self._base_ = base
 250+ self._address_ = address
 251+ if address < base or address + sizeof(self) > base + len(data):
 252+ raise Exception("Range 0x%08X+0x%X out of bounds [0x%08X:0x%08X]" % (address, sizeof(self), base, base + len(data)))
 253+ memmove(addressof(self), data[address - base : address - base + sizeof(self)], sizeof(self))
 254+
 255+ def __int__(self):
 256+ return self._address_
 257+
246258 def _from_bunch(self, bunch):
247259 for field, _ in self._fields_:
248260 if field in bunch:
Index: emcore/trunk/tools/tlsfanalyze.py
@@ -0,0 +1,227 @@
 2+#!/usr/bin/env python
 3+#
 4+#
 5+# Copyright 2011 TheSeven
 6+#
 7+#
 8+# This file is part of emCORE.
 9+#
 10+# emCORE is free software: you can redistribute it and/or
 11+# modify it under the terms of the GNU General Public License as
 12+# published by the Free Software Foundation, either version 2 of the
 13+# License, or (at your option) any later version.
 14+#
 15+# emCORE is distributed in the hope that it will be useful,
 16+# but WITHOUT ANY WARRANTY; without even the implied warranty of
 17+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 18+# See the GNU General Public License for more details.
 19+#
 20+# You should have received a copy of the GNU General Public License
 21+# along with emCORE. If not, see <http://www.gnu.org/licenses/>.
 22+#
 23+#
 24+
 25+
 26+import sys
 27+import struct
 28+from misc import ExtendedCStruct
 29+from ctypes import *
 30+
 31+
 32+def usage():
 33+ print("Usage: %s <image> [image_base] [tlsf_pool] [SL_INDEX_COUNT_LOG2] [FL_INDEX_MAX]" % (sys.argv[0]))
 34+ exit(2)
 35+
 36+
 37+image_base = 0x08000000
 38+tlsf_pool = 0x08000000
 39+SL_INDEX_COUNT_LOG2 = 5
 40+FL_INDEX_MAX = 30
 41+
 42+if len(sys.argv) < 2: usage()
 43+filename = sys.argv[1]
 44+if len(sys.argv) > 2: image_base = int(sys.argv[2])
 45+if len(sys.argv) > 3: tlsf_pool = int(sys.argv[3])
 46+if len(sys.argv) > 4: SL_INDEX_COUNT_LOG2 = int(sys.argv[4])
 47+if len(sys.argv) > 5: FL_INDEX_MAX = int(sys.argv[5])
 48+if len(sys.argv) > 6: usage()
 49+
 50+file = open(filename, "rb")
 51+data = file.read()
 52+file.close()
 53+
 54+SL_INDEX_COUNT = 1 << SL_INDEX_COUNT_LOG2
 55+FL_INDEX_SHIFT = SL_INDEX_COUNT_LOG2 + 2
 56+FL_INDEX_COUNT = FL_INDEX_MAX - FL_INDEX_SHIFT + 1
 57+SMALL_BLOCK_SIZE = 1 << FL_INDEX_SHIFT
 58+
 59+
 60+class block_header_t(ExtendedCStruct):
 61+ _fields_ = [("prev_phys_block", c_uint32),
 62+ ("size", c_uint32),
 63+ ("next_free", c_uint32),
 64+ ("prev_free", c_uint32)]
 65+
 66+ def is_last(self):
 67+ return self.get_size() == 0;
 68+
 69+ def is_null(self):
 70+ return self._address_ == self.next_free and self.size == 0 and self.prev_phys_block == 0
 71+
 72+ def is_free(self):
 73+ return (self.size & block_header_free_bit) != 0;
 74+
 75+ def is_prev_free(self):
 76+ return (self.size & block_header_prev_free_bit) != 0;
 77+
 78+ def get_address(self):
 79+ return self._address_
 80+
 81+ def get_size(self):
 82+ return self.size & 0xfffffffc
 83+
 84+ def get_prev_free(self):
 85+ if not self.is_free(): raise Exception("Trying to get previous free block of non-free block")
 86+ return block_header_t(self._data_, self._base_, self.prev_free)
 87+
 88+ def get_next_free(self):
 89+ if not self.is_free(): raise Exception("Trying to get next free block of non-free block")
 90+ return block_header_t(self._data_, self._base_, self.next_free)
 91+
 92+ def get_prev_phys(self):
 93+ if not self.is_prev_free(): raise Exception("Trying to get non-free previous physical block")
 94+ return block_header_t(self._data_, self._base_, self.prev_phys_block)
 95+
 96+ def get_next_phys(self):
 97+ return self.get_next_by_offset(self.get_size() + 4)
 98+
 99+ def get_next_by_offset(self, offset):
 100+ return block_header_t(self._data_, self._base_, self._address_ + offset)
 101+
 102+
 103+class pool_t(ExtendedCStruct):
 104+ _fields_ = [("fl_bitmap", c_uint32),
 105+ ("sl_bitmap", c_uint32 * FL_INDEX_COUNT),
 106+ ("blocks", c_uint32 * SL_INDEX_COUNT * FL_INDEX_COUNT)]
 107+
 108+
 109+block_header_free_bit = 1
 110+block_header_prev_free_bit = 2
 111+block_size_min = sizeof(block_header_t) - 4;
 112+block_size_max = 1 << FL_INDEX_MAX
 113+
 114+pool = pool_t(data, image_base, tlsf_pool)
 115+block = block_header_t(data, image_base, tlsf_pool + sizeof(pool_t) - 4)
 116+prev_free = False
 117+prev_addr = 0
 118+blocks = []
 119+free_blocks = []
 120+bytes_used = 0
 121+bytes_free = 0
 122+
 123+while True:
 124+ if block.is_prev_free() != prev_free:
 125+ print("Block %08X previous free indicator is %d, expected %d" % (block.get_address(), block.is_prev_free(), prev_free))
 126+ if prev_free and prev_addr != block.prev_phys_block:
 127+ print("Block %08X previous physical block address is wrong. Got %08X, should be %08X" % (block.get_address(), block.prev_phys_block, prev_addr))
 128+ prev_free = block.is_free()
 129+ prev_addr = block.get_address()
 130+ if block.is_last(): break
 131+ if blocks.count(prev_addr) > 0:
 132+ print("Block loop detected at %08X" % (prev_addr))
 133+ break
 134+ blocks.append(prev_addr)
 135+ if prev_free:
 136+ print("%08X: %08X bytes free" % (prev_addr + 4, block.get_size() + 4))
 137+ free_blocks.append(prev_addr)
 138+ bytes_free = bytes_free + block.get_size() + 4
 139+ else:
 140+ owner_address = prev_addr - image_base + block.get_size() - 4
 141+ owner = struct.unpack("<I", data[owner_address : owner_address + 4])[0]
 142+ print("%08X: %08X+8 bytes owned by %08X" % (prev_addr + 8, block.get_size() - 4, owner))
 143+ bytes_used = bytes_used + block.get_size() + 4
 144+ try: block = block.get_next_phys()
 145+ except:
 146+ print("Block %08X has invalid size: %08X" % (prev_addr, block.get_size()))
 147+ print("Fatal error in block chain, continuing with map check")
 148+ break
 149+
 150+handled_blocks = []
 151+for i in range(FL_INDEX_COUNT):
 152+ fl_map = (pool.fl_bitmap >> i) & 1
 153+ sl_list = pool.sl_bitmap[i]
 154+ if fl_map == 0:
 155+ if sl_list != 0:
 156+ print("[%d:%d] Second-level map must be null, but isn't" % (i, j))
 157+ elif sl_list == 0:
 158+ print("[%d:%d] No free blocks in second-level map, but first-level map indicates there are some" % (i, j))
 159+ for j in range(SL_INDEX_COUNT):
 160+ sl_map = (sl_list >> j) & 1
 161+ ba = pool.blocks[i][j]
 162+ block = block_header_t(data, image_base, ba)
 163+ if sl_map == 0:
 164+ if not block.is_null():
 165+ print("[%d:%d:%08X] Block list must be null, but isn't" % (i, j, ba))
 166+ continue
 167+ elif block.is_null():
 168+ print("[%d:%d:%08X] Block list is null, but second-level map indicates there are free blocks" % (i, j, ba))
 169+ blocks = []
 170+ while not block.is_null():
 171+ fatal = False
 172+ addr = block.get_address()
 173+ if blocks.count(addr) > 0:
 174+ print("[%d:%d:%08X] Detected block loop" % (i, j, addr))
 175+ break
 176+ blocks.append(addr)
 177+ if not block.is_free():
 178+ print("[%d:%d:%08X] Non-free block on free list" % (i, j, addr))
 179+ fatal = True
 180+ if block.is_prev_free():
 181+ print("[%d:%d:%08X] Block should have coalesced with previous one" % (i, j, addr))
 182+ try:
 183+ if block.get_next_phys().is_free():
 184+ print("[%d:%d:%08X] Block should have coalesced with next one" % (i, j, addr))
 185+ except:
 186+ print("Block %08X has invalid size: %08X" % (addr, block.get_size()))
 187+ fatal = True
 188+ size = block.get_size()
 189+ if size < block_size_min:
 190+ print("[%d:%d:%08X] Block violates minimum size: %d (should be at least %d)" % (i, j, addr, size, block_size_min))
 191+ if size > block_size_max:
 192+ print("[%d:%d:%08X] Block violates maximum size: %d (should be at most %d)" % (i, j, addr, size, block_size_max))
 193+ if size < SMALL_BLOCK_SIZE:
 194+ fl = 0
 195+ sl = size / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT)
 196+ else:
 197+ fl = 32 - FL_INDEX_SHIFT;
 198+ if (size & 0xffff0000) == 0:
 199+ size = size << 16
 200+ fl = fl - 16
 201+ if (size & 0xff000000) == 0:
 202+ size = size << 8
 203+ fl = fl - 8
 204+ if (size & 0xf0000000) == 0:
 205+ size = size << 4
 206+ fl = fl - 4
 207+ if (size & 0xc0000000) == 0:
 208+ size = size << 2
 209+ fl = fl - 2
 210+ if (size & 0x80000000) == 0:
 211+ size = size << 1
 212+ fl = fl - 1
 213+ sl = (block.get_size() >> (fl - SL_INDEX_COUNT_LOG2 + FL_INDEX_SHIFT - 1)) ^ (1 << SL_INDEX_COUNT_LOG2)
 214+ if fl != i or sl != j:
 215+ print("Block %08X is in wrong free list: [%d:%d] (should be [%d:%d])" % (addr, i, j, fl, sl))
 216+ if free_blocks.count(addr) != 1:
 217+ print("[%d:%d:%08X] Block is in free list, but was not found in pool" % (i, j, addr))
 218+ if handled_blocks.count(addr) > 0:
 219+ print("[%d:%d:%08X] Block appears in multiple free lists" % (i, j, addr))
 220+ else: handled_blocks.append(addr)
 221+ if fatal:
 222+ print("Fatal error in block chain, continuing with next chain")
 223+ break
 224+ block = block.get_next_free()
 225+
 226+for addr in free_blocks:
 227+ if handled_blocks.count(addr) != 1:
 228+ print("Free block %08X does not appear in any free list" % (addr))