Subversion Repositories freemyipod

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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