| Line 22... |
Line 22... |
| 22 |
#
|
22 |
#
|
| 23 |
|
23 |
|
| 24 |
|
24 |
|
| 25 |
import sys
|
25 |
import sys
|
| 26 |
import struct
|
26 |
import struct
|
| 27 |
from misc import ExtendedCStruct
|
27 |
from misc import ExtendedCStruct, string_from_image
|
| - |
|
28 |
from libemcoredata import scheduler_thread
|
| 28 |
from ctypes import *
|
29 |
from ctypes import *
|
| 29 |
|
30 |
|
| 30 |
|
31 |
|
| 31 |
def usage():
|
32 |
def usage():
|
| 32 |
print("Usage: %s <image> [image_base] [tlsf_pool] [SL_INDEX_COUNT_LOG2] [FL_INDEX_MAX]" % (sys.argv[0]))
|
33 |
print("Usage: %s <image> [image_base] [tlsf_pool] [SL_INDEX_COUNT_LOG2] [FL_INDEX_MAX]" % (sys.argv[0]))
|
| Line 130... |
Line 131... |
| 130 |
if blocks.count(prev_addr) > 0:
|
131 |
if blocks.count(prev_addr) > 0:
|
| 131 |
print("Block loop detected at %08X" % (prev_addr))
|
132 |
print("Block loop detected at %08X" % (prev_addr))
|
| 132 |
break
|
133 |
break
|
| 133 |
blocks.append(prev_addr)
|
134 |
blocks.append(prev_addr)
|
| 134 |
if prev_free:
|
135 |
if prev_free:
|
| - |
|
136 |
try:
|
| - |
|
137 |
nfa = block.get_next_free().get_address()
|
| - |
|
138 |
if nfa >= prev_addr and nfa < prev_addr + block.get_size() + 4:
|
| - |
|
139 |
print("%08X: Next free block (%08X) lies within the block itself" % (prev_addr, nfa))
|
| - |
|
140 |
except: print("%08X: Invalid next free block pointer: %08X" % (prev_addr, block.next_free))
|
| - |
|
141 |
try:
|
| - |
|
142 |
pfa = block.get_prev_free().get_address()
|
| - |
|
143 |
if pfa >= prev_addr and pfa < prev_addr + block.get_size() + 4:
|
| - |
|
144 |
print("%08X: Previous free block (%08X) lies within the block itself" % (prev_addr, pfa))
|
| - |
|
145 |
except:
|
| - |
|
146 |
print("%08X: Invalid previous free block pointer: %08X" % (prev_addr, block.prev_free))
|
| 135 |
print("%08X: %08X bytes free" % (prev_addr + 4, block.get_size() + 4))
|
147 |
print("%08X: %08X bytes free" % (prev_addr + 4, block.get_size() + 4))
|
| 136 |
free_blocks.append(prev_addr)
|
148 |
free_blocks.append(prev_addr)
|
| 137 |
bytes_free = bytes_free + block.get_size() + 4
|
149 |
bytes_free = bytes_free + block.get_size() + 4
|
| 138 |
else:
|
150 |
else:
|
| 139 |
owner_address = prev_addr - image_base + block.get_size() - 4
|
151 |
owner_address = prev_addr - image_base + block.get_size() + 4
|
| 140 |
owner = struct.unpack("<I", data[owner_address : owner_address + 4])[0]
|
152 |
owner = struct.unpack("<I", data[owner_address : owner_address + 4])[0]
|
| - |
|
153 |
if (owner & 3) == 0:
|
| - |
|
154 |
if (owner & 0xfffc0000) == 0x22000000: name = "<KERNEL_THREAD>"
|
| - |
|
155 |
else:
|
| - |
|
156 |
try:
|
| - |
|
157 |
thread = scheduler_thread(data, image_base, owner & ~3)
|
| - |
|
158 |
name = "Thread: " + string_from_image(data, image_base, thread.name, 128)
|
| - |
|
159 |
except: name = "<BAD_THREAD>"
|
| - |
|
160 |
elif (owner & 3) == 1:
|
| - |
|
161 |
try:
|
| - |
|
162 |
handle = struct.unpack("<I", data[(owner & ~3) - image_base + 4 : (owner & ~3) - image_base + 8])[0]
|
| - |
|
163 |
lib = struct.unpack("<4sI", data[(handle & ~3) - image_base + 4 : (handle & ~3) - image_base + 12])
|
| - |
|
164 |
name = "Library: " + lib[0].decode("latin_1") + "_v%d" % lib[1]
|
| - |
|
165 |
except: name = "<BAD_LIBRARY>"
|
| - |
|
166 |
elif (owner & 3) == 2:
|
| - |
|
167 |
if (owner >> 2) == 0: name = "<KERNEL_UNKNOWN>";
|
| - |
|
168 |
elif (owner >> 2) == 1: name = "<KERNEL_USB_MONITOR>";
|
| - |
|
169 |
elif (owner >> 2) == 2: name = "<KERNEL_FILE_HANDLE>";
|
| - |
|
170 |
elif (owner >> 2) == 3: name = "<KERNEL_DIR_HANDLE>";
|
| - |
|
171 |
elif (owner >> 2) == 4: name = "<KERNEL_ATA_BBT>";
|
| - |
|
172 |
else: name = "<KERNEL_UNKNOWN_TYPE>";
|
| - |
|
173 |
else: name = "<UNKNOWN_TYPE>"
|
| 141 |
print("%08X: %08X+8 bytes owned by %08X" % (prev_addr + 8, block.get_size() - 4, owner))
|
174 |
print("%08X: %08X+8 bytes owned by %08X (%s)" % (prev_addr + 8, block.get_size() - 4, owner, name))
|
| 142 |
bytes_used = bytes_used + block.get_size() + 4
|
175 |
bytes_used = bytes_used + block.get_size() + 4
|
| 143 |
try: block = block.get_next_phys()
|
176 |
try: block = block.get_next_phys()
|
| 144 |
except:
|
177 |
except:
|
| 145 |
print("Block %08X has invalid size: %08X" % (prev_addr, block.get_size()))
|
178 |
print("Block %08X has invalid size: %08X" % (prev_addr, block.get_size()))
|
| 146 |
print("Fatal error in block chain, continuing with map check")
|
179 |
print("Fatal error in block chain, continuing with map check")
|
| Line 164... |
Line 197... |
| 164 |
print("[%d:%d:%08X] Block list must be null, but isn't" % (i, j, ba))
|
197 |
print("[%d:%d:%08X] Block list must be null, but isn't" % (i, j, ba))
|
| 165 |
continue
|
198 |
continue
|
| 166 |
elif block.is_null():
|
199 |
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))
|
200 |
print("[%d:%d:%08X] Block list is null, but second-level map indicates there are free blocks" % (i, j, ba))
|
| 168 |
blocks = []
|
201 |
blocks = []
|
| - |
|
202 |
prev = None
|
| 169 |
while not block.is_null():
|
203 |
while not block.is_null():
|
| 170 |
fatal = False
|
204 |
fatal = False
|
| 171 |
addr = block.get_address()
|
205 |
addr = block.get_address()
|
| 172 |
if blocks.count(addr) > 0:
|
206 |
if blocks.count(addr) > 0:
|
| 173 |
print("[%d:%d:%08X] Detected block loop" % (i, j, addr))
|
207 |
print("[%d:%d:%08X] Detected block loop" % (i, j, addr))
|
| 174 |
break
|
208 |
break
|
| 175 |
blocks.append(addr)
|
209 |
blocks.append(addr)
|
| - |
|
210 |
size = block.get_size()
|
| - |
|
211 |
print("[%d:%d] Block at %08X (%08X bytes)" % (i, j, addr, size + 4))
|
| 176 |
if not block.is_free():
|
212 |
if not block.is_free():
|
| 177 |
print("[%d:%d:%08X] Non-free block on free list" % (i, j, addr))
|
213 |
print("[%d:%d:%08X] Non-free block on free list" % (i, j, addr))
|
| 178 |
fatal = True
|
214 |
fatal = True
|
| 179 |
if block.is_prev_free():
|
215 |
if block.is_prev_free():
|
| 180 |
print("[%d:%d:%08X] Block should have coalesced with previous one" % (i, j, addr))
|
216 |
print("[%d:%d:%08X] Block should have coalesced with previous one" % (i, j, addr))
|
| 181 |
try:
|
217 |
try:
|
| 182 |
if block.get_next_phys().is_free():
|
218 |
if block.get_next_phys().is_free():
|
| 183 |
print("[%d:%d:%08X] Block should have coalesced with next one" % (i, j, addr))
|
219 |
print("[%d:%d:%08X] Block should have coalesced with next one" % (i, j, addr))
|
| 184 |
except:
|
220 |
except:
|
| 185 |
print("Block %08X has invalid size: %08X" % (addr, block.get_size()))
|
221 |
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:
|
222 |
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))
|
223 |
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:
|
224 |
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))
|
225 |
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:
|
226 |
if size < SMALL_BLOCK_SIZE:
|
| Line 207... |
Line 241... |
| 207 |
size = size << 2
|
241 |
size = size << 2
|
| 208 |
fl = fl - 2
|
242 |
fl = fl - 2
|
| 209 |
if (size & 0x80000000) == 0:
|
243 |
if (size & 0x80000000) == 0:
|
| 210 |
size = size << 1
|
244 |
size = size << 1
|
| 211 |
fl = fl - 1
|
245 |
fl = fl - 1
|
| - |
|
246 |
size = block.get_size()
|
| 212 |
sl = (block.get_size() >> (fl - SL_INDEX_COUNT_LOG2 + FL_INDEX_SHIFT - 1)) ^ (1 << SL_INDEX_COUNT_LOG2)
|
247 |
sl = (size >> (fl - SL_INDEX_COUNT_LOG2 + FL_INDEX_SHIFT - 1)) ^ (1 << SL_INDEX_COUNT_LOG2)
|
| 213 |
if fl != i or sl != j:
|
248 |
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))
|
249 |
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:
|
250 |
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))
|
251 |
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:
|
252 |
if handled_blocks.count(addr) > 0:
|
| 218 |
print("[%d:%d:%08X] Block appears in multiple free lists" % (i, j, addr))
|
253 |
print("[%d:%d:%08X] Block appears in multiple free lists" % (i, j, addr))
|
| 219 |
else: handled_blocks.append(addr)
|
254 |
else: handled_blocks.append(addr)
|
| - |
|
255 |
try:
|
| - |
|
256 |
nfa = block.get_next_free().get_address()
|
| - |
|
257 |
if nfa >= addr and nfa < addr + size + 4:
|
| - |
|
258 |
print("[%d:%d:%08X] Next free block (%08X) lies within the block itself" % (i, j, addr, nfa))
|
| - |
|
259 |
fatal = True
|
| - |
|
260 |
except:
|
| - |
|
261 |
print("[%d:%d:%08X] Invalid next free block pointer: %08X" % (i, j, addr, block.next_free))
|
| - |
|
262 |
fatal = True
|
| - |
|
263 |
try:
|
| - |
|
264 |
pfa = block.get_prev_free().get_address()
|
| - |
|
265 |
if pfa >= addr and pfa < addr + size + 4:
|
| - |
|
266 |
print("[%d:%d:%08X] Previous free block (%08X) lies within the block itself" % (i, j, addr, pfa))
|
| - |
|
267 |
if prev == None and not block.get_prev_free().is_null():
|
| - |
|
268 |
print("[%d:%d:%08X] Previous free block pointer is broken: %08X (should be NULL)" % (i, j, addr, pfa))
|
| - |
|
269 |
if prev != None and prev != pfa:
|
| - |
|
270 |
print("[%d:%d:%08X] Previous free block pointer is broken: %08X (should be %08X)" % (i, j, addr, pfa, prev))
|
| - |
|
271 |
except:
|
| - |
|
272 |
print("[%d:%d:%08X] Invalid previous free block pointer: %08X" % (i, j, addr, block.prev_free))
|
| 220 |
if fatal:
|
273 |
if fatal:
|
| 221 |
print("Fatal error in block chain, continuing with next chain")
|
274 |
print("Fatal error in block chain, continuing with next chain")
|
| 222 |
break
|
275 |
break
|
| - |
|
276 |
prev = addr
|
| 223 |
block = block.get_next_free()
|
277 |
block = block.get_next_free()
|
| 224 |
|
278 |
|
| 225 |
for addr in free_blocks:
|
279 |
for addr in free_blocks:
|
| 226 |
if handled_blocks.count(addr) != 1:
|
280 |
if handled_blocks.count(addr) != 1:
|
| 227 |
print("Free block %08X does not appear in any free list" % (addr))
|
281 |
print("Free block %08X does not appear in any free list" % (addr))
|