136 lines
5.6 KiB
Python
Executable File
136 lines
5.6 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
##Copyright IBM Corp. 2010
|
|
##
|
|
##Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
|
##
|
|
##http://www.apache.org/licenses/LICENSE-2.0
|
|
##
|
|
##Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
|
|
import immlib
|
|
import getopt
|
|
from libheap import *
|
|
import libdatatype
|
|
|
|
DESC= "Low Fragmentation Heap Viewer"
|
|
def usage(imm):
|
|
imm.log("!horse [-h HEAP_ADDR] [-b BLOCKS_ADDR] [-s Heap Bucket / SubSegment Info")
|
|
imm.log(" -h HEAPADDR Set the heap address to inspect")
|
|
imm.log(" -b BLOCKSADDR Set the _HEAP_LIST_LOOKUP block to inspect")
|
|
imm.log(" -n Find bins which are NOT being managed by the LFH")
|
|
|
|
def main(args):
|
|
imm = immlib.Debugger()
|
|
window = None
|
|
|
|
if not args:
|
|
imm.log("Please supply a valid _HEAP")
|
|
return "NO HEAP PASSED"
|
|
|
|
# options:
|
|
# -h HEAP
|
|
# -b Only look at specific _HEAP_LIST_LOOKUP
|
|
# -n Look for empty bins
|
|
try:
|
|
opts, argo = getopt.getopt(args, "h:nsb:")
|
|
except getopt.GetoptError:
|
|
#imm.setStatusBar("Bad heap argument %s" % args[0])
|
|
usage(imm)
|
|
return "Bad heap argument %s" % args[0]
|
|
|
|
heap = 0x0
|
|
lfhthreshold = 0x12
|
|
singleblock = False
|
|
blockindex = 0x0
|
|
emptybins = False
|
|
restore = False
|
|
opennewwindow = False
|
|
|
|
for o,a in opts:
|
|
if o == "-h":
|
|
try:
|
|
heap = int(a, 16)
|
|
except ValueError, msg:
|
|
return "Invalid heap address: %s" % a
|
|
elif o == "-b":
|
|
singleblock = True
|
|
try:
|
|
blockindex = int(a, 16)
|
|
except ValueError, msg:
|
|
return "Invalid heap address: %s" % a
|
|
elif o == "-n":
|
|
emptybins = True
|
|
elif o == "-r":
|
|
restore = True
|
|
|
|
if (heap and ( heap in imm.getHeapsAddress() )) or blockindex:
|
|
tag = "heap_%08x" % heap
|
|
|
|
if not opennewwindow:
|
|
window = imm.getKnowledge(tag)
|
|
if window and not window.isValidHandle():
|
|
imm.forgetKnowledge(tag)
|
|
del window
|
|
window = None
|
|
|
|
if not window:
|
|
window = imm.createTable("Heap dump 0x%08x" % heap, ["Address", "Chunks"] )
|
|
imm.addKnowledge(tag, window, force_add = 1)
|
|
|
|
if not heap and blockindex:
|
|
pheap = imm.getHeap(blockindex & 0xFFFF0000, restore)
|
|
else:
|
|
pheap = imm.getHeap( heap, restore )
|
|
|
|
if pheap and pheap.FrontEndHeapType == 0x2 and pheap.FrontEndHeap:
|
|
lfhthreshold = 0x11
|
|
|
|
for i in (0, len(pheap.blocks)-1):
|
|
block = pheap.blocks[i]
|
|
|
|
#we're looking for a specific blockindex
|
|
if singleblock:
|
|
if block.address != blockindex:
|
|
continue
|
|
|
|
num_of_freelists = block.ArraySize - block.BaseIndex
|
|
window.Log("Printing Block information for 0x%08x" % block.address)
|
|
window.Log("ExtendedLookup => 0x%08x" % block.ExtendedLookup)
|
|
window.Log("ArraySize [max permitted in blocks] => 0x%08x" % block.ArraySize)
|
|
window.Log("BaseIdex => 0x%08x" % block.BaseIndex)
|
|
window.Log("End Block information for 0x%08x" % block.address)
|
|
window.Log("Block has [0x%x] FreeLists starting at 0x%08x:" % (num_of_freelists, block.ListHints))
|
|
|
|
memory = imm.readMemory( block.ListHints, num_of_freelists * 8 )
|
|
|
|
for a in range(0, num_of_freelists):
|
|
free_entry = []
|
|
# Previous and Next Chunk of the head of the double linked list
|
|
(flink, heap_bucket) = struct.unpack("LL", memory[a *8 : a * 8 + 8] )
|
|
|
|
bin = a + block.BaseIndex
|
|
|
|
freelist_addr = block.ListHints + (bin - block.BaseIndex) * 8
|
|
|
|
if heap_bucket != 0 and not emptybins:
|
|
if heap_bucket & 1:
|
|
window.Log("Flink => 0x%08x | Bin[0x%x] enabled | Bucket => 0x%08x" % (flink, bin, heap_bucket - 1), address = freelist_addr)
|
|
elif (heap_bucket & 0x0000FFFF) >= 0x22: #there appears to be a case where the LFH isn't activated when it should be...
|
|
window.Log("Flink => 0x%08x | Bin[0x%x] ??????? | Bucket => 0x%08x" % (flink, bin, heap_bucket), address = freelist_addr)
|
|
else:
|
|
allocations = heap_bucket & 0x0000FFFF
|
|
allocations = allocations / 2
|
|
amount_needed = lfhthreshold - allocations
|
|
window.Log("Flink => 0x%08x | Bin[0x%x] has had 0x%x allocations | Needs 0x%x more" % (flink, bin, allocations, amount_needed), address = freelist_addr)
|
|
else:
|
|
if emptybins and heap_bucket == 0 and bin != 0x1 and bin != 0x0:
|
|
window.Log("Flink => 0x%08x | Bin[0x%x] is Emtpy!" % (flink, bin), address = freelist_addr)
|
|
|
|
window.Log("")
|
|
window.Log("=-" * 0x23 + "=")
|
|
return "Heap 0x%x dumped" % heap
|
|
else:
|
|
imm.log("Error: A proper heap or blockindex needs to be defined")
|
|
return "Error: A proper heap or blockindex needs to be defined"
|