|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# |
| 3 | +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework |
| 4 | +# |
| 5 | + |
| 6 | +from qiling.utils import ql_get_module_function |
| 7 | +from qiling.const import QL_ARCH |
| 8 | + |
| 9 | +from .context import Context |
| 10 | +from .arch import ArchCORTEX_M, ArchARM, ArchMIPS, ArchX86 |
| 11 | + |
| 12 | +class MemoryManager(Context, ArchX86, ArchCORTEX_M, ArchARM, ArchMIPS): |
| 13 | + """ |
| 14 | + memory manager for handing memory access |
| 15 | + """ |
| 16 | + |
| 17 | + def __init__(self, ql): |
| 18 | + super().__init__(ql) |
| 19 | + |
| 20 | + for arch in ("ArchARM", "ArchMIPS", "ArchCORTEX_M", "ArchX86"): |
| 21 | + if ql.archtype.name in str(arch): |
| 22 | + imp_arch = ql_get_module_function("qiling.debugger.qdb.arch", arch) |
| 23 | + |
| 24 | + imp_arch.__init__(self) |
| 25 | + |
| 26 | + self.DEFAULT_FMT = ('x', 4, 1) |
| 27 | + |
| 28 | + self.FORMAT_LETTER = { |
| 29 | + "o", # octal |
| 30 | + "x", # hex |
| 31 | + "d", # decimal |
| 32 | + "u", # unsigned decimal |
| 33 | + "t", # binary |
| 34 | + "f", # float |
| 35 | + "a", # address |
| 36 | + "i", # instruction |
| 37 | + "c", # char |
| 38 | + "s", # string |
| 39 | + "z", # hex, zero padded on the left |
| 40 | + } |
| 41 | + |
| 42 | + self.SIZE_LETTER = { |
| 43 | + "b": 1, # 1-byte, byte |
| 44 | + "h": 2, # 2-byte, halfword |
| 45 | + "w": 4, # 4-byte, word |
| 46 | + "g": 8, # 8-byte, giant |
| 47 | + } |
| 48 | + |
| 49 | + def extract_count(self, t): |
| 50 | + return "".join([s for s in t if s.isdigit()]) |
| 51 | + |
| 52 | + def get_fmt(self, text): |
| 53 | + f, s, c = self.DEFAULT_FMT |
| 54 | + if self.extract_count(text): |
| 55 | + c = int(self.extract_count(text)) |
| 56 | + |
| 57 | + for char in text.strip(str(c)): |
| 58 | + if char in self.SIZE_LETTER.keys(): |
| 59 | + s = self.SIZE_LETTER.get(char) |
| 60 | + |
| 61 | + elif char in self.FORMAT_LETTER: |
| 62 | + f = char |
| 63 | + |
| 64 | + return (f, s, c) |
| 65 | + |
| 66 | + def fmt_unpack(self, bs: bytes, sz: int) -> int: |
| 67 | + return { |
| 68 | + 1: lambda x: x[0], |
| 69 | + 2: self.ql.unpack16, |
| 70 | + 4: self.ql.unpack32, |
| 71 | + 8: self.ql.unpack64, |
| 72 | + }.get(sz)(bs) |
| 73 | + |
| 74 | + def parse(self, line: str): |
| 75 | + args = line.split() |
| 76 | + |
| 77 | + if line.startswith("/"): # followed by format letter and size letter |
| 78 | + |
| 79 | + fmt, *rest = line.strip("/").split() |
| 80 | + |
| 81 | + rest = "".join(rest) |
| 82 | + |
| 83 | + fmt = self.get_fmt(fmt) |
| 84 | + |
| 85 | + elif len(args) == 1: # only address |
| 86 | + rest = args[0] |
| 87 | + fmt = self.DEFAULT_FMT |
| 88 | + |
| 89 | + else: |
| 90 | + rest = args |
| 91 | + |
| 92 | + if self.ql.archtype in (QL_ARCH.ARM, QL_ARCH.ARM_THUMB): |
| 93 | + rest = rest.replace("fp", "r11") |
| 94 | + |
| 95 | + elif self.ql.archtype == QL_ARCH.MIPS: |
| 96 | + rest = rest.replace("fp", "s8") |
| 97 | + |
| 98 | + # for supporting addition of register with constant value |
| 99 | + elems = rest.split("+") |
| 100 | + elems = [elem.strip("$") for elem in elems] |
| 101 | + |
| 102 | + items = [] |
| 103 | + |
| 104 | + for elem in elems: |
| 105 | + if elem in self.ql.reg.register_mapping.keys(): |
| 106 | + if (value := self.ql.reg.read(elem)): |
| 107 | + items.append(value) |
| 108 | + else: |
| 109 | + items.append(self.read_int(elem)) |
| 110 | + |
| 111 | + addr = sum(items) |
| 112 | + |
| 113 | + ft, sz, ct = fmt |
| 114 | + |
| 115 | + if ft == "i": |
| 116 | + |
| 117 | + for offset in range(addr, addr+ct*4, 4): |
| 118 | + line = self.disasm(offset) |
| 119 | + if line: |
| 120 | + print(f"0x{line.address:x}: {line.mnemonic}\t{line.op_str}") |
| 121 | + |
| 122 | + print() |
| 123 | + |
| 124 | + else: |
| 125 | + lines = 1 if ct <= 4 else math.ceil(ct / 4) |
| 126 | + |
| 127 | + mem_read = [] |
| 128 | + for offset in range(ct): |
| 129 | + # append data if read successfully, otherwise return error message |
| 130 | + if (data := self.try_read(addr+(offset*sz), sz))[0] is not None: |
| 131 | + mem_read.append(data[0]) |
| 132 | + |
| 133 | + else: |
| 134 | + return data[1] |
| 135 | + |
| 136 | + for line in range(lines): |
| 137 | + offset = line * sz * 4 |
| 138 | + print(f"0x{addr+offset:x}:\t", end="") |
| 139 | + |
| 140 | + idx = line * self.ql.pointersize |
| 141 | + for each in mem_read[idx:idx+self.ql.pointersize]: |
| 142 | + data = self.fmt_unpack(each, sz) |
| 143 | + prefix = "0x" if ft in ("x", "a") else "" |
| 144 | + pad = '0' + str(sz*2) if ft in ('x', 'a', 't') else '' |
| 145 | + ft = ft.lower() if ft in ("x", "o", "b", "d") else ft.lower().replace("t", "b").replace("a", "x") |
| 146 | + print(f"{prefix}{data:{pad}{ft}}\t", end="") |
| 147 | + |
| 148 | + print() |
| 149 | + |
| 150 | + return True |
0 commit comments