diff --git a/riscemu/Executable.py b/riscemu/Executable.py index c1f4821..46e2978 100644 --- a/riscemu/Executable.py +++ b/riscemu/Executable.py @@ -1,7 +1,7 @@ from dataclasses import dataclass, field from typing import Dict, List, Tuple, Union, Optional from .Exceptions import * -from .helpers import parse_numeric_argument, align_addr +from .helpers import * import typing @@ -127,7 +127,7 @@ class LoadedMemorySection: name: str base: int size: int - content: Union[List[LoadedInstruction], bytearray] + content: Union[List[LoadedInstruction], bytearray] = field(repr=False) flags: MemoryFlags def read(self, offset: int, size: int): @@ -162,6 +162,53 @@ class LoadedMemorySection: for i in range(size): self.content[offset + i] = data[i] + def dump(self, at_addr=None, fmt='hex', max_rows=10, group=4, bytes_per_row=16, all=False): + highlight = -1 + if at_addr is None: + at_addr = self.base + else: + highlight = at_addr - self.base + + at_off = at_addr - self.base + start = max(align_addr(at_off - ((max_rows * bytes_per_row) // 2), 8) - 8, 0) + if all: + end = self.size + else: + end = min(start + (max_rows * bytes_per_row), self.size) + + + fmt_str = " 0x{:0" + str(ceil(log(self.base + end, 16))) + "X}: {}" + + if self.flags.executable: + # this section holds instructions! + start = max(self.base - at_addr - (max_rows // 2), 0) + end = min(self.size, start + max_rows) + print(FMT_BOLD + FMT_MAGENTA + "MemorySection {} at base 0x{:08X}, viewing {} instructions:".format( + self.name, self.base, end - start + ) + FMT_NONE) + for i in range(start, end): + if i == highlight: + ins = FMT_UNDERLINE + FMT_ORANGE + repr(self.content[i]) + FMT_NONE + else: + ins = repr(self.content[i]) + print(fmt_str.format(self.base + i, ins)) + else: + print(FMT_BOLD + FMT_MAGENTA + "MemorySection {} at base 0x{:08X}, viewing {} bytes:".format( + self.name, self.base, end - start + ) + FMT_NONE) + for i in range(start, end, bytes_per_row): + data = self.content[start + i: min(start + i + bytes_per_row, end)] + if start + i <= highlight <= start + i + bytes_per_row: + # do hightlight here! + hi_ind = (highlight - start - i) // group + print(fmt_str.format(self.base + start + i, format_bytes(data, fmt, group, highlight=hi_ind))) + else: + print(fmt_str.format(self.base + start + i, format_bytes(data, fmt, group))) + if end == self.size: + print(FMT_BOLD + FMT_MAGENTA + "End of section!" + FMT_NONE) + else: + print(FMT_BOLD + FMT_MAGENTA + "..." + FMT_NONE) + class LoadedExecutable: """ diff --git a/riscemu/helpers.py b/riscemu/helpers.py index b5be871..a3e0550 100644 --- a/riscemu/helpers.py +++ b/riscemu/helpers.py @@ -1,5 +1,7 @@ +from math import log10, ceil, log from .Exceptions import NumberFormatException + def align_addr(addr: int, to_bytes: int = 8): """ align an address to `to_bytes` (meaning addr & to_bytes = 0) @@ -23,7 +25,7 @@ def int_to_bytes(val, bytes=4, unsigned=False): if unsigned and val < 0: raise NumberFormatException("unsigned negative number!") return bytearray([ - (val >> ((bytes-i-1) * 8)) & 0xFF for i in range(bytes) + (val >> ((bytes - i - 1) * 8)) & 0xFF for i in range(bytes) ]) @@ -44,7 +46,7 @@ def int_from_bytes(bytes, unsigned=False): def to_unsigned(num: int, bytes=4): if num < 0: - return 2**(bytes * 8) + num + return 2 ** (bytes * 8) + num return num @@ -53,6 +55,7 @@ def to_signed(num: int, bytes=4): return num - 2 ** (8 * bytes) return num + # Colors FMT_RED = '\033[31m' @@ -66,3 +69,36 @@ FMT_NONE = '\033[0m' FMT_UNDERLINE = '\033[4m' FMT_ERROR = FMT_RED + FMT_BOLD + + +def create_chunks(my_list, chunk_size): + return [my_list[i:i + chunk_size] for i in range(0, len(my_list), chunk_size)] + + +def apply_highlight(item, ind, hi_ind): + """ + applies some hightlight such as underline to item if ind == hi_ind + """ + if ind == hi_ind: + return FMT_UNDERLINE + FMT_ORANGE + item + FMT_NONE + return item + + +def highlight_in_list(items, hi_ind): + return " ".join([apply_highlight(item, i, hi_ind) for i, item in enumerate(items)]) + + +def format_bytes(bytes, fmt, group=1, highlight=-1): + chunks = create_chunks(bytes, group) + if fmt == 'hex': + return highlight_in_list(['0x{}'.format(ch.hex()) for ch in chunks], highlight) + if fmt == 'int': + spc = str(ceil(log10(2 ** (group * 8 - 1))) + 1) + return highlight_in_list([('{:0' + spc + 'd}').format(int_from_bytes(ch)) for ch in chunks], highlight) + if fmt == 'uint': + spc = str(ceil(log10(2 ** (group * 8)))) + return highlight_in_list([('{:0' + spc + 'd}').format(int_from_bytes(ch, unsigned=True)) for ch in chunks], + highlight) + if fmt == 'ascii': + spc = str(4 * group) + return highlight_in_list([('{:>' + spc + '}').format(ch.decode('ascii')) for ch in chunks], highlight)