pmacs3/mode/hex.py

310 lines
13 KiB
Python

import re, string, struct
from subprocess import Popen, PIPE, STDOUT
import color, mode
from lex import Grammar, PatternRule, RegionRule
from method import Method, Argument
from point import Point
class Hex(mode.Fundamental):
modename = 'Hex'
config = {
'hex.disinst': 'disinst',
}
lmargin = 12
rmargin = 18
_ctrans = ['.'] * 256
byteorder = 'native'
byteorders = {
'native': '=',
'little': '<',
'big': '>',
}
cgreen = color.build('green', 'default', 'bold')
ccyan = color.build('cyan', 'default', 'bold')
ccursor = color.build('default', 'default', 'bold', 'reverse')
for c in string.letters + string.digits + string.punctuation + ' ':
_ctrans[ord(c)] = c
ctrans = ''.join(_ctrans)
def __init__(self, w):
mode.Fundamental.__init__(self, w)
self.bindings = {}
self.add_bindings('center-view', ('C-l',))
self.add_bindings('next-line', ('C-n', 'D_ARROW',))
self.add_bindings('previous-line', ('C-p', 'U_ARROW',))
self.add_bindings('next-section', ('M-n', 'M-D_ARROW',))
self.add_bindings('previous-section', ('M-p', 'M-U_ARROW',))
self.add_bindings('page-down', ('C-v', 'PG_DN',))
self.add_bindings('page-up', ('M-v', 'PG_UP',))
self.add_bindings('goto-beginning', ('M-<',))
self.add_bindings('goto-end', ('M->',))
self.add_bindings('right-word', ('M-f',))
self.add_bindings('left-word', ('M-b',))
self.add_bindings('set-mark', ('C-@',))
self.add_bindings('switch-buffer', ('C-x b',))
self.add_bindings('switch-mark', ('C-x C-x',))
self.add_bindings('undo', ('C-/', 'C-x u',))
self.add_bindings('redo', ('M-/', 'M-_', 'C-x r',))
self.add_bindings('goto-line', ('M-g',))
self.add_bindings('forward-chars', ('C-x M-c',))
self.add_bindings('forward-lines', ('C-x M-n',))
self.add_bindings('search', ('C-s',))
self.add_bindings('reverse-search', ('C-r',))
self.add_bindings('regex-search', ('M-C-s',))
self.add_bindings('regex-reverse-search', ('M-C-r',))
self.add_bindings('toggle-margins', ('M-m',))
self.add_bindings('open-file', ('C-x C-f',))
self.add_bindings('kill-buffer', ('C-x k',))
self.add_bindings('list-buffers', ('C-x C-b',))
self.add_bindings('meta-x', ('M-x',))
self.add_bindings('save-buffer', ('C-x C-s',))
self.add_bindings('save-buffer-as', ('C-x C-w',))
self.add_bindings('exit', ('C-x C-c',))
self.add_bindings('split-window', ('C-x s', 'C-x 2',))
self.add_bindings('unsplit-window', ('C-u s', 'C-x 1',))
self.add_bindings('toggle-window', ('C-x o',))
self.add_bindings('open-console', ('M-e',))
self.add_bindings('show-bindings-buffer', ('C-c M-h',))
self.add_bindings('show-functions-buffer', ('C-c M-?',))
self.add_bindings('which-command', ('M-h',))
self.add_bindings('cmd-help-buffer', ('M-?',))
self.add_bindings('set-mode', ('C-x m',))
self.add_bindings('cancel', ('C-]',))
self.add_bindings('exec', ('C-c e', 'C-c !'))
self.add_bindings('grep', ('C-c g',))
self.add_bindings('pipe', ('C-c p', 'C-c |'))
self.add_bindings('view-buffer-parent', ('C-c .',))
self.add_bindings('get-token', ('C-c t',))
self.add_action_and_bindings(HexForward(), ('C-f', 'R_ARROW',))
self.add_action_and_bindings(HexBackward(), ('C-b', 'L_ARROW',))
self.add_action_and_bindings(HexForwardWord(), ('M-f', 'M-R_ARROW',))
self.add_action_and_bindings(HexBackwardWord(), ('M-b', 'M-L_ARROW',))
self.add_action_and_bindings(HexStartOfLine(), ('C-a', 'HOME',))
self.add_action_and_bindings(HexEndOfLine(), ('C-e', 'END',))
self.add_action_and_bindings(HexRead('char', 'b'), ('C-c b',))
self.add_action_and_bindings(HexRead('uchar', 'B'), ('C-c B',))
self.add_action_and_bindings(HexRead('short', 'h'), ('C-c h',))
self.add_action_and_bindings(HexRead('ushort', 'H'), ('C-c H',))
self.add_action_and_bindings(HexRead('int', 'i'), ('C-c i',))
self.add_action_and_bindings(HexRead('uint', 'I'), ('C-c I',))
self.add_action_and_bindings(HexRead('long', 'l'), ('C-c l',))
self.add_action_and_bindings(HexRead('ulong', 'L'), ('C-c L',))
self.add_action_and_bindings(HexRead('float', 'f'), ('C-c f',))
self.add_action_and_bindings(HexRead('double', 'd'), ('C-c d',))
self.add_action_and_bindings(HexReadAligned('char', 'b'), ('C-u b',))
self.add_action_and_bindings(HexReadAligned('uchar', 'B'), ('C-u B',))
self.add_action_and_bindings(HexReadAligned('short', 'h'), ('C-u h',))
self.add_action_and_bindings(HexReadAligned('ushort', 'H'), ('C-u H',))
self.add_action_and_bindings(HexReadAligned('int', 'i'), ('C-u i',))
self.add_action_and_bindings(HexReadAligned('uint', 'I'), ('C-u I',))
self.add_action_and_bindings(HexReadAligned('long', 'l'), ('C-u l',))
self.add_action_and_bindings(HexReadAligned('ulong', 'L'), ('C-u L',))
self.add_action_and_bindings(HexReadAligned('float', 'f'), ('C-u f',))
self.add_action_and_bindings(HexReadAligned('double', 'd'), ('C-u d',))
self.add_action_and_bindings(ShowAddress(), ('C-c a',))
self.add_action_and_bindings(ShowX86Instruction(), ('C-c x',))
self.add_action_and_bindings(GotoAddress(), ('C-c M-g',))
self.add_action(HexSetByteOrder())
# create all the insert actions for the basic text input
for c in string.letters + string.digits + string.punctuation:
if c in string.hexdigits:
self.add_action_and_bindings(HexOverwriteChar(c), (c,))
def get_address(self, y, x):
return (y * 16) + x
def get_lmargin(self, y, x=0, ended=False, cont=False):
lm = self.lmargin
if ended:
s = ' -------- '
else:
addr = self.get_address(y, x)
s = '0x%08x ' % addr
return ((0, s, self.ccyan),)
def get_rmargin(self, y, x=0, ended=False, cont=False):
if ended:
return ((0, '', 0),)
else:
(cx, cy) = self.window.cursor.xy()
s = string.translate(self.window.buffer.rawdata[y], self.ctrans)
if cy == y:
i = self.window.buffer.cursorx_to_datax(cy, cx)
if i is None:
rmargins = ((0, s, self.cgreen),)
elif i < len(s):
rmargins = ((0, s[0:i], self.cgreen),
(i, s[i], self.ccursor),
(i + 1, s[i+1:], self.cgreen))
else:
rmargins= ((0, s[0:i], self.cgreen),
(i, s[i], self.cgreen),)
return rmargins
else:
return ((0, s, self.cgreen),)
def read_data(self, cy, ix, size):
b = self.window.buffer
s = b.rawdata[cy][ix:]
if len(s) < size:
if cy < len(b.rawdata) - 1:
s += b.rawdata[cy + 1]
s = s[:size]
return s
def read_struct(self, cy, ix, fmt, size):
s = self.read_data(cy, ix, size)
fmt = '%s%s' % (self.byteorders[self.byteorder], fmt)
return struct.unpack(fmt, s)[0]
class HexSetByteOrder(Method):
'''Sets the byte-order to use to 'little', 'big', or 'native' order'''
args = [Argument("byteorder", type=type(''), prompt="Byte order: ")]
def _execute(self, w, **vargs):
order = vargs['byteorder']
if order in w.mode.byteorders:
w.mode.byteorder = order
w.set_error("byte-order set to %r" % w.mode.byteorder)
else:
w.set_error("invalid ordering %r (use 'little', 'big', or 'native'")
class HexForward(Method):
def _execute(self, w, **vargs):
w.forward()
end = w.buffer.get_buffer_end()
while w.cursor_char().isspace() and w.cursor < end:
w.forward()
class HexBackward(Method):
def _execute(self, w, **vargs):
w.backward()
start = w.buffer.get_buffer_start()
while w.cursor_char().isspace() and w.cursor > start:
w.backward()
class HexForwardWord(Method):
def _execute(self, w, **vargs):
hf = w.application.methods['hex-forward']
for i in range(0, w.buffer.wordsize * 2):
hf.execute(w, **vargs)
class HexBackwardWord(Method):
def _execute(self, w, **vargs):
hb = w.application.methods['hex-backward']
for i in range(0, w.buffer.wordsize * 2):
hb.execute(w, **vargs)
class HexStartOfLine(Method):
'''Move the cursor to the start of the current hex line'''
def _execute(self, w, **vargs):
w.start_of_line()
class HexEndOfLine(Method):
'''Move the cursor to the end of the current hex line'''
def _execute(self, w, **vargs):
w.end_of_line()
if w.cursor_char() == '\n':
w.backward()
class HexRead(Method):
_is_method = False
def __init__(self, type_, fmt):
self.name = 'hex-read-%s' % type_.lower()
self.type_ = type_
self.fmt = fmt
self.size = struct.calcsize(fmt)
self.args = []
self.help = "Read %r from address in the current buffer." % self.type_
def _get_ix(self, b, cy, cx):
ix = b.cursorx_to_datax(cy, cx)
return ix
def _execute(self, w, **vargs):
b = w.buffer
hb = w.application.methods['hex-backward']
(cx, cy) = w.cursor.xy()
ix = self._get_ix(b, cy, cx)
addr = b.get_address(cy, 0) + ix
try:
v = w.mode.read_struct(cy, ix, self.fmt, self.size)
if v is None:
w.set_error("not enough data to read %s" % self.type_)
else:
end = '%s-endian' % w.mode.byteorder
w.set_error("%s %s at 0x%08x: %r" % (end, self.type_, addr, v))
except Exception, e:
w.set_error("%s could not be read at 0x%08x" % (self.type_, addr))
class HexReadAligned(HexRead):
_is_method = False
def __init__(self, type_, fmt):
self.name = 'hex-read-aligned-%s' % type_.lower()
self.type_ = type_
self.fmt = fmt
self.size = struct.calcsize(fmt)
self.args = []
self.help = "Read %r from word-aligned address in the current buffer." % self.type_
def _get_ix(self, b, cy, cx):
ix = b.cursorx_to_datax(cy, cx)
ix -= ix % b.wordsize
return ix
class HexOverwriteChar(Method):
_is_method = False
def __init__(self, c):
self.name = 'hex-overwrite-char-%s' % c
self.args = []
self.help = "Overwrite %r into the current hex buffer." % c
self.char = c
def _execute(self, w, **vargs):
w.overwrite_char_at_cursor(self.char)
end = w.buffer.get_buffer_end()
while w.cursor_char().isspace() and w.cursor < end:
w.forward()
class ShowX86Instruction(Method):
''''''
size_re = re.compile(r'X86 insn \((\d+) bytes\):')
def _execute(self, w, **vargs):
disinst = w.application.config.get('hex.disinst')
(cx, cy) = w.cursor.xy()
ix = w.buffer.cursorx_to_datax(cy, cx)
data = w.mode.read_data(cy, ix, 13)
data = ''.join(['%02x' % ord(c) for c in data])
try:
p = Popen((disinst, data), stdout=PIPE, stderr=STDOUT)
lines = [l.strip() for l in p.stdout.readlines()]
result = p.wait()
m = self.size_re.match(lines[0])
assert m
size = int(m.group(1))
data = data[:size]
w.set_error("%s %s" % (data, lines[1]))
except Exception, e:
w.set_error("there was an error")
class GotoAddress(Method):
'''Jump to the specified line number'''
args = [Argument("address", type=type(0), prompt="Goto address: ")]
def _execute(self, w, **vargs):
b = w.buffer
addr = vargs["address"]
if addr < 0:
w.set_error("Negative address not supported.")
ix = addr % (b.groupsize * b.numgroups)
cx = w.buffer.datax_to_cursorx(ix)
cy = addr // (b.groupsize * b.numgroups)
w.goto(Point(cx, cy))
w.set_error("Goto 0x%08x (%r, %r)" % (addr, cx, cy))
class ShowAddress(Method):
'''Show the cursor's address in the current buffer'''
def _execute(self, w, **vargs):
(cx, cy) = w.cursor.xy()
ix = w.buffer.cursorx_to_datax(cy, cx)
addr = w.buffer.get_address(cy, ix)
w.set_error("Cursor's address is 0x%08x" % addr)
install = Hex.install