pmacs3/mode/hex.py

422 lines
17 KiB
Python

import re, string, struct
from subprocess import Popen, PIPE, STDOUT
import color
from mode import Fundamental
from lex import Grammar, PatternRule, RegionRule
from method import Method, Argument
from method.move import GotoBeginning, GotoEnd
from point import Point
from render import RenderString
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):
end = w.buffer.get_buffer_end()
if w.cursor >= end.add(-2, 0):
return
w.forward()
if w.mode.symbolic_edit:
w.forward()
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()
if w.mode.symbolic_edit:
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 HexGotoBeginning(GotoBeginning):
'''Move the cursor to the start of the current hex line'''
class HexGotoEnd(GotoEnd):
'''Move the cursor to the end of the current hex line'''
def _execute(self, w, **vargs):
w.application.methods['goto-end'].execute(w)
w.application.methods['hex-backward'].execute(w)
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
self.part1, self.part2 = '%02x' % ord(self.char)
def _execute(self, w, **vargs):
if w.mode.symbolic_edit:
b = w.buffer
hb = w.application.methods['hex-backward']
(cx, cy) = w.cursor.xy()
ix = b.cursorx_to_datax(cy, cx)
if ix is None:
return
cx2 = w.buffer.datax_to_cursorx(ix)
w.goto(Point(cx2, cy))
w.overwrite_char_at_cursor(self.part1)
w.overwrite_char_at_cursor(self.part2)
elif self.char not in string.hexdigits:
return
else:
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 HexOverwriteCharSpace(HexOverwriteChar):
def __init__(self):
self.name = 'hex-overwrite-char-space'
self.args = []
self.help = "Overwrite SPACE into the current hex buffer."
self.char = ' '
self.part1, self.part2 = '%02x' % ord(self.char)
class HexOverwriteCharTab(HexOverwriteChar):
def __init__(self):
self.name = 'hex-overwrite-char-tab'
self.args = []
self.help = "Overwrite TAB into the current hex buffer."
self.char = '\t'
self.part1, self.part2 = '%02x' % ord(self.char)
class HexOverwriteCharNewline(HexOverwriteChar):
def __init__(self):
self.name = 'hex-overwrite-char-newline'
self.args = []
self.help = "Overwrite NEWLINE into the current hex buffer."
self.char = '\n'
self.part1, self.part2 = '%02x' % ord(self.char)
class HexToggleSymbolic(Method):
def _execute(self, w, **vargs):
w.mode.symbolic_edit = not w.mode.symbolic_edit
if w.mode.symbolic_edit:
w.set_error("Symbolic editing enabled")
else:
w.set_error("Symbolic editing disabled")
class HexLiteral(Method):
def _execute(self, w, **vargs):
w.mode.symbolic_edit = False
w.set_error("Symbolic editing disabled")
class HexSymbolic(Method):
def _execute(self, w, **vargs):
w.mode.symbolic_edit = True
w.set_error("Symbolic editing enabled")
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)
class Hex(Fundamental):
name = '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)
actions = [HexForward, HexBackward, HexForwardWord, HexBackwardWord,
HexStartOfLine, HexEndOfLine, ShowAddress, ShowX86Instruction,
GotoAddress, HexSetByteOrder, HexToggleSymbolic, HexSymbolic, HexLiteral,
HexOverwriteCharSpace, HexOverwriteCharTab,
HexOverwriteCharNewline, HexGotoBeginning, HexGotoEnd]
#header = 1
#header_size = 1
hlo = color.build('red', 'default')
hhi = color.build('default', 'red')
format = "%(flag)s %(bname)-18s (%(mname)s) {%(symbolic)s} %(cursor)s %(perc)s"
def get_status_names(self):
names = Fundamental.get_status_names(self)
if self.symbolic_edit:
names['symbolic'] = 'symbolic'
else:
names['symbolic'] = 'literal'
return names
def get_header(self):
s0 = ' 87654321 '
s1 = '00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff'
s2 = ' ' * (self.window.width - 48)
s3 = '0123456789abcdef '
def lo(s): return RenderString(s=s, attrs=self.hlo)
def hi(s): return RenderString(s=s, attrs=self.hhi)
if self.symbolic_edit:
return [[lo(s0), lo(s1), lo(s2), hi(s3)]]
else:
return [[lo(s0), hi(s1), lo(s2), lo(s3)]]
def __init__(self, w):
Fundamental.__init__(self, w)
self.bindings = {}
self.lmargin = 12
self.rmargin = 18
self.header = 1
self.footer = 0
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-]', 'C-g'))
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_bindings('hex-forward', ('C-f', 'R_ARROW',))
self.add_bindings('hex-backward', ('C-b', 'L_ARROW',))
self.add_bindings('hex-forward-word', ('M-f', 'M-R_ARROW',))
self.add_bindings('hex-backward-word', ('M-b', 'M-L_ARROW',))
self.add_bindings('hex-start-of-line', ('C-a', 'HOME',))
self.add_bindings('hex-end-of-line', ('C-e', 'END',))
self.add_bindings('hex-goto-beginning', ('M-<',))
self.add_bindings('hex-goto-end', ('M->',))
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_bindings('show-address', ('C-c a',))
self.add_bindings('show-x86-instruction', ('C-c x',))
self.add_bindings('goto-address', ('C-c M-g',))
# create all the insert actions for the basic text input
for c in string.letters + string.digits + string.punctuation:
self.add_action_and_bindings(HexOverwriteChar(c), (c,))
self.add_bindings('hex-overwrite-char-space', ('SPACE',))
self.add_bindings('hex-overwrite-char-tab', ('TAB',))
self.add_bindings('hex-overwrite-char-newline', ('RETURN',))
self.symbolic_edit = True
def get_address(self, y, x):
return (y * 16) + x
def get_lmargin(self, w, y, x, ended=False, cont=False):
lm = self.lmargin
if ended:
s = ' -------- '
else:
addr = self.get_address(y, x)
s = '0x%08x ' % addr
return (RenderString(s, attrs=self.ccyan),)
def get_rmargin(self, w, y, x, ended=False, cont=False):
if ended:
return tuple()
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 = (RenderString(s, attrs=self.cgreen),)
elif i < len(s):
rmargins = (RenderString(s[0:i], attrs=self.cgreen),
RenderString(s[i], x=i, attrs=self.ccursor),
RenderString(s[i+1:], x=i + 1, attrs=self.cgreen))
else:
rmargins= (RenderString(s[0:i], attrs=self.cgreen),
RenderString(s[i], x=i, attrs=self.cgreen))
return rmargins
else:
return (RenderString(s, attrs=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]
install = Hex.install