dissy-9/0000755000175000017500000000000011155777556010520 5ustar skaskadissy-9/setup.py0000644000175000017500000000251611155777556012236 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Filename: setup.py ## Author: Simon Kagstrom ## Description: Installation script ## ## $Id: setup.py 14502 2007-03-28 04:21:14Z ska $ ## ###################################################################### import sys sys.path.append(".") from dissy import Config from distutils.core import setup setup(name='%s' % (Config.PROGRAM_NAME).lower(), version='%s' % (Config.PROGRAM_VERSION), description="A graphical frontend to objdump with navigation possibilities", author="Simon Kagstrom", url="%s" % (Config.PROGRAM_URL), author_email="simon.kagstrom@bth.se", packages = ['dissy'], scripts = ['scripts/dissy'], data_files = [('share/%s/gfx' % (Config.PROGRAM_NAME.lower()), ['gfx/red_arrow_left.png', 'gfx/red_line.png', 'gfx/red_start_down.png', 'gfx/red_arrow_right.png', 'gfx/red_plus.png', 'gfx/red_start_up.png', 'gfx/icon.svg']), ('share/%s/' % (Config.PROGRAM_NAME.lower()), ['menubar.xml']), ('share/doc/%s/' % (Config.PROGRAM_NAME.lower()), ['README']), ('share/doc/%s/' % (Config.PROGRAM_NAME.lower()), ['COPYING']), ('share/man/man1/', ['dissy.1']), ], ) dissy-9/menubar.xml0000644000175000017500000000107611155777556012677 0ustar skaska dissy-9/TODO0000644000175000017500000000020211155777556011202 0ustar skaska* Support ide_hwif+0x30 (Linux crashes) * bcl- 20,4*cr7+so, ff73930 * U-boot: bne in get_table_entry_name, and genimg_get_os_name dissy-9/README0000644000175000017500000000043011155777556011375 0ustar skaskaDissy is a graphical frontend to objdump with navigation possibilities. See the webpage, http://dissy.googlecode.com for more information. Running without installing -------------------------- run $ scripts/dissy Installing ---------- run $ sudo python setup.py install dissy-9/dissy/0000755000175000017500000000000011155777556011653 5ustar skaskadissy-9/dissy/DataModel.py0000644000175000017500000000317011155777556014060 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Display the functions ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import gtk, gobject class InfoModel: """ The model class holds the information we want to display """ def __init__(self, fileContainer): """ Sets up and populates our gtk.TreeStore """ self.tree_store = gtk.TreeStore( gobject.TYPE_STRING, gobject.TYPE_LONG, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT ) # Create the TreeStore for item in fileContainer.getData(): # Insert functions item.iter = self.tree_store.append(None, ("0x%08x" % item.getAddress(), item.getSize(), item.getLabel(), item.getType(), item ) ) def getModel(self): """ Returns the model """ if self.tree_store: return self.tree_store else: return None dissy-9/dissy/InstructionModel.py0000644000175000017500000001437311155777556015537 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Instruction models ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import gtk, gobject from Config import * from Function import Function from StrEntity import StrEntity from Instruction import Instruction def loadFile(fileName): pathsToSearch = ['.', '/usr/local/share/%s' % (PROGRAM_NAME).lower(), '/usr/share/%s' % (PROGRAM_NAME).lower()] for path in pathsToSearch: fullPath = "%s/%s" % (path, fileName) try: return gtk.gdk.pixbuf_new_from_file(fullPath) except: pass return None red_start_down = loadFile("gfx/red_start_down.png") red_line = loadFile("gfx/red_line.png") red_plus = loadFile("gfx/red_plus.png") red_arrow_left = loadFile("gfx/red_arrow_left.png") red_start_up = loadFile("gfx/red_start_up.png") red_arrow_right = loadFile("gfx/red_arrow_right.png") jump_pixmaps_right=[None, red_start_down, red_line, red_arrow_left, red_plus, red_plus] jump_pixmaps_left=[None, red_start_up, red_line, red_arrow_right, red_plus, red_plus] ( COLUMN_ADDR, COLUMN_LEFT_STATE2, COLUMN_LEFT_STATE1, COLUMN_LEFT_STATE0, COLUMN_STR_REPRESENTATION, COLUMN_RIGHT_STATE0, COLUMN_RIGHT_STATE1, COLUMN_RIGHT_STATE2, COLUMN_TARGET, COLUMN_INSTRUCTION, ) = range(10) class InfoModel: """ The model class holds the information we want to display """ def __init__(self, function, curInstruction = None, highlighters=[]): """ Sets up and populates our gtk.TreeStore """ self.function = function self.curInstruction = curInstruction self.highlighters = highlighters self.tree_store = gtk.TreeStore( gobject.TYPE_STRING, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gobject.TYPE_STRING, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT ) # Create the TreeStore if self.function == None: return self.lazyinitFunction() for insn in self.function.getAll(): if isinstance(insn, StrEntity): if config.showHighLevelCode: insn.iter = self.tree_store.append( None, ("", jump_pixmaps_left[insn.left_state[2]], jump_pixmaps_left[insn.left_state[1]], jump_pixmaps_left[insn.left_state[0]], '%s\t' % (config.highLevelCodeFgColor, str(insn)), jump_pixmaps_right[insn.right_state[0]], jump_pixmaps_right[insn.right_state[1]], jump_pixmaps_right[insn.right_state[2]], "", insn )) continue target = "" if isinstance(insn.getOutLink(), Function): target = insn.getOutLink().getLabel() insnAddr = "0x%08x" % (insn.getAddress()) insnStr = insn.getOpcode() argsStr = insn.getArgs() strRepresentation = '%s\t%s' % (config.insnFgColor, insnStr, argsStr) insn.iter = self.tree_store.append( None, (insnAddr, jump_pixmaps_left[insn.left_state[2]], jump_pixmaps_left[insn.left_state[1]], jump_pixmaps_left[insn.left_state[0]], strRepresentation, jump_pixmaps_right[insn.right_state[0]], jump_pixmaps_right[insn.right_state[1]], jump_pixmaps_right[insn.right_state[2]], target, insn )) self.refreshModel() def refreshModel(self): for iter in self.tree_store: insn = iter[COLUMN_INSTRUCTION] if isinstance(insn, Instruction): insnAddr = "0x%08x" % (insn.getAddress()) insnStr = insn.getOpcode() argsStr = insn.getArgs() strRepresentation = '%s\t%s' % (config.insnFgColor, insnStr, argsStr) iter[COLUMN_STR_REPRESENTATION] = strRepresentation iter[COLUMN_ADDR] = insnAddr for highlighter in self.highlighters: highlighter.highlight(iter, self.curInstruction) def lazyinitFunction(self): if self.function == None: return if self.function.getAll() == []: self.function.parse() self.function.link() def setCurInstruction(self, curInstruction): self.curInstruction = curInstruction if self.function == None: return def getModel(self): """ Returns the model """ if self.tree_store: return self.tree_store else: return None dissy-9/dissy/arm.py0000644000175000017500000002113011155777556013001 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Arm arch specific stuff ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import sys, architecture from dissy.architecture import Architecture arm_jumps = ['b', 'bcc', 'bl', 'ble', 'bne', 'bleq', 'blt', 'bgt', 'beq', 'bcs', ] arm_calls = ['bl'] arm_conditionflag_setters = ['cmp'] + \ [i + "s" for i in ['mul', 'mla', 'umull', 'umlal', 'smull', 'smlal', 'mov', 'mvn', 'asr', 'lsl', 'lsr', 'ror', 'rrx',] #TODO more ] arm_conditionflag_users = [''] arm_instr_descriptions = { 'cmp': 'Compare two values, and sets the condition flags', 'adc': 'Add with carry', 'add': 'Add', 'sub': 'Subtract', 'and': 'Logical and', 'bic': 'Bit Clear', 'bal': 'Unconditional Branch', 'blal': 'Unconditional Branch and Link', 'mov': 'Move', 'mvn': 'Move and negate (XOR 0xFFFFFFFF)', 'bx': """Branch and eXchange PC := Rm""", 'bl': """Branch with Link LR := Address of next instruction, PC := label""", 'push': """Push on the stack. Canonical form of "stmdb SP!, \"""", 'pop': """Pop from the stack. Canonical form of "ldm SP!, \"""", 'asr': 'Arithmetic Shift Right', 'mul': 'Multiply', 'muls': 'Multiply and set condition flags', 'mla': 'Multiply and Accumulate', 'mls': 'Multiply and Subtract', 'smull': """Signed Multiply Long %(arg1)s,%(arg2)s := signed(%(arg3)s * %(arg4)s)""", 'ldr': 'Load (from memory to register)', 'str': 'Store (from register to memory)', 'lsl': 'Logical Shift Left', 'lsls': 'Logical Shift Left and set condition flags', 'lsr': 'Logical Shift Right', 'lsr': 'Logical Shift Right and set condition flags', 'rsb': 'Reverse Subtract', } arm_conditions = { 'cs': 'Carry Set', 'cc': 'Carry Clear', 'eq': 'Equal (Zero Set)', 'ne': 'Not Equal (Zero Clear)', 'vs': 'Overflow Set', 'vc': 'Overflow Clear', 'gt': 'Signed Greater Than', 'lt': 'Signed Less Than', 'ge': 'Signed Greater than or Equal', 'le': 'Signed Less than or Equal', 'pl': 'Plus (Positive)', 'mi': 'Minus (Negative)', 'hi': 'Unsigned Higher Than', 'lo': 'Unsigned Lower Than', 'hs': 'Unsigned Higher or Same', 'ls': 'Unsigned Lower or Same', } arm_lists_inited = False if not arm_lists_inited: conditional_instructions = { 'b': """Branch on %s PC := label, label is this instruction +/-32Mb""", 'bx': """Branch and eXchange on %s PC := Rm Change to Thumb mode if Rm[0] is 1, change to ARM mode if Rm[0] is 0""", 'bl': """Branch and Link on %s""", 'mov': """Move on %s""", 'add': """Add on %s""", 'sub': """Subtract on %s""", } for i in conditional_instructions: for c in arm_conditions: arm_instr_descriptions[i + c] = conditional_instructions[i] % (arm_conditions[c]) arm_conditionflag_users += [i + c] arm_lists_inited = True class ArmArchitecture(architecture.Architecture): def __init__(self): architecture.Architecture.__init__(self, arm_jumps, arm_calls, arm_conditionflag_setters, arm_conditionflag_users) def getInstructionInfo(self, instruction): opcode = instruction.getOpcode() args = str(instruction.getArgs()) args_list = args.split(", ") args_dict = dict( zip(['arg' + str(i) for i in range(1, len(args_list)+1)], args_list)) description = arm_instr_descriptions.get(instruction.getOpcode(), '') return {'shortinfo': opcode + " " + args, 'description': description % args_dict, } def parseArguments(self, instr): """Parses an argument string, into a two-tuple, containing: * A list of the registers read in this instruction * A list of the registers written to in this instruction""" def parseComSepList(lstr): ret = [] tmp = "" stack = [] for c in lstr: if c in "{[": stack += [c] tmp += c elif c in "]}": tmp += c c2 = stack.pop() if c == "]" and c2 == "[" or \ c == "}" and c2 == "{": ret += [tmp] tmp = "" else: raise ValueError("unbalanced parenthesis") elif c == ' ': pass elif stack == [] and c == ',': ret += [tmp] tmp = "" elif stack == []: tmp += c else: tmp += c if tmp: ret += [tmp] return ret def isRegister(s): if s in ['r' + str(i) for i in range(0, 16)]: #r0..r15 return True if s in ['sl', #r10 = gcc "got pointer"? 'fp', #r11 = gcc frame pointer 'ip', #r12 = gcc "scratch register"? 'sp', #r13, stack pointer 'lr', #r14, link register 'pc']: #r15, program counter return True return False def isValue(s): if s[:1] == '#': if s[1:].isdigit(): return True return False regwrite = [] regread = [] values = [] args = parseComSepList(instr.args) values = [int(a[1:]) for a in args if isValue(a)] if instr.getOpcode()[:3] == 'cmp': regread = [a for a in args if isRegister(a)] elif instr.getOpcode()[:3] in ['sub', 'add', 'lsl', 'asr', 'rsb', 'mov', 'and', 'mvn']: regwrite = [args[0]] regread = [a for a in args[1:] if isRegister(a)] #branches elif instr.getOpcode() in ['b' + c for c in arm_conditions.keys() + ['']]: regwrite = ['pc'] elif instr.getOpcode() in ['bl' + c for c in arm_conditions.keys() + ['']]: regwrite = ['pc', 'lr'] elif instr.getOpcode() in ['bx' + c for c in arm_conditions.keys() + ['']]: regwrite = ['pc'] regread = [args[0]] elif instr.getOpcode() in ['blx' + c for c in arm_conditions.keys() + ['']]: regwrite = ['pc'] regread = isRegister(args[0]) and [args[0]] or [] #load elif instr.getOpcode() in ['ldr' + c for c in arm_conditions.keys() + ['']]: regwrite = [args[0]] if args[1].startswith('['): offsetl = parseComSepList(args[1][1:-1]) regread = [r for r in offsetl if isRegister(r)] #store elif instr.getOpcode() in ['str' + c for c in arm_conditions.keys() + ['']]: regread = [args[0]] if args[1].startswith('['): offsetl = parseComSepList(args[1][1:-1]) regread += [r for r in offsetl if isRegister(r)] #push elif instr.getOpcode() in ['push' + c for c in arm_conditions.keys() + ['']]: regwrite = ['sp'] regread = ['sp'] reglist = parseComSepList(args[0][1:-1]) regread += reglist elif instr.getOpcode() in ['pop' + c for c in arm_conditions.keys() + ['']]: regwrite = ['sp'] regread = ['sp'] reglist = parseComSepList(args[0][1:-1]) regwrite += reglist elif instr.getOpcode() in ['smull' + c for c in arm_conditions.keys() + ['']]: regwrite = [args[0], args[1]] regread = [args[2], args[3]] elif instr.getOpcode() in ['mla' + c for c in arm_conditions.keys() + ['']]: regwrite = [args[0]] regread = args[1:] elif instr.getOpcode() in ['mul' + c for c in arm_conditions.keys() + ['']] + \ ['muls' + c for c in arm_conditions.keys() + ['']]: regwrite = [args[0]] regread = [args[1], args[2]] elif instr.getOpcode() == '.word': return ([], [], []) else: raise ValueError("Unknown instruction opcode: " + str(instr)) return (regread, regwrite, values) dissy-9/dissy/Function.py0000644000175000017500000001353111155777556014015 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: A function ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import re, os, cgi from dissy.Config import config from dissy.Entity import Entity, AddressableEntity from dissy.Instruction import Instruction from dissy.JumpStreamHandler import * from dissy.StrEntity import StrEntity ADDRESS_REGEXP = "[0-9,a-f,A-F]+" ENCODING_REGEXP = ADDRESS_REGEXP + "[ ]" INSN_REGEXP = "[0-9,a-z,A-Z,_,\-,\.,\+]+" INSN_ARGS_REGEXP= "\**[a-z,A-Z,0-9,_,\,,\(,\),\%,\$,\[,\],!,#,\-, ,&,{,},\*,\+]+" insnRegExp = re.compile("[ ]*(" + ADDRESS_REGEXP + "):[ \t]+((?:" + ENCODING_REGEXP +")*)[ \t]+(" + INSN_REGEXP + ")+[ \t]*(" + INSN_ARGS_REGEXP + ")*") class Function(AddressableEntity): def __init__(self, fileContainer, address, label, size=0): AddressableEntity.__init__(self, address = address, endAddress = address + size, baseAddress = fileContainer.baseAddress) self.label = label self.all = [] self.insns = [] self.file = fileContainer def addInstruction(self, insn): self.insns.append(insn) self.all.append(insn) if insn.getAddress() > self.endAddress: self.setSize(insn.getAddress() - self.address) def getFile(self): return self.file def addOther(self, other): self.all.append(StrEntity(self, other)) def lookup(self, address): last = self.insns[0] for insn in self.insns[1:]: if address >= last.getAddress() and address < insn.getAddress(): return last last = insn return None def parse(self, try64bitWorkaround=False): """Parse the function.""" count = 0 start, end = self.getExtents() if try64bitWorkaround: if start & (1<<31): start = long(start) | 0xffffffff00000000 if end & (1<<31): end = long(end) | 0xffffffff00000000 s = "%s --wide --demangle --source --start-address=0x%Lx --stop-address=0x%Lx %s" % (config.objdump, start, end, self.file.filename) self.stream = os.popen(s) if self.stream == None: self.prepareParseFunction() self.instructions = [] self.all = [] firstNonEmpty=False for line in self.stream: # Weed away some unneeded stuff if line.startswith("Disassembly of section ") or line.startswith("%s: " % (self.file.filename)): continue if not firstNonEmpty and line.strip() == "": continue firstNonEmpty=True r = insnRegExp.match(line) if r != None: insn = Instruction(self, long("0x" + r.group(1),16), r.group(2), r.group(3), r.group(4)) self.addInstruction(insn) count = count + 1 else: self.addOther(cgi.escape(line)) self.stream.close() if count == 0 and try64bitWorkaround == False: # If we couldn't add anything interesting, try the 64-bit # workaround (for e.g., MIPS). See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=369343 return self.parse(try64bitWorkaround = True) def link(self): """ Link the local jumps in this function. External jumps are linked to the function they reside in. """ unresolved = [] for insn in self.insns: if insn.hasLink() and not insn.link(): unresolved.append(insn) positive, negative = self.getJumpDicts() # Fill in the jumps, forwards... self.fillInJumpStreams(positive, False) # ... and backwards self.all.reverse() self.fillInJumpStreams(negative, True) self.all.reverse() return unresolved def getInstructions(self): return self.insns def getAll(self): return self.all def getJumpDicts(self): """ Get jump dictionaries for the forward and backward jumps. """ positive = {} negative = {} for insn in self.insns: other = insn.getOutLink() if isinstance(other, Instruction) and other != insn: if other.getAddress() < insn.getAddress(): # Jump from insn to other BACKWARDS negative[insn.getAddress()] = (insn, other) else: # Jump from insn to other FORWARDS positive[insn.getAddress()] = (insn, other) return positive, negative def fillInJumpStreams(self, jumpDict, left): """ Fill in the jump streams for a dictionary of start addresses. Specify if the left or right streams should be generated. """ jumpStreamHandler = JumpStreamHandler() for insn in self.all: if isinstance(insn, Instruction): # Something starts on this address if jumpDict.has_key(insn.getAddress()): stream = jumpStreamHandler.alloc() if stream != None: stream.start(jumpDict[insn.getAddress()] ) jumpStreamHandler.update(insn) if left == True: insn.left_state = jumpStreamHandler.getStateTuple() else: insn.right_state = jumpStreamHandler.getStateTuple() def __str__(self): out = str("0x%08x" % self.address) + " " + str(self.label) + ":\n" for insn in self.insns: out = out + str(insn) + "\n" return out dissy-9/dissy/Entity.py0000644000175000017500000000247311155777556013507 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Entity (address, size etc.) ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### class Entity: def __init__(self): pass class AddressableEntity(Entity): def __init__(self, address=0, baseAddress = 0, endAddress = 0): self.label = "" self.address = address + baseAddress self.baseAddress = baseAddress if endAddress == 0: self.endAddress = self.address else: self.endAddress = endAddress + baseAddress def getAddress(self): return self.address def getLabel(self): return self.label def getExtents(self): "Return the extents of this function" return (self.address - self.baseAddress, self.endAddress - self.baseAddress) def setSize(self, size): "Set the size of this entity" self.endAddress = self.address + size def getSize(self): return self.endAddress - self.address dissy-9/dissy/FileDialogue.py0000644000175000017500000000315311155777556014560 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: File dialogue ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import pygtk, dissy pygtk.require('2.0') import gtk, gobject from dissy.Config import * from dissy.File import File import dissy.FunctionModel class FileDialogue: def __init__(self, controller): file_open_dialog = gtk.FileChooserDialog(title="Open object file", action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) filter = gtk.FileFilter() filter.set_name("Object files") filter.add_pattern("*.o") filter.add_mime_type("application/x-object") filter.add_mime_type("application/x-executable") file_open_dialog.add_filter(filter) filter = gtk.FileFilter() filter.set_name("All files") filter.add_pattern("*") file_open_dialog.add_filter(filter) if file_open_dialog.run() == gtk.RESPONSE_OK: filename = file_open_dialog.get_filename() controller.loadFile(filename) file_open_dialog.destroy() else: file_open_dialog.destroy() return dissy-9/dissy/mips.py0000644000175000017500000000472511155777556013205 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: MIPS arch specific stuff ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import dissy.architecture, re from dissy.architecture import Architecture REGISTER_REGEXP = "(?:[tsakv]{1}[0-9]{1})|sp|ra|fp|gp|at" ADDRESS_REGEXP = "[0-9,a-f,A-F]+" mips_jumps = ['bgez', 'bnez', 'beqz', 'blez', 'bgez', 'bltz', 'bgtz', 'bc1f', 'bc1t', 'beq', 'bne', 'b', 'jal', 'j', ] mips_calls = ['jal'] instr_descriptions = { 'lbu': 'Load Unsigned Byte', 'lb': 'Load signed Byte', 'li': 'Load Immediate value to destination register', 'lui' : 'Load Upper Immediate (set destination to v << 16)', 'move' : 'Copy between registers', 'jal' : 'Jump And Link, jump to destination and store return address in ra (r31)', 'or' : 'Bitwise or', 'sb' : 'Store Byte to memory', 'sw' : 'Store 32-bit word to memory', 'sh' : 'Store 16-bit word to memory', 'lb' : 'Load Byte from memory, signed', 'lw' : 'Load 32-bit value from memory', 'lh' : 'Load 16-bit value from memory, signed', 'lbu' : 'Load 16-bit value from memory, unsigned', 'lhu' : 'Load 16-bit value from memory, unsigned', } class MipsArchitecture(Architecture): def __init__(self): Architecture.__init__(self, mips_jumps, mips_calls) self.jumpRegexp = re.compile("(?:(" + REGISTER_REGEXP + "),)+" + "(" + ADDRESS_REGEXP + ")"); def getJumpDestination(self, insn, args): r = self.jumpRegexp.match(args) if r == None: return Architecture.getJumpDestination(self, insn, args) return Architecture.getJumpDestination(self, insn, r.group(2)) def getInstructionInfo(self, instruction): opcode = instruction.getOpcode() args = str(instruction.getArgs()) description = instr_descriptions.get(instruction.getOpcode(), '') return {'shortinfo': opcode + " " + args, 'description': description, } dissy-9/dissy/File.py0000644000175000017500000001465211155777556013114 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Describes one file ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import cgi, os, sys sys.path.append(".") import dissy, dissy.architecture from dissy.Function import * from dissy.Instruction import * from dissy.Data import * from dissy.Entity import AddressableEntity ADDRESS_REGEXP = "[0-9,a-f,A-F]+" FUNCTION_REGEXP = "(?:[.]*)[_,0-9,a-z,A-Z,\:,\*,\,\(,\), ,<,>,~,\.]+" symbolRegexp = re.compile("(" + ADDRESS_REGEXP + ")* *(" + ADDRESS_REGEXP + ")* ([A,B,C,D,G,I,N,R,S,T,U,V,W,a,b,c,d,g,i,n,r,s,t,u,v,w,-,?]{1}) ("+ FUNCTION_REGEXP + "){1}") # Followed by size, but let's just skip it linuxKernelCrashRegexp = re.compile("(" + FUNCTION_REGEXP + "){1}" + "\+[0x]*(" + ADDRESS_REGEXP + "){1}") TYPE_UNDEFINED = 0 TYPE_TEXT = 1 TYPE_RODATA = 2 TYPE_DATA = 3 TYPE_BSS = 4 typeToClass = { TYPE_TEXT : Function, TYPE_RODATA : RoData, TYPE_DATA : Data, TYPE_BSS : Bss, } def getObjType(s): if s in ('u', 'U'): return TYPE_UNDEFINED elif s in ('d', 'D'): return TYPE_DATA elif s in ('r', 'R'): return TYPE_RODATA elif s in ('b', 'B', 's', 'S', 'c', 'C'): return TYPE_BSS elif s in ('t', 'T'): return TYPE_TEXT return TYPE_DATA class File(AddressableEntity): def __init__(self, filename=None, baseAddress = 0): AddressableEntity.__init__(self, baseAddress = baseAddress) self.symbols = [] self.functions = [] self.data = [] self.filename = filename self.arch = "intel" if filename != None: self.arch = dissy.architecture.getArchitecture(self.getArchStr()) if self.hasSymbols(): self.parse() else: self.parseNoSymbols() def getArchStr(self): "Get the architecture of the file" arch = "intel" # Assume Intel architecture f = os.popen("%s -h --wide %s" % (config.readelf, self.filename)) for line in f: words = line.split() if len(words) >= 2 and words[0] == "Machine:": arch = words[1].lower() break f.close() return arch def lookup_int(self, address): for sym in self.symbols: extents = sym.getExtents() if address >= extents[0] and address < extents[1]: return sym return None def lookup_str(self, label): for sym in self.symbols: if label == sym.getLabel(): return sym return None def lookup(self, param): "Lookup a label or an address" if isinstance(param, long): return self.lookup_int(param) return self.lookup_str(param) def getArch(self): return self.arch def hasSymbols(self): return True def link(self): for fn in self.functions: unresolved = fn.link() for insn in unresolved: other = self.lookup(insn.getAddress()) if other: insn.linkTo(other) def parse(self): "Parse the functions from this file (with symbols)" f = os.popen("%s --numeric-sort --demangle --print-size %s" % (config.nm, self.filename)) lines = f.readlines() f.close() for line in lines: r = symbolRegexp.match(line) if r == None: continue address = 0 size = 0 if r.group(1) != None: address = long("0x" + r.group(1), 16) if r.group(2) != None: size = long("0x" + r.group(2), 16) objType = getObjType(r.group(3)) label = cgi.escape(r.group(4)) if size == 0: idx = lines.index(line) if idx < len(lines)-1: # The size is next line.adr - this line.adr s = symbolRegexp.match(lines[idx+1]) if s == None or s and s.group(1) == None: # Nope, doesn't work... continue nextAdr = long("0x" + s.group(1), 16) size = nextAdr - address else: # FIXME: This is a bug - the last symbol will be too small. # This can be fixed by e.g., using the section size size = 0 if objType == TYPE_UNDEFINED: continue if objType == TYPE_TEXT: sym = typeToClass[objType](self, address, label, size) self.functions.append(sym) self.symbols.append(sym) # else: # sym = typeToClass[objType](self, address, label, size) # self.data.append(sym) def parseNoSymbols(self): "Parse the functions from this file (without symbols)" callDests = [] f = os.popen("%s --disassemble --demangle %s" % (config.objdump, self.filename)) for line in f: r = insnRegExp.match(line) if r != None: if self.arch.isCall(r.group(3)): dst = self.arch.getJumpDestination(r.group(3), r.group(4)) if dst != None: callDests.append(dst) # Sort the calls callDests.sort() count = 0 for call in callDests[:-1]: next = callDests[callDests.index(call)+1] if next-call == 0: # Empty continue fn = Function(self, call, "func%d" % (count), next-call) # This has not been prepared yet... fn.stream = None self.functions.append(fn) count = count + 1 f.close() def getFunctions(self): return self.functions def getData(self): return self.functions def __str__(self): out = "%s: " % (self.filename) for fn in self.functions: out = out + str(fn) return out if __name__ == "__main__": if len(sys.argv) < 2: print "Arg: filename (ELF)" sys.exit(1) f = File(sys.argv[1]) f.parse() dissy-9/dissy/JumpStreamHandler.py0000644000175000017500000000371311155777556015616 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Jump streams ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### INVALID=0 START=1 RUNNING=2 END=3 EXTRA=4 EXTRA2=5 class JumpStream: def __init__(self): self.state = INVALID self.insnTuple = (None,None) def start(self, insnTuple): self.state = START self.insnTuple = insnTuple def running(self): self.state = RUNNING def end(self): self.state = END def invalid(self): self.state = INVALID def extra(self): self.state = EXTRA def extra2(self): self.state = EXTRA2 class JumpStreamHandler: def __init__(self): self.streams = [] for i in range(0,3): self.streams.append(JumpStream()) def alloc(self): for stream in self.streams: if stream.state == INVALID or stream.state == END: return stream for stream in self.streams: stream.extra() return None def update(self, insn): for stream in self.streams: if stream.state == START and insn != stream.insnTuple[0]: stream.running() elif stream.state == END: stream.invalid() elif stream.state == EXTRA: stream.extra2() elif stream.state == EXTRA2: stream.running() # If this is the destination, switch to the end state if insn == stream.insnTuple[1]: stream.end() def getStateTuple(self): return (self.streams[0].state, self.streams[1].state, self.streams[2].state) dissy-9/dissy/history.py0000644000175000017500000000514111155777556013727 0ustar skaska###################################################################### ## ## Copyright (C) 2007, Simon Kagstrom ## ## Author: Simon Kagstrom ## Description: History implementation ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### class History: def __init__(self): self.history = [] self.index = 0 self.enabled = True def add(self, entry): "Add an entry to the history" # Don't add twice if not self.enabled or self.history != [] and self.history[self.index-1] == entry: return None if self.index == 1 and len(self.history) > 1: self.history = [] self.index = 0 self.history = self.history[ : self.index] + [entry] self.index = self.index + 1 return entry def enable(self): self.enabled = True def disable(self): self.enabled = False def back(self): "Go back one step" if self.index-1 <= 0: raise Exception("End of history") self.index = self.index - 1 return self.history[self.index-1] def forward(self): "Go forward one step" if self.index >= len(self.history): raise Exception("End of history") self.index = self.index + 1 return self.history[self.index-1] def current(self): "Get the current entry" return self.history[self.index] def isFirst(self): "Is this the first entry?" return self.index <= 0 def isLast(self): "Is this the last entry?" return self.index >= len(self.history) def getAllEntries(self): "Return everything in the current history" return self.history if __name__ == "__main__": h = History() print "Adding some entries" h.add(1) h.add(2) h.add(3) print h.getAllEntries() print "Back one step:", h.back() h.add(4) print "Add, all entries:", h.getAllEntries() print "Back two, forward" print h.back() print h.back() try: # Should raise print h.back() except: print "Got expected exception (back)" print h.forward() print h.forward() try: print h.forward() except: print "Got expected exception (fwd)" print "All entries", h.getAllEntries() h.back() h.back() h.add(5) print h.getAllEntries() h.add(6) print h.getAllEntries() dissy-9/dissy/FunctionModel.py0000644000175000017500000000306711155777556015001 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Display the functions ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import gtk, gobject class InfoModel: """ The model class holds the information we want to display """ def __init__(self, fileContainer): """ Sets up and populates our gtk.TreeStore """ self.tree_store = gtk.TreeStore( gobject.TYPE_STRING, gobject.TYPE_LONG, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT ) # Create the TreeStore for item in fileContainer.getFunctions(): # Insert functions item.iter = self.tree_store.append(None, ("0x%08x" % item.getAddress(), item.getSize(), item.getLabel(), item ) ) def getModel(self): """ Returns the model """ if self.tree_store: return self.tree_store else: return None dissy-9/dissy/PreferencesDialogue.py0000644000175000017500000001217011155777556016141 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Preferences dialog ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import pygtk # General warning: The code in this file is pure horror! Go somewhere else # if you suffer from heart problems. pygtk.require('2.0') import gtk, gobject from Config import * def colorToString(color): return "#%04x%04x%04x" % (color.red, color.green, color.blue) class PreferencesDialogue: def __init__(self, main_program): self.main_program = main_program dialog = gtk.Dialog("%s - Preferences" % (PROGRAM_NAME)) defaults = gtk.Button("Defaults") cancel = gtk.Button("Cancel", gtk.STOCK_CANCEL) ok = gtk.Button("OK", gtk.STOCK_OK) table = gtk.Table(3, 3, False) objdump = gtk.Entry() readelf = gtk.Entry() nm = gtk.Entry() insnColor = gtk.ColorButton(gtk.gdk.color_parse(config.insnFgColor)) markupColor = gtk.ColorButton(gtk.gdk.color_parse(config.markupFgColor)) highLevelColor = gtk.ColorButton(gtk.gdk.color_parse(config.highLevelCodeFgColor)) showHighLevel = gtk.CheckButton("Show high level code") showInstructionInfo = gtk.CheckButton("Show instruction information") cancel.connect("clicked", lambda w: dialog.destroy()) ok.connect("clicked", self.okSelected, dialog, objdump, readelf, nm, showHighLevel, showInstructionInfo, insnColor, markupColor, highLevelColor) defaults.connect("clicked", self.defaultsSelected, objdump, readelf, nm, showHighLevel, showInstructionInfo, insnColor, markupColor, highLevelColor) objdump.set_text(config.objdump) readelf.set_text(config.readelf) nm.set_text(config.nm) showHighLevel.set_active(config.showHighLevelCode) showInstructionInfo.set_active(config.showInstructionInformationBox) table.attach(gtk.Label("Objdump:"), 0, 1, 0, 1, ypadding=2) table.attach(gtk.Label("Readelf:"), 0, 1, 1, 2, ypadding=2) table.attach(gtk.Label("nm:"), 0, 1, 2, 3, ypadding=2) table.attach(gtk.Label("Instruction color:"), 0, 1, 3, 4, ypadding=2) table.attach(gtk.Label("Highlight color:"), 0, 1, 4, 5, ypadding=2) table.attach(gtk.Label("High-level code color:"), 0, 1, 5, 6, ypadding=2) table.attach(objdump, 1, 2, 0, 1, ypadding=2) table.attach(readelf, 1, 2, 1, 2, ypadding=2) table.attach(nm, 1, 2, 2, 3, ypadding=2) table.attach(insnColor, 1, 2, 3, 4, ypadding=2) table.attach(markupColor, 1, 2, 4, 5, ypadding=2) table.attach(highLevelColor, 1, 2, 5, 6, ypadding=2) table.attach(showHighLevel, 0, 2, 6, 7, ypadding=6) table.attach(showInstructionInfo, 0, 2, 7, 8, ypadding=6) dialog.vbox.pack_start(table, True, True, 0) dialog.action_area.pack_start(defaults, True, True, 0) dialog.action_area.pack_start(cancel, True, True, 0) dialog.action_area.pack_start(ok, True, True, 0) dialog.show_all() def defaultsSelected(self, widget, objdump, readelf, nm, showHighLevel, showInstructionInfo, insnColor, markupColor, highLevelColor): config.restoreAllDefaults() objdump.set_text(config.objdump) readelf.set_text(config.readelf) nm.set_text(config.nm) insnColor.set_color( gtk.gdk.color_parse(config.getDefault("insnFgColor")) ) markupColor.set_color( gtk.gdk.color_parse(config.getDefault("markupFgColor")) ) highLevelColor.set_color( gtk.gdk.color_parse(config.getDefault("highLevelCodeFgColor")) ) showHighLevel.set_active(config.showHighLevelCode) showInstructionInfo.set_active(config.showInstructionInfo) def okSelected(self, widget, dialog, objdump, readelf, nm, showHighLevelCode, showInstructionInfo, insnColor, markupColor, highLevelColor): if objdump.get_text() == "": config.objdump = config.getDefault("objdump") else: config.objdump = objdump.get_text() if readelf.get_text() == "": config.readelf = config.getDefault("readelf") else: config.readelf = readelf.get_text() if nm.get_text() == "": config.nm = config.getDefault("nm") else: config.nm = nm.get_text() config.insnFgColor = colorToString(insnColor.get_color()) config.markupFgColor = colorToString(markupColor.get_color()) config.highLevelCodeFgColor = colorToString(highLevelColor.get_color()) config.showHighLevelCode = showHighLevelCode.get_active() config.showInstructionInformationBox = showInstructionInfo.get_active() config.save() dialog.destroy() self.main_program.setInformationBox() dissy-9/dissy/intel.py0000644000175000017500000000666011155777556013350 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Intel arch specific stuff ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import sys, architecture from dissy.architecture import Architecture intel_jumps = ['jmp', 'call' ] intel_calls = ['call'] intel_conditionflag_setters = ['cmp', 'cmpb', 'cmps', 'cmpw', 'cmpl', 'cmpq', 'test'] intel_conditionflag_users = [''] intel_instr_descriptions = { 'push': 'Push Word onto Stack', 'pushl': 'Push Long onto Stack', 'mov': 'Move', 'movl': 'Move Long', 'cmp': 'Compare', 'cmpb': 'Compare Byte', 'lea': 'Load Effective Address', 'add': 'Add', 'jmp': 'Unconditional Jump', 'pop': 'Pop Word off Stack', 'ret': 'Return from Procedure', 'sub': 'Subtract', 'xor': 'eXclusive Or', 'and': 'Logical And', 'nop': 'NoOp', 'call': 'Procedure Call', 'hlt': 'Halt', 'test': """Test for Bit Pattern Performs a logical AND of the two operands, updating the condition flags without saving the results""", 'leave': 'Restore stack for procedure exit', 'xchg': 'Exchange', 'sar': 'Shift Arithmetic Right', 'sal': 'Shift Arithmetic Left', 'shr': 'Shift Logical Right', 'shl': 'Shift Logical Left', } intel_lists_inited = False if not intel_lists_inited: conditional_instructions = { 'j': "Jump if %s", } conditions = { 'a': 'Above', 'ae': 'Above or Equal', 'b': 'Below', 'be': 'Below or Equal', 'c': 'Carry set', 'cxz': 'CX Zero', 'e': 'Equal', 'g': 'Greater (Signed)', 'ge': 'Greater or Equal (Signed)', 'l': 'Less (Signed)', 'le': 'Less or Equal (Signed)', 'na': 'Not Above', 'nae': 'Not Above or Equal', 'nb': 'Not Below', 'nbe': 'Not Below or Equal', 'nc': 'Not Carry', 'ne': 'Not Equal', 'ng': 'Not Greater (Signed)', 'nge': 'Not Greater or Equal (Signed)', 'nl': 'Not Less (Signed)', 'nle': 'Not Less or Equal (Signed)', 'no': 'Not Overflow (Signed)', 'np': 'No Parity', 'ns': 'Not Signed (Signed)', 'nz': 'Not Zero', 'o': 'Overflow (Signed)', 'p': 'Parity', 'pe': 'Parity Even', 'po': 'Parity Odd', 's': 'Signed (Signed)', 'z': 'Zero', } for i in ['j']: for c in conditions: intel_instr_descriptions[i + c] = conditional_instructions[i] % (conditions[c]) intel_conditionflag_users += [i + c] intel_jumps += [i + c] class IntelArchitecture(architecture.Architecture): def __init__(self): architecture.Architecture.__init__(self, intel_jumps, intel_calls, intel_conditionflag_setters, intel_conditionflag_users) def getInstructionInfo(self, instruction): opcode = instruction.getOpcode() args = str(instruction.getArgs()) description = intel_instr_descriptions.get(instruction.getOpcode(), '') return {'shortinfo': opcode + " " + args, 'description': description, } dissy-9/dissy/Bookmark.py0000644000175000017500000000125511155777556013775 0ustar skaska###################################################################### ## ## Copyright (C) 2008, Simon Kagstrom ## ## Author: Simon Kagstrom ## Description: Bookmarks in functions/files ## ## Licensed under the terms of GNU General Public License version 2 or ## later. See COPYING file distributed with Dissy for full text of the ## license. ## ###################################################################### class Bookmark: def __init__(self, comment, address): self.comment = comment self.location = location class BookmarkSet: def __init__(self, filename): self.bookmarks = [] self.md5sum = 0 dissy-9/dissy/architecture.py0000644000175000017500000000537011155777556014714 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Base-class for architecture handling ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### class Architecture: """ Architecture base class. Inherit this to implement architecture-specific handling (see intel.py and mips.py) """ def __init__(self, arch_jumps = [], arch_calls = [], arch_conditionflagsetters = [], arch_conditionflagusers = []): self.jumps = {} self.calls = {} # To handle reverse-engineering self.conditionflagsetters = {} self.conditionflagusers = {} for s in arch_jumps: self.jumps[s.strip()] = True for s in arch_calls: self.calls[s.strip()] = True for s in arch_conditionflagsetters: self.conditionflagsetters[s.strip()] = True for s in arch_conditionflagusers: self.conditionflagusers[s.strip()] = True def isJump(self, insn): "Returns true if this instruction is a jump" return insn in self.jumps def isCall(self, insn): "Returns true if this instruction is a call" return insn in self.calls def isConditionFlagSetter(self, insn): "Returns true if this instruction sets the condition flags" return insn in self.conditionflagsetters def isConditionFlagUser(self, insn): "Returns true if this instruction uses the condition flags" return insn in self.conditionflagusers def getJumpDestination(self, insn, args): """Parse the instruction to return the jump destination. The base class only tries to convert the argument to a number. See mips.py for a more advanced translation. """ try: return long(args, 16) except ValueError: pass return None from dissy import mips, intel, ppc, arm def getArchitecture(archStr): if archStr == "intel": return intel.IntelArchitecture() elif archStr == "x86-64": return intel.IntelArchitecture() elif archStr == "i8086": return intel.IntelArchitecture() if archStr == "mips": return mips.MipsArchitecture() if archStr == "ppc": return ppc.PpcArchitecture() if archStr == "powerpc": return ppc.PpcArchitecture() if archStr == "arm": return arm.ArmArchitecture() if archStr == "arm26": return arm.ArmArchitecture() return Architecture([]) dissy-9/dissy/Config.py0000644000175000017500000000555111155777556013440 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Configuration storage ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import cPickle, os, os.path PROGRAM_NAME="Dissy" PROGRAM_VERSION="9" PROGRAM_URL="http://dissy.googlecode.com" class Config: def __init__(self): self.configfile = os.path.expanduser("~/.dissy/config.dump") self.defaults = {} self.defaults["markupFgColor"] = "red" self.defaults["insnFgColor"] = "blue" self.defaults["highLevelCodeFgColor"] = "grey50" self.defaults["showHighLevelCode"] = True self.defaults["showInstructionInformationBox"] = True self.defaults["objdump"] = "objdump" self.defaults["readelf"] = "readelf" self.defaults["nm"] = "nm" self.defaults["version"] = PROGRAM_VERSION self.restoreAllDefaults() def restoreAllDefaults(self): self.markupFgColor = self.getDefault("markupFgColor") self.insnFgColor = self.getDefault("insnFgColor") self.highLevelCodeFgColor = self.getDefault("highLevelCodeFgColor") self.showHighLevelCode = self.getDefault("showHighLevelCode") self.showInstructionInformationBox = self.getDefault("showInstructionInformationBox") self.objdump = self.getDefault("objdump") self.readelf = self.getDefault("readelf") self.nm = self.getDefault("nm") def copy(self, other): self.markupFgColor = other.markupFgColor self.insnFgColor = other.insnFgColor self.highLevelCodeFgColor = other.highLevelCodeFgColor self.showHighLevelCode = other.showHighLevelCode self.showInstructionInformationBox = getattr(other, "showInstructionInformationBox", True) self.objdump = other.objdump self.readelf = other.readelf self.nm = other.nm def getFromEnvironment(self): od = os.getenv("OBJDUMP") if od != None: self.objdump = od def getDefault(self, which): return self.defaults[which] def load(self): try: f = open(self.configfile) other = cPickle.load(f) f.close() self.copy(other) except IOError: pass def save(self): try: os.makedirs(os.path.dirname(self.configfile), 0700) except OSError: # Already exists pass f = open(self.configfile, "w") cPickle.dump(self, f) f.close() config = Config() # Load the old configuration config.load() config.getFromEnvironment() dissy-9/dissy/ppc.py0000644000175000017500000000251711155777556013014 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Andrew May ## Description: PPC arch specific stuff ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import sys, architecture from dissy.architecture import Architecture ppc_jumps = [ 'beq', 'bne', 'bge', 'b', 'bl', 'beq-', 'bne-', 'bge-', 'blt-', 'ble-', 'bdnz-', 'beq+', 'bne+', 'bge+', 'blt+', 'bdnz+', 'ble+', 'b-', ] ppc_calls = ['bl'] class PpcArchitecture(Architecture): def __init__(self): Architecture.__init__(self, ppc_jumps, ppc_calls) def getJumpDestination(self, insn, args): r = args.split(",") if len(r) == 1: return Architecture.getJumpDestination(self, insn, args) return Architecture.getJumpDestination(self, insn, r[-1]) dissy-9/dissy/InstructionModelHighlighter.py0000644000175000017500000000625711155777556017720 0ustar skaska###################################################################### ## ## Copyright (C) 2009, Mads Chr. Olesen ## ## Author: Mads Chr. Olesen ## Description: Filter-decorator for InstructionModel ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### from Config import * from dissy import InstructionModel from Instruction import Instruction import re class InstructionModelHighlighter: def __init__(self): pass def highlight(self, row, curInstruction): """Possibly modify the columns of row""" pass class SearchwordHighlighter(InstructionModelHighlighter): """Highlights anything that matches the regular expression given""" def __init__(self, searchPattern=None): InstructionModelHighlighter.__init__(self) self.setSearchPattern(searchPattern) def setSearchPattern(self, searchPattern): if searchPattern: #Match anything not in a tag (> occurs after match, but before a <) self.searchPattern = re.compile(searchPattern + "(?![^<]*>)") else: self.searchPattern = None def markup(self, pattern, string, color): s = "" last = 0 for i in pattern.finditer(string): span = i.span() s = s + string[last:span[0]] + '' + string[span[0] : span[1] ] + '' last = span[1] else: s = s + string[last:] return s def highlight(self, row, curInstruction): insn = row[InstructionModel.COLUMN_INSTRUCTION] strRep = row[InstructionModel.COLUMN_STR_REPRESENTATION] if self.searchPattern: strRep = self.markup(self.searchPattern, strRep, config.markupFgColor) row[InstructionModel.COLUMN_STR_REPRESENTATION] = strRep class ConditionFlagHighlighter(InstructionModelHighlighter): """Highlights the instruction that may have set the processor condition flags.""" def __init__(self): InstructionModelHighlighter.__init__(self) def highlight(self, row, curInstruction): if not curInstruction: return insn = row[InstructionModel.COLUMN_INSTRUCTION] arch = curInstruction.getFunction().getFile().getArch() #import pdb; pdb.set_trace() if not arch.isConditionFlagSetter(insn.getOpcode()) or \ not arch.isConditionFlagUser(curInstruction.getOpcode()): return if curInstruction == insn: return inthezone = False for i in curInstruction.getFunction().getAll(): if not isinstance(i, Instruction): continue if inthezone and arch.isConditionFlagSetter(i.getOpcode()): return if i == insn: inthezone = True if inthezone and i == curInstruction: row[InstructionModel.COLUMN_ADDR] = '' + \ row[InstructionModel.COLUMN_ADDR] + \ '' dissy-9/dissy/Instruction.py0000644000175000017500000000474511155777556014560 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Instruction class ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### from dissy.Entity import Entity, AddressableEntity class Instruction(AddressableEntity): def __init__(self, function, address, encoding, insn, args): AddressableEntity.__init__(self, address = address, endAddress = address, baseAddress = function.baseAddress) self.function = function self.encoding = encoding self.insn = insn self.args = args self.outLinkAddress = None self.outLink = None arch = self.function.getFile().getArch() if arch.isJump(insn): val = arch.getJumpDestination(insn, args) if val != None: self.addLinkOut( val + self.baseAddress ) def getFunction(self): return self.function def getOpcode(self): return self.insn def getArgs(self): if self.args != None: return self.args return "" def getOutLinkAddress(self): return self.outLinkAddress def getOutLink(self): return self.outLink def getInLinks(self): return self.inLink def hasLink(self): return self.outLinkAddress != None def addLinkIn(self, insn): pass # Implement this if needed #self.linksIn.append(insn) def addLinkOut(self, obj): self.outLinkAddress = obj def linkTo(self, other): self.outLink = other def link(self): if not self.hasLink(): raise Exception other = self.function.lookup(self.getOutLinkAddress()) if other: self.linkTo(other) other.addLinkIn(self) else: # External reference other = self.function.getFile().lookup(self.getOutLinkAddress()) self.linkTo(other) if other == None: return False self.label = other.getLabel() return True def __str__(self): out = ("0x%08x " % self.address) + " " + str(self.insn) if self.args != None: out += str(" " * (20-len(out))) + str(self.args) return out dissy-9/dissy/StrEntity.py0000644000175000017500000000133511155777556014174 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: String entity ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### from dissy.Entity import Entity class StrEntity(Entity): def __init__(self, fn, string): self.string = string self.function = fn def getFunction(self): return self.function def __str__(self): return self.string dissy-9/dissy/__init__.py0000644000175000017500000000001211155777556013755 0ustar skaska# Nothing dissy-9/dissy/Data.py0000644000175000017500000000615411155777556013104 0ustar skaska###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: Describes data symbols ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import re, os, cgi, curses.ascii from dissy.Config import config from dissy.Entity import Entity, AddressableEntity from dissy.StrEntity import StrEntity class DataBase(AddressableEntity): def __init__(self, fileContainer, address, label, size=0): AddressableEntity.__init__(self, address = address, endAddress = address + size, baseAddress = fileContainer.baseAddress) self.label = label self.file = fileContainer self.data = [] self.string = "" self.stream = None self.type = "Unknown" def parse(self): pass def toNumericValue(self): val = 0 if len(self.data) in (1,2,4,8): for i in range(0, len(self.data)): val = val + self.data[i] << (len(self.data) - i)*8 return val def toBytes(self): return self.data def toString(self): return self.string class Data(DataBase): def __init__(self, fileContainer, address, label, size=0): DataBase.__init__(self, fileContainer, address, label, size) self.type = "Initialized data" def parse(self): extents = self.getExtents() s = "%s --wide --demangle --full-contents --start-address=0x%x --stop-address=0x%x %s" % (config.objdump, extents[0], extents[1], self.file.filename) self.stream = os.popen(s) for line in self.stream: # Weed away some unneeded stuff if line.startswith("Contents of section ") or line.startswith("%s: " % (self.file.filename)): continue if line.strip() == "": continue words = line.split() for word in words[1:max(4, len(words))]: for i in range(0, len(word), 2): try: val = int(word[i:i+2], 16) self.data.append(val) except: # For "short" data continue if curses.ascii.isprint(val): self.string += "%c" % curses.ascii.ascii(val) else: self.string += "." self.stream.close() class Bss(DataBase): def __init__(self, fileContainer, address, label, size=0): DataBase.__init__(self, fileContainer, address, label, size) self.type = "Uninitialized data" def parse(self): size = self.getSize() self.data = [ 0 ] * size self.string = "." * size class RoData(Data): def __init__(self, fileContainer, address, label, size=0): Data.__init__(self, fileContainer, address, label, size) self.type = "Read-only data" dissy-9/COPYING0000644000175000017500000004311011155777556011552 0ustar skaska GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. dissy-9/MANIFEST0000644000175000017500000000074311155777556011655 0ustar skaskaCOPYING README setup.py dissy/Config.py dissy/Entity.py dissy/File.py dissy/FileDialogue.py dissy/Function.py dissy/FunctionModel.py dissy/Instruction.py dissy/InstructionModel.py dissy/JumpStreamHandler.py dissy/PreferencesDialogue.py dissy/StrEntity.py dissy/__init__.py dissy/architecture.py dissy/intel.py dissy/mips.py scripts/dissy gfx/red_arrow_left.png gfx/red_line.png gfx/red_start_down.png gfx/red_arrow_right.png gfx/red_plus.png gfx/red_start_up.png menubar.xml dissy.1 dissy-9/scripts/0000755000175000017500000000000011155777556012207 5ustar skaskadissy-9/scripts/dissy0000744000175000017500000005620511155777556013276 0ustar skaska#!/usr/bin/env python ###################################################################### ## ## Copyright (C) 2006, Blekinge Institute of Technology ## ## Author: Simon Kagstrom ## Description: The main program ## ## Licensed under the terms of GNU General Public License version 2 ## (or later, at your option). See COPYING file distributed with Dissy ## for full text of the license. ## ###################################################################### import pygtk, pango, getopt, sys, os, cgi, re sys.path.append(".") sys.path = ['/home/ska/projects/dissy/trunk/'] + sys.path pygtk.require('2.0') import gtk, gobject from dissy.Config import * from dissy.File import File from dissy.File import linuxKernelCrashRegexp from dissy.Entity import Entity from dissy.StrEntity import StrEntity from dissy.Instruction import Instruction from dissy.Function import Function from dissy.PreferencesDialogue import PreferencesDialogue from dissy.FileDialogue import FileDialogue from dissy.history import History from dissy import FunctionModel from dissy import InstructionModel from dissy import InstructionModelHighlighter NUM_JUMP_COLUMNS=3 # Navigation history history = History() def lookupFile(name): pathsToSearch = ['.', '/usr/local/share/%s' % (PROGRAM_NAME).lower(), '/usr/share/%s' % (PROGRAM_NAME).lower()] for path in pathsToSearch: fullPath = "%s/%s" % (path, name) try: st = os.lstat(fullPath) return fullPath except: pass return None def loadFile(fileName): try: f = open(lookupFile(fileName)) out = f.read() f.close() return out except: return None # Taken from the cellrenderer.py example class GUI_Controller: """ The GUI class is the controller for Dissy """ def __init__(self, inFile=None): if inFile == None: self.fileContainer = File(baseAddress=baseAddress) inFile = "" else: self.fileContainer = File(inFile, baseAddress=baseAddress) self.searchwordHighlighter = InstructionModelHighlighter.SearchwordHighlighter() self.conditionFlagHighlighter = InstructionModelHighlighter.ConditionFlagHighlighter() self.highlighters = [ self.searchwordHighlighter, self.conditionFlagHighlighter, ] functionModel = FunctionModel.InfoModel(self.fileContainer).getModel() self.instructionModel = InstructionModel.InfoModel(None, highlighters=self.highlighters) insnModel = self.instructionModel.getModel() self.display = DisplayModel(self) icon = None icon_name = lookupFile('gfx/icon.svg') if icon_name != None: icon = gtk.gdk.pixbuf_new_from_file(icon_name) icon = icon.scale_simple(64, 64, gtk.gdk.INTERP_BILINEAR) # setup the main window self.root = gtk.Window(type=gtk.WINDOW_TOPLEVEL) self.root.set_title("%s - %s" % (PROGRAM_NAME, inFile)) self.root.set_icon(icon) self.root.connect("destroy", self.destroy_cb) self.root.set_default_size(900, 600) # Boxes for the widgets vbox = gtk.VBox() hbox = gtk.HBox() # menubar self.uimgr = gtk.UIManager() self.accelgroup = self.uimgr.get_accel_group() self.root.add_accel_group(self.accelgroup) # Create an ActionGroup self.actiongroup = gtk.ActionGroup('UIManagerExample') # Create actions self.actiongroup.add_actions([('Quit', gtk.STOCK_QUIT, '_Quit', None, 'Quit the Program', self.destroy_cb), ('Open', gtk.STOCK_OPEN, '_Open', None, 'Open a file', lambda w: FileDialogue(self)), ('Reload', None, '_Reload', 'r', 'Reload a file', lambda w: self.loadFile() ), ('File', None, '_File'), ('Options', None, '_Options'), ('Navigation', None, '_Navigation'), ('Forward', gtk.STOCK_GO_FORWARD, '_Forward', 'Right', 'Navigate forwards in history', lambda w: self.forward()), ('Back', gtk.STOCK_GO_BACK, '_Back', 'Left', 'Navigate backwards in history', lambda w: self.back()), ('Preferences', gtk.STOCK_PREFERENCES, '_Preferences', None, 'Configure preferences for %s' % (PROGRAM_NAME), self.preferencesDialogue), ('Toggle source', None, '_Toggle source', None, 'Toggle the showing of high-level source', self.toggleHighLevelCode), ('Toggle information box', None, 'Toggle _information box', None, 'Toggle the showing of the instruction information box', self.toggleInformationBox), ('Help', None, '_Help'), ('About', gtk.STOCK_ABOUT, '_About', None, 'About %s' % PROGRAM_NAME, self.about), ]) # Add the actiongroup to the uimanager self.uimgr.insert_action_group(self.actiongroup, 0) self.uimgr.add_ui_from_string(loadFile("menubar.xml")) # Pastebin for quick lookup of symbols pasteBin = gtk.combo_box_entry_new_text() # Pattern matcher patternMatchBin = gtk.Entry() # Move to the pasteBin with Ctrl-l pasteBin.child.add_accelerator("grab-focus", self.accelgroup, ord('L'), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) # Move to the pattern match bin with Ctrl-k patternMatchBin.add_accelerator("grab-focus", self.accelgroup, ord('K'), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) pasteBin.child.connect("activate", self.pasteBinCallback, pasteBin) patternMatchBin.connect("activate", self.patternMatchBinCallback, patternMatchBin) tooltips = gtk.Tooltips() tooltips.set_tip(pasteBin.child, "Lookup an address or symbol (shortcut Ctrl-l)") tooltips.set_tip(patternMatchBin, "Enter a pattern to highlight (shortcut Ctrl-k)") hbox.pack_start(gtk.Label("Lookup"), expand=False, padding=2) hbox.pack_start(pasteBin) hbox.pack_start(gtk.Label("Highlight"), expand=False, padding=2) hbox.pack_start(patternMatchBin, expand=False, padding=2) vbox.pack_start(self.uimgr.get_widget("/MenuBar"), expand=False) vbox.pack_start(hbox, expand=False, padding=2) sw_up = gtk.ScrolledWindow() sw_up.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.sw_down = gtk.ScrolledWindow() self.sw_down.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.vpaned = gtk.VPaned() self.vpaned.set_position(650/3) vbox.pack_start(self.vpaned) # Get the model and attach it to the view self.functionView, self.instructionView = self.display.makeViews( functionModel, insnModel ) # Add instruction info section self.hpaned_down = gtk.HPaned() self.hpaned_down.set_position(900/3*2) self.vbox_instr_info = gtk.VBox() self.instr_info_label = gtk.Label("Instruction Information") self.instr_info_label.set_use_markup(True) self.vbox_instr_info.pack_start(self.instr_info_label, expand=False) self.instr_info_description = gtk.TextView() self.instr_info_description.set_editable(False) self.instr_info_description.set_wrap_mode(gtk.WRAP_WORD) self.vbox_instr_info.pack_start(self.instr_info_description) self.sw_down.add(self.instructionView) self.hpaned_down.pack1(self.sw_down, resize=True) self.hpaned_down.pack2(self.vbox_instr_info, resize=False) # Add our view into the scrolled window sw_up.add(self.functionView) self.vpaned.add1(sw_up) self.vpaned.add2(self.hpaned_down) self.root.add(vbox) # Setup focus chains (no tab-to-focus in the information box) vbox.set_focus_chain([ self.vpaned ]) self.hpaned_down.set_focus_chain([ self.sw_down ]) self.root.show_all() # Make the info box visible or not depending on the configuration self.setInformationBox() def loadFile(self, filename=None): if filename == None: if not self.fileContainer: return filename = self.fileContainer.filename self.root.set_title("%s - %s" % (PROGRAM_NAME, filename)) self.fileContainer = File(filename, baseAddress=baseAddress) self.functionView.set_model( FunctionModel.InfoModel(self.fileContainer).getModel() ) def loadTimeoutCallback(self, o): self.fileContainer, done = o.parse(10) self.functionView.set_model( FunctionModel.InfoModel( self.fileContainer ).getModel() ) return done def about(self, w=None): "Display the about dialogue" about = gtk.AboutDialog() about.set_name(PROGRAM_NAME) about.set_version("v%s" % (PROGRAM_VERSION) ) about.set_copyright("(C) Simon Kagstrom, 2006-2009") about.set_website(PROGRAM_URL) about.run() about.hide() def redisplayFunction(self): try: fnCursor = self.functionView.get_cursor()[0] curFunction = self.functionView.get_model()[fnCursor][3] except TypeError: # There is no function currently being shown return insnCursor = self.instructionView.get_cursor()[0] curInstruction = None if insnCursor: curInstruction = self.instructionView.get_model()[insnCursor][InstructionModel.COLUMN_INSTRUCTION] self.instructionModel.setCurInstruction(curInstruction) self.instructionModel.refreshModel() try: self.instructionView.set_cursor(insnCursor) self.instructionView.scroll_to_cell(insnCursor) except: # If nothing is selected this will fail pass def toggleHighLevelCode(self, widget): config.showHighLevelCode = not config.showHighLevelCode config.save() try: fnCursor = self.functionView.get_cursor()[0] curFunction = self.functionView.get_model()[fnCursor][3] except TypeError: # There is no function currently being shown return self.instructionView.set_model( InstructionModel.InfoModel(curFunction).getModel() ) self.redisplayFunction() def setInformationBox(self): if config.showInstructionInformationBox: self.vbox_instr_info.show() else: self.vbox_instr_info.hide() def toggleInformationBox(self, widget): config.showInstructionInformationBox = not config.showInstructionInformationBox config.save() self.setInformationBox() def preferencesDialogue(self, widget): pd = PreferencesDialogue(self) def patternMatchBinCallback(self, entry, comboBox): markPattern = entry.get_text() self.searchwordHighlighter.setSearchPattern(markPattern) self.redisplayFunction() def lookupFunction(self, val): function = self.fileContainer.lookup(val) history.disable() if function != None: model = self.functionView.get_model() self.functionView.set_cursor_on_cell(model.get_path(function.iter)) self.functionView.row_activated(model.get_path(function.iter), self.display.viewColumns[0]) # Return if this was just a label lookup if isinstance(val, str): history.enable() return True insn = function.lookup(val) if insn != None: model = self.display.insnView.get_model() self.display.insnView.set_cursor_on_cell(model.get_path(insn.iter)) self.display.insnView.row_activated(model.get_path(insn.iter), self.display.insnColumns[0]) history.enable() return True history.enable() return False def pasteBinCallback(self, entry, comboBox): """ Called to lookup a symbol / address. Looks up a label or an address. """ txt = entry.get_text() comboBox.prepend_text(txt) # Split the input in words and navigate to them for word in txt.split(): # Special-case Linux crashes r = linuxKernelCrashRegexp.match(word) if r != None: fn_name = r.group(1) fn_addend = r.group(2) function = self.fileContainer.lookup(fn_name) if function != None: val=function.getAddress() + long(fn_addend, 16) if self.lookupFunction( val ): history.add(val) continue try: # Try to convert to a number (handle some common cases) word = word.strip("+():") val = long(word, 16) except: val = word if self.lookupFunction(val): history.add(val) def clearInstructionInfo(self): self.instr_info_description.get_buffer().set_text('Not available') def updateInstructionInfo(self, instruction): # Check if this architecture supports instruction info if not hasattr(self.fileContainer.getArch(), "getInstructionInfo"): self.clearInstructionInfo() return instrInfo = self.fileContainer.getArch().getInstructionInfo(instruction) self.instr_info_description.get_buffer().set_text( instrInfo.get('shortinfo', '') + "\n\n" + instrInfo.get('description', '') ) def forward(self, filename=None): try: val = history.forward() except: return return self.lookupFunction(val) def back(self, filename=None): try: val = history.back() except: return return self.lookupFunction(val) def destroy_cb(self, *kw): """ Destroy callback to shutdown the app """ gtk.main_quit() return def run(self): """ run is called to set off the GTK mainloop """ gtk.main() return class DisplayModel: """ Displays the Info_Model model in a view """ def __init__(self, controller): self.controller = controller def makeFunctionView( self, model ): """ Form a view for the Tree Model """ self.functionView = gtk.TreeView( model ) # setup the cell renderers self.functionRenderer = gtk.CellRendererText() self.functionRenderer.set_property("font", "Monospace") self.functionView.connect( 'row-activated', self.functionRowActivated, model ) self.functionView.set_search_column(0) self.functionView.set_search_equal_func(self.functionSearchCallback, model) self.viewColumns = {} # Connect column0 of the display with column 0 in our list model # The renderer will then display whatever is in column 0 of # our model . self.viewColumns[0] = gtk.TreeViewColumn("Address", self.functionRenderer, markup=0) self.viewColumns[1] = gtk.TreeViewColumn("Size", self.functionRenderer, markup=1) self.viewColumns[2] = gtk.TreeViewColumn("Label", self.functionRenderer, markup=2) # The columns active state is attached to the second column # in the model. So when the model says True then the button # will show as active e.g on. for col in self.viewColumns.values(): self.functionView.append_column( col ) return self.functionView def searchCommon(self, entity, key): key = key.lower() comp1 = ("0x%08x" % entity.getAddress()).lower() comp2 = entity.getLabel().lower() if isinstance(entity, Instruction): comp3 = entity.getOpcode() + entity.getArgs() else: comp3 = "" # Lookup either the address or the label when doing an interactive # search if comp1.find(key) != -1 or comp2.find(key) != -1 or comp3.find(key) != -1: return False return True def functionSearchCallback(self, model, column, key, iter, unused): """ Callback for interactive searches. """ entity = model[iter][3] return self.searchCommon(entity, key) def insnSearchCallback(self, model, column, key, iter, unused): """ Callback for interactive searches. """ entity = model[iter][InstructionModel.COLUMN_INSTRUCTION] if isinstance(entity, StrEntity): return True return self.searchCommon(entity, key) def functionRowActivated( self, view, iter, path, model ): """ Run when one row is selected (double-click/space) """ model = self.functionView.get_model() entity = model[iter][3] entity.link() history.add(entity.address) self.controller.instructionModel = InstructionModel.InfoModel(entity, highlighters=self.controller.highlighters) model = self.controller.instructionModel.getModel() self.insnView.set_model( model ) self.insnView.connect( 'row-activated', self.insnRowActivated, model ) def makeInstructionView(self, model): self.insnView = gtk.TreeView( model ) # setup the cell renderers link_renderer = gtk.CellRendererPixbuf() insnRenderer = gtk.CellRendererText() addressRenderer = gtk.CellRendererText() callDstRenderer = gtk.CellRendererText() addressRenderer.set_property("font", "Monospace") insnRenderer.set_property("font", "Monospace") insnRenderer.set_property("width", 500) link_renderer.set_property("width", 22) link_renderer.set_property("height", 22) insnRenderer.set_property("height", 22) callDstRenderer.set_property("font", "Monospace") self.insnView.connect( 'row-activated', self.insnRowActivated, model ) self.insnView.connect( 'move-cursor', self.insnMoveCursor, None ) self.insnView.connect( 'cursor-changed', self.insnCursorChanged ) self.insnView.set_search_column(0) self.insnView.set_search_equal_func(self.insnSearchCallback, model) self.insnColumns = {} # Connect column0 of the display with column 0 in our list model # The renderer will then display whatever is in column 0 of # our model . self.insnColumns[0] = gtk.TreeViewColumn("Address", addressRenderer, markup=0) self.insnColumns[1] = gtk.TreeViewColumn("b0", link_renderer, pixbuf=1) self.insnColumns[2] = gtk.TreeViewColumn("b1", link_renderer, pixbuf=2) self.insnColumns[3] = gtk.TreeViewColumn("b2", link_renderer, pixbuf=3) self.insnColumns[4] = gtk.TreeViewColumn("Instruction", insnRenderer, markup=4) self.insnColumns[5] = gtk.TreeViewColumn("f0", link_renderer, pixbuf=5) self.insnColumns[6] = gtk.TreeViewColumn("f1", link_renderer, pixbuf=6) self.insnColumns[7] = gtk.TreeViewColumn("f2", link_renderer, pixbuf=7) self.insnColumns[8] = gtk.TreeViewColumn("Target", callDstRenderer, markup=8) # The columns active state is attached to the second column # in the model. So when the model says True then the button # will show as active e.g on. for col in self.insnColumns.values(): self.insnView.append_column( col ) return self.insnView def insnCursorChanged(self, view): model = view.get_model() cur = model[view.get_cursor()[0]][InstructionModel.COLUMN_INSTRUCTION] if isinstance(cur, Instruction): self.controller.updateInstructionInfo(cur) self.controller.instructionModel.setCurInstruction(cur) self.controller.instructionModel.refreshModel() else: self.controller.clearInstructionInfo() def insnMoveCursor(self, view, step, count, user): model = view.get_model() try: cur = model[view.get_cursor()[0]][InstructionModel.COLUMN_INSTRUCTION] except: # There is no model, just ignore return function = cur.getFunction() if step == gtk.MOVEMENT_DISPLAY_LINES: all = function.getAll() nextIdx = all.index(cur) try: while not isinstance(all[nextIdx + count], Instruction): nextIdx = nextIdx + count except IndexError: return True if nextIdx < 0: return True view.set_cursor(model.get_path(all[nextIdx].iter)) return True def insnRowActivated( self, view, iter, path, unused ): """ Run when one row is selected (double-click/space) """ model = view.get_model() functionModel = self.functionView.get_model() try: entity = model[iter][InstructionModel.COLUMN_INSTRUCTION] except IndexError: # If the index is outside of the model return if isinstance(entity, Instruction) and entity.hasLink(): link = entity.getOutLink() if isinstance(link, Function): history.add(link.getAddress()) dst = link self.functionView.set_cursor_on_cell(functionModel.get_path(dst.iter)) self.functionView.row_activated(functionModel.get_path(dst.iter), self.viewColumns[0]) view.set_cursor_on_cell(0) else: func = entity.getFunction() dst = func.lookup(link.getAddress()) if dst != None: history.add(dst.getAddress()) view.set_cursor(model.get_path(dst.iter)) def makeViews( self, functionModel, insnModel ): functionView, instructionView = self.makeFunctionView( functionModel), self.makeInstructionView( insnModel ) return functionView, instructionView def usage(): print "Usage: %s -h [FILE]" % (PROGRAM_NAME.lower()) print "Disassemble FILE and open in a graphical window.\n" print " -t BASE_ADDRESS Set the start address for the disassembled file (.text segment)" print " -h Display this help and exit" sys.exit(1) baseAddress = 0 if __name__ == "__main__": optlist, args = getopt.gnu_getopt(sys.argv[1:], "ht:") for opt, arg in optlist: if opt == "-h": usage() if opt == "-t": try: baseAddress = long(arg) except: try: baseAddress = long(arg, 16) except: raise if len(args) == 0: filename = None else: filename = args[0] myGUI = GUI_Controller(filename) myGUI.run() dissy-9/gfx/0000755000175000017500000000000011155777555011303 5ustar skaskadissy-9/gfx/red_start_down.png0000644000175000017500000000033411155777555015027 0ustar skaskaPNG  IHDRĴl; pHYs  tIME { GtEXtCommentCreated with The GIMPd%nRIDAT8 0CU+ ԫ!7QGC 18yC ߊ~'Ǻm/X>+'sIENDB`dissy-9/gfx/red_start_up.png0000644000175000017500000000036711155777555014512 0ustar skaskaPNG  IHDRĴl;bKGD oFFs A pHYs  YIDAT8T1@ W iҡ*k@V % Z/Tі8xsԸGE:_glEE< !!9tEXtCommentCreated with The GIMPd%nIENDB`dissy-9/gfx/icon.svg0000644000175000017500000000747411155777555012770 0ustar skaska image/svg+xml dissy-9/gfx/red_plus.png0000644000175000017500000000034311155777555013626 0ustar skaskaPNG  IHDRĴl;bKGD pHYs  tIME /Q~tEXtCommentCreated with The GIMPd%nGIDAT8c?AȈFBZhr1f.f!_(G &#aLb C8FcJ_z9IENDB`dissy-9/gfx/red_line.png0000644000175000017500000000030311155777555013566 0ustar skaskaPNG  IHDRĴl; pHYs  tIME ytEXtCommentCreated with The GIMPd%n9IDAT8c?AȈFBZhr1f.f!_a<ƣa<ƣa<hn$TIENDB`dissy-9/gfx/red_arrow_left.png0000644000175000017500000000036611155777555015014 0ustar skaskaPNG  IHDRĴl; pHYs  tIME tEXtCommentCreated with The GIMPd%nlIDAT8ՔQ 0 BkSj߭( >"q2G Px5d PIĪi*cilδ4f53.kFnVي/o)7ۦIENDB`dissy-9/gfx/red_arrow_right.png0000644000175000017500000000042011155777555015166 0ustar skaskaPNG  IHDRĴl;bKGD oFFs A pHYs  rIDAT8A 0 wyXHi6x0JB-j`ܓb5p.KiqX3xMK<+Vo|CggxH͠u 8'vk0l1 0tEXtCommentCreated with The GIMPd%nIENDB`dissy-9/tests/0000755000175000017500000000000011155777555011661 5ustar skaskadissy-9/tests/test_arm_arch.py0000744000175000017500000001110311155777555015043 0ustar skaska#!/usr/bin/python import sys import os.path import unittest projdir = os.path.normpath(os.path.join(os.path.dirname(sys.argv[0]), '..')) sys.path = [projdir] + sys.path import dissy.architecture from dissy.arm import ArmArchitecture from dissy.Instruction import Instruction def instr(opcode, args): #mock of function + file object class MockFunction(): def __init__(self): self.baseAddress = 0 self.arch = ArmArchitecture() def getFile(self): return self def getArch(self): return self.arch return Instruction(MockFunction(), 0, None, opcode, args) class TestArmArch(unittest.TestCase): def setUp(self): self.arch = ArmArchitecture() self.assertNotEqual(self.arch, None) def test_arg_parsing(self): self.assertEqual(self.arch.parseArguments(instr('mov', 'r8, #6')), ([], ['r8'], [6])) self.assertEqual(self.arch.parseArguments(instr('mov', 'ip, #0')), ([], ['ip'], [0])) self.assertEqual(self.arch.parseArguments(instr('movle', 'r0, #1')), ([], ['r0'], [1])) self.assertEqual(self.arch.parseArguments(instr('cmp', 'r0, #1')), (['r0'], [], [1])) #Add og sub self.assertEqual(self.arch.parseArguments(instr('sub', 'sp, sp, #4')), (['sp'], ['sp'], [4])) self.assertEqual(self.arch.parseArguments(instr('add', 'sp, sp, #4')), (['sp'], ['sp'], [4])) self.assertEqual(self.arch.parseArguments(instr('add', 'r2, r2, #1')), (['r2'], ['r2'], [1])) self.assertEqual(self.arch.parseArguments(instr('addlt', 'r5, r5, r3')), (['r5', 'r3'], ['r5'], [])) self.assertEqual(self.arch.parseArguments(instr('sub', 'r3, r3, r0, lsl #2')), (['r3', 'r0'], ['r3'], [])) #shifts self.assertEqual(self.arch.parseArguments(instr('lsl', 'r1, r3, #7')), (['r3'], ['r1'], [7])) self.assertEqual(self.arch.parseArguments(instr('asr', 'r1, r2, #31')), (['r2'], ['r1'], [31])) self.assertEqual(self.arch.parseArguments(instr('rsb', 'r0, r1, r0, asr #9')), (['r1', 'r0'], ['r0'], [])) self.assertEqual(self.arch.parseArguments(instr('lsl', 'r1, r3, #7')), (['r3'], ['r1'], [7])) #branches self.assertEqual(self.arch.parseArguments(instr('bl', '0')), ([], ['pc', 'lr'], [])) self.assertEqual(self.arch.parseArguments(instr('bx', 'lr')), (['lr'], ['pc'], [])) self.assertEqual(self.arch.parseArguments(instr('ble', '4c')), ([], ['pc'], [])) #Dynamisk load self.assertEqual(self.arch.parseArguments(instr('ldr', 'r3, [ip]')), (['ip'], ['r3'], [])) self.assertEqual(self.arch.parseArguments(instr('ldr', 'r3, [pc, #8]')), (['pc'], ['r3'], [])) self.assertEqual(self.arch.parseArguments(instr('ldr', 'r3, [r2, r0]')), (['r2', 'r0'], ['r3'], [])) #Dynamisk store self.assertEqual(self.arch.parseArguments(instr('str', 'r0, [r3]')), (['r0', 'r3'], [], [])) self.assertEqual(self.arch.parseArguments(instr('str', 'r0, [r4, r5]')), (['r0', 'r4', 'r5'], [], [])) #unimplemented instruction type self.assertRaises(ValueError, self.arch.parseArguments, instr('abemad', 'r1, r0')) #multiplication self.assertEqual(self.arch.parseArguments(instr('smull', 'r1, r0, r3, r2')), (['r3', 'r2'], ['r1', 'r0'], [])) #multiplication self.assertEqual(self.arch.parseArguments(instr('mul', 'r0, r3, r2')), (['r3', 'r2'], ['r0'], [])) self.assertEqual(self.arch.parseArguments(instr('mla', 'r1, r2, r3, r1')), (['r2', 'r3', 'r1'], ['r1'], [])) #Push, pop self.assertEqual(self.arch.parseArguments(instr('push', '{lr}')), (['sp', 'lr'], ['sp'], [])) self.assertEqual(self.arch.parseArguments(instr('push', '{r4, r5, lr}')), (['sp', 'r4', 'r5', 'lr'], ['sp'], [])) self.assertEqual(self.arch.parseArguments(instr('pop', '{r4, r5, lr}')), (['sp'], ['sp', 'r4', 'r5', 'lr'], [])) self.assertEqual(self.arch.parseArguments(instr('pop', '{lr}')), (['sp'], ['sp', 'lr'], [])) #Assorted self.assertEqual(self.arch.parseArguments(instr('and', 'r3, r3, #31')), (['r3'], ['r3'], [31])) self.assertEqual(self.arch.parseArguments(instr('muls', 'r3, r4, r3')), (['r4', 'r3'], ['r3'], [])) if __name__ == '__main__': unittest.main() dissy-9/UPGRADE0000644000175000017500000000040511155777556011531 0ustar skaskaUpgrading from version 1 to 2 ----------------------------- The configuration file has changed and is no longer compatible with the new version. Remove the ~/.dispy directory. A new directory called ~/.dissy will be created when you start dissy the next time. dissy-9/ChangeLog0000644000175000017500000000722711155777556012302 0ustar skaskaDissy (9) * Don't allow information box to grab focus when "tabbing" through the windows * Register value analysis added for Arm. This is still inactive though (Mads Chr. Olesen) * Make toggling options persistent (save options so that they are remembered on next start) * Refactor highlighting in the Instruction model class to allow it to be more easily extendible (Mads Chr. Olesen) * Add an information box right of the instruction view that describes what the current instruction does (Mads Chr. Olesen) * Highlight the instruction that (most likely) set the condition flags if the current instruction is conditional (Mads Chr. Olesen) * Added an icon (icon.svg). Please make a nicer version! * Add licensing info to file headers and fix email address * Convert tabs to spaces (fix from Mads Chr. Olesen) * Fix close of about dialogue (patch from Lubomir Rintel) * Fix deprecated file dialogue (patch from Mads Chr. Olesen, thanks) -- Simon Kagstrom , Wed Mar 11 19:09:36 CET 2009 Dissy (8) * Special-case Linux crashes. This allows you to paste things like [ 3796.619417] [] ? ext2_free_blocks+0xfa/0x2b7 [ 3796.619417] [] ? activate_page+0x9a/0xa2 [ 3796.619417] [] ? ext2_free_branches+0x12d/0x190 [ 3796.619417] [] ? __getblk+0x27/0x294 into the dissy "address bar" and get a nice callback * bdnz+/- for PowerPC -- Simon Kagstrom , Sat Jan 31 10:16:14 CET 2009 Dissy (7) * Workaround for a objdump bug on (at least) some MIPS binaries, where addresses are internally 64 bits. If dissy finds no instructions in a function, it will therefore try to sign-extend the value and use that * Support for setting the OBJDUMP environment variable to set the objdump to use (idea from Joseph E. Garvey) * Initial ARM support (i.e., support for visualizing jumps - disassembly has always worked) * Better support for PowerPC (instruction regexp + handling of more branch instructions) * History handling has changed to more match that of a web-browser, overwriting the "current" entry instead of appending after it -- Simon Kagstrom , Fri Jan 25 13:10:25 CET 2008 Dissy (6) * New ChangeLog format * Better "location bar" behavior: Allow multiple words to be pasted and do more intelligent handling of numbers * Added navigation history with back/forward (like in web browsers) * Fixed MIPS register regexp to handle k registers * Added manpage written by the Varun Hiremath of the Debian project, and documented the new features * Fixed bug where the -t option made it impossible to search for addresses -- Simon Kagstrom , Sun Aug 5 12:54:21 CEST 2007 2007-03-11 Simon Kgstrm (5) * Don't parse symbols eagerly (this improves performance a lot) * Added some missing jump instructions on IA-32 2006-11-25 Simon Kgstrm (4) * Added PPC support (Andrew May) * Added a text entry for marking certain patterns, e.g., to highlight certain registers and so in the text. The pattern is a regular expression * Fixed checks to avoid a few non-fatal exceptions * Added tooltips * Setting of colors is now possible in the preferences dialogue 2006-10-14 Simon Kgstrm (3) * Added ability to search for instructions and registers * Fixed bug in label lookup 2006-09-03 Simon Kgstrm (2) * Much faster loading of files. Only load a list of symbols and then load and links each function on demand. * More clever use of objdump, nm and readelf * Added reload menu option * Better IA-32 architecture support dissy-9/dissy.10000644000175000017500000000364711155777556011747 0ustar skaska.TH DISSY 1 "October 20, 2006" .SH NAME dissy - graphical frontend for objdump .SH DESCRIPTION .PP Dissy is a disassembler for Linux and UNIX which supports multiple architectures and allows easy navigation through the code. Dissy is implemented in Python and uses objdump for disassembling files. Dissy can be used for debugging, reverse engineering and checking compiler-generated code. .TP \fB\-t\fR \fIBASE_ADDRESS\fR Use BASE_ADDRESS as the start address of the disassembled code .PP .TP \fB\-h\fR Display usage .PP .SH Features and usage .PP * Dissy shows jumps with red links to the destination address .PP * A label is used to show call destinations .PP * Clicking (or pressing enter) on calls or jumps will take you to the destination function / address .PP * Dissy supports interactive searching for labels and addresses both for functions and instructions .PP * Browser-like history navigation (back/forward) is available, which is useful for example to lookup callchains. Alt-Left and Alt-Right are used to navigate back and forward .PP * The lookup (use Ctrl-l to access) feature allows for looking up pasted addresses or labels. The lookup is intelligent in that it tries to convert common patterns into numbers before reverting to label lookup. Pasting multiple addresses or names will lookup each in turn and stop at the last (access the earlier in the history) .PP * The highlight field (ues Ctrl-k to access) allows the disassembled text to be highlighted for example to show all accesses to a certain register. Regular expressions are allowed in this field .PP * The preferences window can be used to select which objdump to use (which can also be controlled by the OBJDUMP environment variable). Colors can also be selected in this window. .SH HOMEPAGE http://rtlab.tekproj.bth.se/wiki/index.php/Dissy .SH AUTHOR This manual page was written by Varun Hiremath , for the Debian project (but may be used by others).