| Index: emcore/trunk/tools/misc.py |
| — | — | @@ -284,6 +284,22 @@ |
| 285 | 285 | thread = scheduler_thread()._to_bunch()
|
| 286 | 286 | thread.name = "[Invalid Thread 0x%08X]" % address
|
| 287 | 287 | return thread
|
| | 288 | +
|
| | 289 | +
|
| | 290 | +def string_from_image(data, base, ptr, maxlen):
|
| | 291 | + if ptr == 0: name = "<NULL>"
|
| | 292 | + try:
|
| | 293 | + string = ""
|
| | 294 | + end = data.find(b"\0", ptr - base, ptr - base + maxlen)
|
| | 295 | + if end < 0: return "<BAD_STRING>"
|
| | 296 | + else:
|
| | 297 | + d = data[ptr - base : end]
|
| | 298 | + for i in range(len(d)):
|
| | 299 | + byte = ord(d[i : i + 1])
|
| | 300 | + if byte < 0x20: return "<BAD_STRING>"
|
| | 301 | + else: string = string + chr(byte)
|
| | 302 | + except: return "<BAD_PTR>"
|
| | 303 | + return string
|
| 288 | 304 |
|
| 289 | 305 |
|
| 290 | 306 | def gethwname(id):
|
| — | — | @@ -445,4 +461,5 @@ |
| 446 | 462 | Returns the major version of python
|
| 447 | 463 | """
|
| 448 | 464 | import sys
|
| 449 | | - return sys.hexversion // 0x1000000 |
| \ No newline at end of file |
| | 465 | + return sys.hexversion // 0x1000000
|
| | 466 | + |
| \ No newline at end of file |
| Index: emcore/trunk/tools/tlsfanalyze.py |
| — | — | @@ -24,7 +24,8 @@ |
| 25 | 25 |
|
| 26 | 26 | import sys
|
| 27 | 27 | import struct
|
| 28 | | -from misc import ExtendedCStruct
|
| | 28 | +from misc import ExtendedCStruct, string_from_image
|
| | 29 | +from libemcoredata import scheduler_thread
|
| 29 | 30 | from ctypes import *
|
| 30 | 31 |
|
| 31 | 32 |
|
| — | — | @@ -132,13 +133,45 @@ |
| 133 | 134 | break
|
| 134 | 135 | blocks.append(prev_addr)
|
| 135 | 136 | if prev_free:
|
| | 137 | + try:
|
| | 138 | + nfa = block.get_next_free().get_address()
|
| | 139 | + if nfa >= prev_addr and nfa < prev_addr + block.get_size() + 4:
|
| | 140 | + print("%08X: Next free block (%08X) lies within the block itself" % (prev_addr, nfa))
|
| | 141 | + except: print("%08X: Invalid next free block pointer: %08X" % (prev_addr, block.next_free))
|
| | 142 | + try:
|
| | 143 | + pfa = block.get_prev_free().get_address()
|
| | 144 | + if pfa >= prev_addr and pfa < prev_addr + block.get_size() + 4:
|
| | 145 | + print("%08X: Previous free block (%08X) lies within the block itself" % (prev_addr, pfa))
|
| | 146 | + except:
|
| | 147 | + print("%08X: Invalid previous free block pointer: %08X" % (prev_addr, block.prev_free))
|
| 136 | 148 | print("%08X: %08X bytes free" % (prev_addr + 4, block.get_size() + 4))
|
| 137 | 149 | free_blocks.append(prev_addr)
|
| 138 | 150 | bytes_free = bytes_free + block.get_size() + 4
|
| 139 | 151 | else:
|
| 140 | | - owner_address = prev_addr - image_base + block.get_size() - 4
|
| | 152 | + owner_address = prev_addr - image_base + block.get_size() + 4
|
| 141 | 153 | 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))
|
| | 154 | + if (owner & 3) == 0:
|
| | 155 | + if (owner & 0xfffc0000) == 0x22000000: name = "<KERNEL_THREAD>"
|
| | 156 | + else:
|
| | 157 | + try:
|
| | 158 | + thread = scheduler_thread(data, image_base, owner & ~3)
|
| | 159 | + name = "Thread: " + string_from_image(data, image_base, thread.name, 128)
|
| | 160 | + except: name = "<BAD_THREAD>"
|
| | 161 | + elif (owner & 3) == 1:
|
| | 162 | + try:
|
| | 163 | + handle = struct.unpack("<I", data[(owner & ~3) - image_base + 4 : (owner & ~3) - image_base + 8])[0]
|
| | 164 | + lib = struct.unpack("<4sI", data[(handle & ~3) - image_base + 4 : (handle & ~3) - image_base + 12])
|
| | 165 | + name = "Library: " + lib[0].decode("latin_1") + "_v%d" % lib[1]
|
| | 166 | + except: name = "<BAD_LIBRARY>"
|
| | 167 | + elif (owner & 3) == 2:
|
| | 168 | + if (owner >> 2) == 0: name = "<KERNEL_UNKNOWN>";
|
| | 169 | + elif (owner >> 2) == 1: name = "<KERNEL_USB_MONITOR>";
|
| | 170 | + elif (owner >> 2) == 2: name = "<KERNEL_FILE_HANDLE>";
|
| | 171 | + elif (owner >> 2) == 3: name = "<KERNEL_DIR_HANDLE>";
|
| | 172 | + elif (owner >> 2) == 4: name = "<KERNEL_ATA_BBT>";
|
| | 173 | + else: name = "<KERNEL_UNKNOWN_TYPE>";
|
| | 174 | + else: name = "<UNKNOWN_TYPE>"
|
| | 175 | + print("%08X: %08X+8 bytes owned by %08X (%s)" % (prev_addr + 8, block.get_size() - 4, owner, name))
|
| 143 | 176 | bytes_used = bytes_used + block.get_size() + 4
|
| 144 | 177 | try: block = block.get_next_phys()
|
| 145 | 178 | except:
|
| — | — | @@ -166,6 +199,7 @@ |
| 167 | 200 | elif block.is_null():
|
| 168 | 201 | print("[%d:%d:%08X] Block list is null, but second-level map indicates there are free blocks" % (i, j, ba))
|
| 169 | 202 | blocks = []
|
| | 203 | + prev = None
|
| 170 | 204 | while not block.is_null():
|
| 171 | 205 | fatal = False
|
| 172 | 206 | addr = block.get_address()
|
| — | — | @@ -173,6 +207,8 @@ |
| 174 | 208 | print("[%d:%d:%08X] Detected block loop" % (i, j, addr))
|
| 175 | 209 | break
|
| 176 | 210 | blocks.append(addr)
|
| | 211 | + size = block.get_size()
|
| | 212 | + print("[%d:%d] Block at %08X (%08X bytes)" % (i, j, addr, size + 4))
|
| 177 | 213 | if not block.is_free():
|
| 178 | 214 | print("[%d:%d:%08X] Non-free block on free list" % (i, j, addr))
|
| 179 | 215 | fatal = True
|
| — | — | @@ -183,8 +219,6 @@ |
| 184 | 220 | print("[%d:%d:%08X] Block should have coalesced with next one" % (i, j, addr))
|
| 185 | 221 | except:
|
| 186 | 222 | print("Block %08X has invalid size: %08X" % (addr, block.get_size()))
|
| 187 | | - fatal = True
|
| 188 | | - size = block.get_size()
|
| 189 | 223 | if size < block_size_min:
|
| 190 | 224 | print("[%d:%d:%08X] Block violates minimum size: %d (should be at least %d)" % (i, j, addr, size, block_size_min))
|
| 191 | 225 | if size > block_size_max:
|
| — | — | @@ -209,7 +243,8 @@ |
| 210 | 244 | if (size & 0x80000000) == 0:
|
| 211 | 245 | size = size << 1
|
| 212 | 246 | fl = fl - 1
|
| 213 | | - sl = (block.get_size() >> (fl - SL_INDEX_COUNT_LOG2 + FL_INDEX_SHIFT - 1)) ^ (1 << SL_INDEX_COUNT_LOG2)
|
| | 247 | + size = block.get_size()
|
| | 248 | + sl = (size >> (fl - SL_INDEX_COUNT_LOG2 + FL_INDEX_SHIFT - 1)) ^ (1 << SL_INDEX_COUNT_LOG2)
|
| 214 | 249 | if fl != i or sl != j:
|
| 215 | 250 | print("Block %08X is in wrong free list: [%d:%d] (should be [%d:%d])" % (addr, i, j, fl, sl))
|
| 216 | 251 | if free_blocks.count(addr) != 1:
|
| — | — | @@ -217,9 +252,28 @@ |
| 218 | 253 | if handled_blocks.count(addr) > 0:
|
| 219 | 254 | print("[%d:%d:%08X] Block appears in multiple free lists" % (i, j, addr))
|
| 220 | 255 | else: handled_blocks.append(addr)
|
| | 256 | + try:
|
| | 257 | + nfa = block.get_next_free().get_address()
|
| | 258 | + if nfa >= addr and nfa < addr + size + 4:
|
| | 259 | + print("[%d:%d:%08X] Next free block (%08X) lies within the block itself" % (i, j, addr, nfa))
|
| | 260 | + fatal = True
|
| | 261 | + except:
|
| | 262 | + print("[%d:%d:%08X] Invalid next free block pointer: %08X" % (i, j, addr, block.next_free))
|
| | 263 | + fatal = True
|
| | 264 | + try:
|
| | 265 | + pfa = block.get_prev_free().get_address()
|
| | 266 | + if pfa >= addr and pfa < addr + size + 4:
|
| | 267 | + print("[%d:%d:%08X] Previous free block (%08X) lies within the block itself" % (i, j, addr, pfa))
|
| | 268 | + if prev == None and not block.get_prev_free().is_null():
|
| | 269 | + print("[%d:%d:%08X] Previous free block pointer is broken: %08X (should be NULL)" % (i, j, addr, pfa))
|
| | 270 | + if prev != None and prev != pfa:
|
| | 271 | + print("[%d:%d:%08X] Previous free block pointer is broken: %08X (should be %08X)" % (i, j, addr, pfa, prev))
|
| | 272 | + except:
|
| | 273 | + print("[%d:%d:%08X] Invalid previous free block pointer: %08X" % (i, j, addr, block.prev_free))
|
| 221 | 274 | if fatal:
|
| 222 | 275 | print("Fatal error in block chain, continuing with next chain")
|
| 223 | 276 | break
|
| | 277 | + prev = addr
|
| 224 | 278 | block = block.get_next_free()
|
| 225 | 279 |
|
| 226 | 280 | for addr in free_blocks:
|