mirror of https://github.com/snare/voltron.git
Revert "Improvements to memory vieweing"
This commit is contained in:
parent
8887aa0446
commit
d9fef0bb40
|
@ -128,39 +128,6 @@ view:
|
|||
attrs: []
|
||||
format:
|
||||
addr_format: "{0:0=16X}"
|
||||
memorystride_view:
|
||||
header:
|
||||
show: false
|
||||
footer:
|
||||
show: true
|
||||
label_left:
|
||||
name: title
|
||||
colour: white
|
||||
bg_colour: grey
|
||||
attrs:
|
||||
- bold
|
||||
label_right:
|
||||
name: info
|
||||
colour: blue
|
||||
bg_colour: grey
|
||||
attrs: []
|
||||
format:
|
||||
addr_format: "{0:0=16X}"
|
||||
keymap:
|
||||
q: exit
|
||||
p: page_up
|
||||
n: page_down
|
||||
KEY_PPAGE: page_up
|
||||
KEY_NPAGE: page_down
|
||||
KEY_UP: line_up
|
||||
KEY_DOWN: line_down
|
||||
KEY_ENTER: reset
|
||||
s: toggle_signed
|
||||
l: toggle_length
|
||||
h: hex_mode
|
||||
d: dec_mode
|
||||
=: inc_row_len
|
||||
-: dec_row_len
|
||||
backtrace_view:
|
||||
header:
|
||||
show: false
|
||||
|
|
|
@ -2,7 +2,6 @@ import voltron
|
|||
import logging
|
||||
import six
|
||||
import struct
|
||||
import binascii
|
||||
|
||||
from voltron.api import *
|
||||
|
||||
|
@ -109,9 +108,7 @@ class APIMemoryRequest(APIRequest):
|
|||
|
||||
res = APIMemoryResponse()
|
||||
res.address = addr
|
||||
#don't use six.u since it processes escape sequences ie... breaks if we have 0x5C 0x37 in memory
|
||||
#res.memory = six.u(memory)
|
||||
res.memory = binascii.hexlify(memory)
|
||||
res.memory = six.u(memory)
|
||||
res.bytes = len(memory)
|
||||
res.deref = deref
|
||||
except TargetBusyException:
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import logging
|
||||
import six
|
||||
import binascii
|
||||
import pygments
|
||||
import pygments.formatters
|
||||
from pygments.token import *
|
||||
|
@ -84,7 +83,6 @@ class MemoryView(TerminalView):
|
|||
|
||||
if m_res and m_res.is_success:
|
||||
bytes_per_chunk = self.args.words*target['addr_size'] if self.args.words else self.args.bytes
|
||||
m_res.memory = binascii.unhexlify(m_res.memory)
|
||||
for c in range(0, m_res.bytes, bytes_per_chunk):
|
||||
chunk = m_res.memory[c:c + bytes_per_chunk]
|
||||
yield (Name.Label, self.format_address(m_res.address + c, size=target['addr_size'], pad=False))
|
||||
|
@ -96,11 +94,8 @@ class MemoryView(TerminalView):
|
|||
n = "%02X" % x
|
||||
token = Text if x else Comment
|
||||
if self.args.track and self.last_memory and self.last_address == m_res.address:
|
||||
try:
|
||||
if x != six.indexbytes(self.last_memory, c + i):
|
||||
token = Error
|
||||
except:
|
||||
pass
|
||||
if x != six.indexbytes(self.last_memory, c + i):
|
||||
token = Error
|
||||
byte_array.append((token, n))
|
||||
|
||||
if self.args.words:
|
||||
|
|
|
@ -1,303 +0,0 @@
|
|||
import logging
|
||||
import six
|
||||
import binascii
|
||||
import math
|
||||
import struct
|
||||
import pygments
|
||||
import pygments.formatters
|
||||
from pygments.token import *
|
||||
|
||||
from voltron.view import TerminalView, VoltronView
|
||||
from voltron.plugin import ViewPlugin, api_request
|
||||
|
||||
log = logging.getLogger("view")
|
||||
|
||||
|
||||
def requires_async(func):
|
||||
def inner(self, *args, **kwargs):
|
||||
if not self.block:
|
||||
return func(self, *args, **kwargs)
|
||||
else:
|
||||
sys.stdout.write('\a')
|
||||
sys.stdout.flush()
|
||||
|
||||
return inner
|
||||
|
||||
class MemoryStrideView(TerminalView):
|
||||
#valid_key_funcs = ["dec_mode", "hex_mode", "exit", "page_up", "page_down", "page_up", "page_down",
|
||||
# "line_up", "line_down", "reset"]
|
||||
TerminalView.valid_key_funcs += ["toggle_signed", "toggle_length", "dec_mode", "hex_mode", "inc_row_len", "dec_row_len"] #s:
|
||||
|
||||
|
||||
printable_filter = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)])
|
||||
|
||||
|
||||
async = True
|
||||
prev_last_memory = None
|
||||
last_memory = None
|
||||
last_address = 0
|
||||
last_length = 0
|
||||
view_style = {'hex_or_dec':'hex', 'word_size':4, 'unsigned':False}
|
||||
|
||||
@classmethod
|
||||
def configure_subparser(cls, subparsers):
|
||||
sp = subparsers.add_parser('memorystride', help='display a chunk of memory', aliases=('ms', 'mems','memstride'))
|
||||
VoltronView.add_generic_arguments(sp)
|
||||
group = sp.add_mutually_exclusive_group(required=False)
|
||||
group.add_argument('--bytes', '-b', action='store', type=int, help='bytes per line (default 16)', default=16)
|
||||
sp.add_argument('--stride', '-s', action='store', type=int, help='bytes between lines (default 128)', default=128)
|
||||
sp.add_argument('--max', action='store', type=int, help='Lines to print (default 0)', default=0)
|
||||
sp.add_argument('--reverse', '-v', action='store_true', help='reverse the output', default=False)
|
||||
sp.add_argument('--track', '-t', action='store_true', help='track and highlight changes', default=True)
|
||||
sp.add_argument('--no-track', '-T', action='store_false', help='don\'t track and highlight changes')
|
||||
|
||||
group = sp.add_mutually_exclusive_group(required=False)
|
||||
group.add_argument('--address', '-a', action='store',
|
||||
help='address (in hex or decimal) from which to start reading memory')
|
||||
group.add_argument('--command', '-c', action='store',
|
||||
help='command to execute resulting in the address from which to start reading memory. '
|
||||
'voltron will do his almighty best to find an address. e.g. "print \$rip + 0x1234"',
|
||||
default=None)
|
||||
group.add_argument('--register', '-r', action='store',
|
||||
help='register containing the address from which to start reading memory', default=None)
|
||||
sp.set_defaults(func=MemoryStrideView)
|
||||
|
||||
|
||||
def build_requests(self):
|
||||
height, width = self.window_size()
|
||||
|
||||
# check args
|
||||
if self.args.register:
|
||||
args = {'register': self.args.register}
|
||||
elif self.args.command:
|
||||
args = {'command': self.args.command}
|
||||
elif self.args.address:
|
||||
if self.args.address.startswith('0x'):
|
||||
addr = int(self.args.address, 16)
|
||||
else:
|
||||
try:
|
||||
addr = int(self.args.address, 10)
|
||||
except:
|
||||
addr = int(self.args.address, 16)
|
||||
# force address be 4-byte aligned
|
||||
addr = int(addr/4)*4
|
||||
args = {'address': addr}
|
||||
|
||||
else:
|
||||
args = {'register': 'sp'}
|
||||
|
||||
|
||||
args['length'] = self.args.stride*height
|
||||
args['offset'] = self.scroll_offset*self.args.stride if self.args.reverse else -self.scroll_offset*self.args.stride
|
||||
if self.args.max:
|
||||
args['length'] = self.args.max
|
||||
|
||||
# get memory and target info
|
||||
return [
|
||||
api_request('targets'),
|
||||
api_request('memory', deref=False, **args)
|
||||
]
|
||||
|
||||
def generate_tokens(self, results):
|
||||
t_res, m_res = results
|
||||
|
||||
if t_res and t_res.is_success and len(t_res.targets) > 0:
|
||||
target = t_res.targets[0]
|
||||
|
||||
if m_res and m_res.is_success:
|
||||
bytes_per_chunk = self.args.stride
|
||||
row_len = self.args.bytes
|
||||
m_res.memory = binascii.unhexlify(m_res.memory)
|
||||
read_bytes = m_res.bytes
|
||||
if(self.args.max):
|
||||
read_bytes = min(self.args.max, m_res.bytes)
|
||||
for c in range(0, read_bytes, bytes_per_chunk):
|
||||
chunk = m_res.memory[c:c + row_len]
|
||||
yield (Name.Label, self.format_address(m_res.address + c, size=target['addr_size'], pad=False))
|
||||
yield (Name.Label, ': ')
|
||||
|
||||
# Hex bytes
|
||||
byte_array = []
|
||||
for i, x in enumerate(six.iterbytes(chunk)):
|
||||
n = "%02X" % x
|
||||
token = Text if x else Comment #Set color white or teal
|
||||
if self.last_memory:
|
||||
byte_addr = m_res.address + c + i
|
||||
last_end_addr = self.last_address + self.last_length
|
||||
if self.args.track and byte_addr > self.last_address and byte_addr < last_end_addr:
|
||||
if x != six.indexbytes(self.last_memory, byte_addr - self.last_address):
|
||||
token = Error #Set color to red
|
||||
byte_array.append((token, n))
|
||||
|
||||
|
||||
byte_array_words = [byte_array[i:i+ self.view_style['word_size']] for i in range(0, row_len, self.view_style['word_size'])]
|
||||
for i, word in enumerate(byte_array_words):
|
||||
format_str = '>' #default Big Endian
|
||||
|
||||
if target['byte_order'] == 'little':
|
||||
word.reverse()
|
||||
format_str = '<' # set to Little Endian
|
||||
|
||||
if self.view_style['hex_or_dec'] == 'hex':
|
||||
for x in word:
|
||||
yield x
|
||||
else:
|
||||
raw_offset = i*self.view_style['word_size'];
|
||||
raw_word = chunk[raw_offset:raw_offset + self.view_style['word_size']]
|
||||
token = Text
|
||||
for x in word:
|
||||
if x[0] == Error:
|
||||
token = Error
|
||||
word_idx = int(math.log(self.view_style['word_size'],2))
|
||||
word_size_mapping = ['b', 'h', 'i', 'q']
|
||||
format_print_str_map = ['{:>-4d}','{:>-6d}','{:>-11d}','{:>-21d}']
|
||||
format_size = word_size_mapping[word_idx]
|
||||
if self.view_style['unsigned']:
|
||||
format_size = format_size.upper()
|
||||
format_str += format_size
|
||||
word_val = struct.unpack(format_str, bytes(raw_word))
|
||||
yield (token, format_print_str_map[word_idx].format(word_val[0]))
|
||||
yield (Text, ' ')
|
||||
|
||||
|
||||
# ASCII representation
|
||||
yield (Punctuation, '| ')
|
||||
for i, x in enumerate(six.iterbytes(chunk)):
|
||||
token = String.Char if x else Comment
|
||||
if self.last_memory:
|
||||
byte_addr = m_res.address + c + i
|
||||
last_end_addr = self.last_address + self.last_length
|
||||
if self.args.track and byte_addr > self.last_address and byte_addr < last_end_addr:
|
||||
if x != six.indexbytes(self.last_memory, byte_addr - self.last_address ):
|
||||
token = Error
|
||||
yield (token, ((x <= 127 and self.printable_filter[x]) or '.'))
|
||||
yield (Punctuation, ' | ')
|
||||
|
||||
|
||||
yield (Text, '\n')
|
||||
|
||||
def render(self, results):
|
||||
target = None
|
||||
self.trunc_top = self.args.reverse
|
||||
|
||||
t_res, m_res = results
|
||||
|
||||
if t_res and t_res.is_success and len(t_res.targets) > 0:
|
||||
target = t_res.targets[0]
|
||||
|
||||
f = pygments.formatters.get_formatter_by_name(self.config.format.pygments_formatter,
|
||||
style=self.config.format.pygments_style)
|
||||
|
||||
if m_res and m_res.is_success:
|
||||
lines = pygments.format(self.generate_tokens(results), f).split('\n')
|
||||
self.body = '\n'.join(reversed(lines)).strip() if self.args.reverse else '\n'.join(lines)
|
||||
self.info = '[0x{0:0=4x}:'.format(len(m_res.memory)) + self.config.format.addr_format.format(m_res.address) + ']'
|
||||
else:
|
||||
log.error("Error reading memory: {}".format(m_res.message))
|
||||
self.body = pygments.format([(Error, m_res.message)], f)
|
||||
self.info = ''
|
||||
|
||||
# Store the memory
|
||||
if self.args.track:
|
||||
#Annoying hack so viewing changes still see deltas
|
||||
self.prev_last_memory = self.last_memory
|
||||
self.last_address = m_res.address
|
||||
self.last_memory = m_res.memory
|
||||
self.last_length = m_res.bytes
|
||||
else:
|
||||
self.body = self.colour("Failed to get targets", 'red')
|
||||
|
||||
if not self.title:
|
||||
self.title = "[memoryStride (" + str(self.args.stride) + ") ]"
|
||||
|
||||
super(MemoryStrideView, self).render(results)
|
||||
|
||||
def format_address(self, address, size=8, pad=True, prefix='0x'):
|
||||
fmt = '{:' + ('0=' + str(size * 2) if pad else '') + 'X}'
|
||||
addr_str = fmt.format(address)
|
||||
if prefix:
|
||||
addr_str = prefix + addr_str
|
||||
return addr_str
|
||||
|
||||
def handle_key(self, key):
|
||||
"""
|
||||
Handle a keypress. Concrete subclasses can implement this method if
|
||||
custom keypresses need to be handled other than for exit and scrolling.
|
||||
"""
|
||||
try:
|
||||
func = None
|
||||
if key.is_sequence:
|
||||
try:
|
||||
func = self.config.keymap[key.name]
|
||||
except:
|
||||
try:
|
||||
func = self.config.keymap[key.code]
|
||||
except:
|
||||
func = self.config.keymap[str(key)]
|
||||
else:
|
||||
func = self.config.keymap[str(key)]
|
||||
|
||||
if func in self.valid_key_funcs:
|
||||
getattr(self, func)()
|
||||
# else:
|
||||
# print "Unmapped Key\n"
|
||||
except:
|
||||
raise
|
||||
|
||||
def kybd_update(self):
|
||||
# Annoying hack so viewing changes still see deltas
|
||||
self.last_memory = self.prev_last_memory
|
||||
self.client.update()
|
||||
|
||||
@requires_async
|
||||
def toggle_signed(self):
|
||||
self.view_style['unsigned'] = not self.view_style['unsigned']
|
||||
self.kybd_update()
|
||||
|
||||
@requires_async
|
||||
def toggle_length(self):
|
||||
x = int(math.log(self.view_style['word_size'], 2))
|
||||
x = (x+1)%4
|
||||
x=2**x
|
||||
self.view_style['word_size'] = x
|
||||
if self.args.bytes % self.view_style['word_size'] != 0:
|
||||
# force bytes to be an even multiple of the word_size
|
||||
self.args.bytes &= ~(self.view_style['word_size'] - 1)
|
||||
self.kybd_update()
|
||||
|
||||
@requires_async
|
||||
def dec_mode(self):
|
||||
self.view_style['hex_or_dec'] = 'dec'
|
||||
self.kybd_update()
|
||||
|
||||
@requires_async
|
||||
def hex_mode(self):
|
||||
self.view_style['hex_or_dec'] = 'hex'
|
||||
self.kybd_update()
|
||||
|
||||
@requires_async
|
||||
def inc_row_len(self):
|
||||
x = self.args.bytes + self.view_style['word_size']
|
||||
#force bytes to be an even multiple of the word_size
|
||||
x &= ~(self.view_style['word_size']-1)
|
||||
if x <= self.args.stride:
|
||||
self.args.bytes = x
|
||||
self.kybd_update()
|
||||
|
||||
@requires_async
|
||||
def dec_row_len(self):
|
||||
x = self.args.bytes - self.view_style['word_size']
|
||||
#force bytes to be an even multiple of the word_size
|
||||
x &= ~(self.view_style['word_size']-1)
|
||||
if x > 0:
|
||||
self.args.bytes = x
|
||||
self.kybd_update()
|
||||
|
||||
|
||||
class MemoryStrideViewPlugin(ViewPlugin):
|
||||
plugin_type = 'view'
|
||||
name = 'memorystride'
|
||||
view_class = MemoryStrideView
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue