| 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: |