#!/usr/bin/env python from os import popen from sys import argv, stderr, exit dll = argv[1] #objdump = "~/xda/wince-cross/usr/local/wince/cross-tools/bin/arm-wince-pe-objdump" objdump = "~/src/oe/build/openmoko/cross/arm-linux/bin/objdump" section_name = [] section_size = [] section_vma = [] section_offset = [] imagebase = 0 # # is this a branch with link instruction? # def isbl(inst): return (inst[0:2] == 'bl') and ((len(inst) == 2) or (inst[2] != 's')) # # is this a load or store instruction? # def isldrstr(inst): return inst[0:3] in ["ldr", "str"] # # extract the address from a string that optionally starts with '; '. # the address has optional '0x' prefix and optional appended '' # def extract_address(s): if s[:2] == '; ': start = 2 else: start = 0 if s[start:start+2] == '0x': start += 2 end = s.find("<") if end >= 0: return int(s[start:end],16) else: return int(s[start:],16) # # character representation of a word # def asciichar(c): if c >= 32 and c < 128: return chr(c) else: return '.' def fourcc(data): return "%c%c%c%c" % (asciichar(data & 0xff), asciichar((data>>8) & 0xff), asciichar((data>>16) & 0xff), asciichar((data>>24) & 0xff)) # # is this an executable with headers? # ftype = popen("file %s" % dll).readlines()[0].split(' ')[1].replace("\n","") if ftype != "data": # # parse section headers # for l in popen("%s -h %s | grep ' \.'" % (objdump, dll)).readlines(): t = l.split() section_name = section_name + [t[1]] section_size = section_size + [int(t[2],16)] section_vma = section_vma + [int(t[3],16)] section_offset = section_offset + [int(t[5],16)] else: section_name = ["none"] section_size = [256*1024] section_vma = [0] section_offset = [0] # # virtual memory address <--> file offset translation # def vma_to_offset(vma): i=0 while i < len(section_size): if (vma >= section_vma[i]) and (vma < section_vma[i]+section_size[i]): return vma-section_vma[i]+section_offset[i] i=i+1 def offset_to_vma(offset): i=0 while i < len(section_size): if (offset >= section_offset[i]) and (offset < section_offset[i]+section_size[i]): return offset-section_offset[i]+section_vma[i] i=i+1 def vma_in_section(vma): i=0 while i < len(section_size): if (vma >= section_vma[i]) and (vma < section_vma[i]+section_size[i]): return True i=i+1 return False # # parse strings into a dictionary (0xADDR : "string") # strings = {} strlen = {} for l in popen("strings -tx %s" % dll).readlines(): l = l.split(None,1) if len(l) != 2: continue addr = offset_to_vma(int(l[0],16)) text = l[1].replace("\n","") strings[addr] = text strlen[addr] = (len(text)-1)/4+1 # unicode strings for l in popen("strings -tx -el %s" % dll).readlines(): l = l.split(None,1) if len(l) != 2: continue addr = offset_to_vma(int(l[0],16)) text = l[1].replace("\n","") if not strings.has_key(addr): strings[addr] = text strlen[addr] = len(text)/2+1 #print "STRING TABLE" #print "vma offset string" #for k in strings.keys(): # print '%8x %8x %s' % (k, vma_to_offset(k), strings[k]) # # parse function table into a dictionary (0xADDR : "name") # pipe = popen("%s -T %s | grep '^[0-9a-f]\{8\}'" % (objdump, dll)) ll=pipe.readlines() pipe.close() ftable = {} for l in ll: addr = int(l[:8],16) ftable[addr] = l[44:-1].strip() # # custom function information # custom_ftable = [] custom_ftable = file(dll+".ftable").readlines() for l in custom_ftable: if l[0] == '#': continue t = l.split('\t') if len(t) < 2: continue ftable[int(t[0],16)] = t[1] ftable[0x31ef0] = "DIS31ef0" #print "FUNCTION TABLE" #for k in ftable.keys(): # print "%8x %s" % (k, ftable[k]) # # disassemble # stderr.write("Disassembling...\n") if ftype == "data": pipe = popen("%s -b binary -m arm -D %s" % (objdump, dll)) else: pipe = popen("%s -D %s" % (objdump, dll)) #pipe = popen("%s -d %s" % (objdump, dll)) ll=pipe.readlines() pipe.close() datadict = {} referenced = {} jumped_to = {} stderr.write("Finding references...\n") i = 0 while i+1 < len(ll): i=i+1 l=ll[i] if (l == '\t...') or (l == '\n'): continue t = l.split('\t') if (len(t[0]) == 0) or (t[0][-1] != ':') or (len(t) < 3): continue addr = int(t[0][0:-1].strip(),16) data = int(t[1],16) datadict[addr] = data # only evaluate references inst = t[2][0:3] if isldrstr(inst): if t[len(t)-1][:2] == '; ': ref = extract_address(t[len(t)-1]) if vma_in_section(ref): referenced[ref] = 0 if isbl(inst): target = extract_address(t[3]) if vma_in_section(target): if target in jumped_to.keys(): jumped_to[target].append("0x%08x" % addr) else: jumped_to[target] = ["0x%08x" % addr] # # resolve references # stderr.write("Resolving references...\n"); for ref in referenced.keys(): if datadict.has_key(ref): referenced[ref] = datadict[ref] if datadict.has_key(referenced[ref]): referenced[referenced[ref]] = datadict[referenced[ref]] else: referenced[ref] = 0 # # go! go! go! # stderr.write("Generating disassembled output...\n") armreg = { 'r0': 0, 'r1': 1, 'r2': 2, 'r3': 3, 'r4': 4, 'r5': 5, 'r6': 6, 'r7': 7, 'r8': 8, 'r9': 9, 'sl': 10, 'fp': 11, 'ip': 12, 'sp': 13, 'lr': 14, 'pc': 15 } r = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] section = None i = 0 while i+1 < len(ll): i=i+1 l=ll[i].strip('\n') if (l == '\t...') or (l == '\n'): #print l continue t = l.split('\t') if (len(t[0]) == 0) or (t[0][-1] != ':') or (len(t) < 3): if t[0][:23] == "Disassembly of section ": section = t[0][23:-1] print "Section %s" % section continue addr = int(t[0][0:-1].strip(),16) data = int(t[1],16) inst = t[2] section_list = [".text", ".rodata", ".data.rel.ro", ".data", ".bss"] if not (section in section_list): continue # # print function header comment # if ftable.has_key(addr): print "\n/*\n * %s\n */" % ftable[addr] if jumped_to.has_key(addr): print "/*\n * %s\n */" % jumped_to[addr] # # interpret some instructions # r[15] = addr+8 intstr = "" if inst == "ldr": a = t[3][:2] b = t[3][5:7] if armreg.has_key(a) and armreg.has_key(b): if t[3][4:10] == "[pc, #": target_addr = extract_address(t[4]) if datadict.has_key(target_addr): r[armreg[a]] = datadict[target_addr] intstr = "%s = %x" % (a, r[armreg[a]]) else: r[armreg[a]] = 0xbaadbaad else: c = t[3][9:] if t[3][7] == ']': target_addr = r[armreg[b]] elif c[0] == '#': if c[-1] == '!': target_addr = r[armreg[b]] + int(c[1:-2]) r[armreg[b]] += int(c[1:-2]) else: target_addr = r[armreg[b]] + int(c[1:-1]) elif armreg.has_key(c[:-1]): target_addr = r[armreg[b]] + r[armreg[c[:-1]]] else: target_addr = 0xbaadbaad if datadict.has_key(target_addr): r[armreg[a]] = datadict[target_addr] intstr = "%s = %x (<-- %x)" % (a, r[armreg[a]], target_addr) else: intstr = "ERR %x" % target_addr r[armreg[a]] = 0xbaadbaad else: intstr = "FIXME" if armreg.has_key(a): r[armreg[a]] = 0xbaadbaad if inst == "mov": a = t[3][:2] if armreg.has_key(a): b = t[3][4:] if b[0] == '#': r[armreg[a]] = int(b[1:]) intstr = "%s = %x" % (a, r[armreg[a]]) elif armreg.has_key(b): r[armreg[a]] = r[armreg[b]] intstr = "%s = %x" % (a, r[armreg[a]]) else: intstr = "FIXME" r[armreg[a]] = 0xbaadbaad else: intstr = "ERR" if inst == "add": a = t[3][:2] b = t[3][4:6] if armreg.has_key(a) and armreg.has_key(b): c = t[3][8:] if c[0] == '#': r[armreg[a]] = (r[armreg[b]] + int(c[1:])) & 0xffffffff intstr = "%s = %x" % (a, r[armreg[a]]) elif armreg.has_key(c): r[armreg[a]] = (r[armreg[b]] + r[armreg[c]]) & 0xffffffff intstr = "%s = %x" % (a, r[armreg[a]]) else: intstr = "FIXME" r[armreg[a]] = 0xbaadbaad else: intstr = "FIXME" if armreg.has_key(a): r[armreg[a]] = 0xbaadbaad if len(intstr) < 8: intstr = intstr + "\t\t" elif len(intstr) < 16: intstr = intstr + "\t" print intstr, # # print line # if strings.has_key(addr): print "%8x:\t\"%s\"" % (addr, strings[addr]) if(strlen[addr]>1): i += strlen[addr]-1 l = ll[i+1] t = l.split('\t') if len(t)>2: next = int(ll[i+1].strip('\n').split('\t')[1],16) if next in [0x0, 0xa]: i += 1 elif referenced.has_key(addr): if strings.has_key(data): print "%8x:\t\"%s\"" % (addr, strings[data]) if(strlen[data]>1): i += strlen[data]-1 l = ll[i+1] t = l.split('\t') if len(t)>2: next = int(ll[i+1].strip('\n').split('\t')[1],16) if next in [0x0, 0xa]: i += 1 elif referenced.has_key(data): if datadict.has_key(referenced[data]): if strings.has_key(referenced[data]): print "%8x:\t%08x --> \"%s\"" % (addr, data, strings[referenced[data]]) else: print "%8x:\t%08x --> %08x" % (addr, data, datadict[referenced[data]]) else: print "%8x:\t%08x --> ? (at %08x)" % (addr, data, referenced[data]) else: if len(t) > 3: print "%8x:\t%08x %s\t%s\t%s\t; (ref.d somewhere)" % (addr, data, fourcc(data), t[2], t[3]) else: print "%8x:\t%08x %s\t%s\t; (ref.d somewhere)" % (addr, data, fourcc(data), t[2]) elif t[len(t)-1][0:4] == '; 0x': ref = int(t[len(t)-1][4:],16) if referenced.has_key(ref) and ref != 0: if datadict.has_key(referenced[ref]): if strings.has_key(referenced[ref]): print "%s = 0x%08x --> \"%s\"" % (l, referenced[ref], strings[referenced[ref]]) else: print "%s = 0x%08x --> %08x" % (l, referenced[ref], datadict[referenced[ref]]) else: print "%s --> 0x%08x" % (l, referenced[ref]) else: print l elif addr in jumped_to.keys(): print "\n/*\n *", print jumped_to[addr], print "\n */\n%s" % l elif isldrstr(inst): if t[len(t)-1][:2] == '; ': ref = extract_address(t[len(t)-1]) if referenced.has_key(ref): if datadict.has_key(referenced[ref]): if strings.has_key(referenced[ref]): print "%s = 0x%08x --> \"%s\"" % (l, referenced[ref], strings[referenced[ref]]) else: print "%s = 0x%08x --> %08x" % (l, referenced[ref], datadict[referenced[ref]]) else: print "%s --> 0x%08x" % (l, referenced[ref]) else: print "INTERNAL ERROR, REFERENCE SHOULD EXIST" exit(1) else: print l elif isbl(inst): target = extract_address(t[3]) if ftable.has_key(target): pos = l.rfind("<") if pos >= 0: print l[:pos], else: print l, print "<%s>" % ftable[target], if ftable[target] in ["printf", "puts", "fwrite"]: print "r0 = 0x%x" % r[0], if strings.has_key(r[0]): print "--> \"%s\"" % strings[r[0]], elif ftable[target] in ["sprintf, vsprintf", "fprintf"]: print "r1 = 0x%x" % r[1], if strings.has_key(r[1]): print "--> \"%s\"" % strings[r[1]], elif ftable[target] in ["putchar", "fputc"]: print "r0 = 0x%x" % r[0] elif ftable[target] == "fread": print "r0 = 0x%x" % r[0] elif ftable[target] == "DIS31ef0": if strings.has_key(r[1]): print "r0 = 0x%x, r1 = \"%s\"" % (r[0], strings[r[1]]) else: print "r0 = 0x%x, r1 = 0x%x" % (r[0], r[1]) print else: print l else: if strings.has_key(data): print "%s\t; --> \"%s\"" % (l, strings[data]) elif ftable.has_key(data): print "%s\t; --> <%s>" % (l, ftable[data]) else: print "%8x:\t%08x %s\t%s" % (addr, data, fourcc(data), '\t'.join(t[2:])) continue