Skip to content

Commit a89a338

Browse files
committed
make some arch-sepecific member variable to property
1 parent 1d7968e commit a89a338

File tree

6 files changed

+160
-117
lines changed

6 files changed

+160
-117
lines changed

qiling/debugger/qdb/arch/arch.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,19 @@
44
#
55

66

7+
from qiling.const import QL_ARCH
78

89
class Arch:
910
"""
1011
base class for arch
1112
"""
1213

13-
_SUPPORTED_ARCH = ["ArchARM", "ArchCORTEX_M", "ArchMIPS", "ArchX86"]
14-
15-
# FIXME: this is a dirty hack for setup archtype at initialization phase
16-
@staticmethod
17-
def set_archtype(self):
18-
for archtype in self._SUPPORTED_ARCH:
19-
for each_type in type(self).mro():
20-
if archtype in str(each_type):
21-
return archtype
22-
2314
def __init__(self):
24-
self.arch_insn_size = 4
25-
self.archtype = self.set_archtype(self)
15+
pass
16+
17+
@property
18+
def arch_insn_size(self):
19+
return 4
2620

2721
def read_insn(self, address: int):
2822
return self.read_mem(address, self.arch_insn_size)

qiling/debugger/qdb/arch/arch_arm.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,19 @@
1010
class ArchARM(Arch):
1111
def __init__(self):
1212
super().__init__()
13-
self.regs = (
13+
14+
@property
15+
def regs(self):
16+
return (
1417
"r0", "r1", "r2", "r3",
1518
"r4", "r5", "r6", "r7",
1619
"r8", "r9", "r10", "r11",
1720
"r12", "sp", "lr", "pc",
1821
)
1922

20-
self.regs_need_swapped = {
23+
@property
24+
def regs_need_swapped(self):
25+
return {
2126
"sl": "r10",
2227
"ip": "r12",
2328
"fp": "r11",

qiling/debugger/qdb/arch/arch_mips.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
class ArchMIPS(Arch):
1111
def __init__(self):
1212
super().__init__()
13-
self.regs = (
13+
14+
@property
15+
def regs(self):
16+
return (
1417
"gp", "at", "v0", "v1",
1518
"a0", "a1", "a2", "a3",
1619
"t0", "t1", "t2", "t3",
@@ -21,6 +24,8 @@ def __init__(self):
2124
"ra", "k0", "k1", "pc",
2225
)
2326

24-
self.regs_need_swapped = {
27+
@property
28+
def regs_need_swapped(self):
29+
return {
2530
"fp": "s8",
2631
}

qiling/debugger/qdb/arch/arch_x86.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,14 @@
1010
class ArchX86(Arch):
1111
def __init__(self):
1212
super().__init__()
13-
self.regs = (
13+
14+
@property
15+
def arch_insn_size(self):
16+
return 15
17+
18+
@property
19+
def regs(self):
20+
return (
1421
"eax", "ebx", "ecx", "edx",
1522
"esp", "ebp", "esi", "edi",
1623
"eip", "ss", "cs", "ds", "es",
@@ -22,7 +29,7 @@ def read_insn(self, address: int) -> bytes:
2229
# always assume the maxium size for disassembler to tell
2330
# what is it exactly.
2431

25-
return self.read_mem(address, 15)
32+
return self.read_mem(address, self.arch_insn_size)
2633

2734
@staticmethod
2835
def get_flags(bits: int) -> Mapping[str, bool]:

qiling/debugger/qdb/memory.py

Lines changed: 129 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,38 @@
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
55

6-
from qiling.utils import ql_get_module_function
6+
from qiling.const import QL_ARCH
77

88
from .context import Context
99
from .arch import ArchCORTEX_M, ArchARM, ArchMIPS, ArchX86
10+
import re, ast, math
1011

11-
class MemoryManager(Context, ArchX86, ArchCORTEX_M, ArchARM, ArchMIPS):
12-
"""
13-
memory manager for handing memory access
14-
"""
1512

16-
def __init__(self, ql):
17-
super().__init__(ql)
1813

19-
for arch in ("ArchARM", "ArchMIPS", "ArchCORTEX_M", "ArchX86"):
20-
if ql.archtype.name in str(arch):
21-
imp_arch = ql_get_module_function("qiling.debugger.qdb.arch", arch)
14+
def setup_memory_Manager(ql):
2215

23-
imp_arch.__init__(self)
16+
arch_type = {
17+
QL_ARCH.X86: ArchX86,
18+
QL_ARCH.MIPS: ArchMIPS,
19+
QL_ARCH.ARM: ArchARM,
20+
QL_ARCH.CORTEX_M: ArchCORTEX_M,
21+
}.get(ql.archtype)
2422

25-
self.DEFAULT_FMT = ('x', 4, 1)
23+
class MemoryManager(Context, arch_type):
24+
"""
25+
memory manager for handing memory access
26+
"""
2627

27-
self.FORMAT_LETTER = {
28+
def __init__(self, ql):
29+
super().__init__(ql)
30+
31+
@property
32+
def get_default_fmt(self):
33+
return ('x', 4, 1)
34+
35+
@property
36+
def get_format_letter(self):
37+
return {
2838
"o", # octal
2939
"x", # hex
3040
"d", # decimal
@@ -38,116 +48,138 @@ def __init__(self, ql):
3848
"z", # hex, zero padded on the left
3949
}
4050

41-
self.SIZE_LETTER = {
42-
"b": 1, # 1-byte, byte
43-
"h": 2, # 2-byte, halfword
44-
"w": 4, # 4-byte, word
45-
"g": 8, # 8-byte, giant
46-
}
47-
48-
def extract_count(self, t):
49-
return "".join([s for s in t if s.isdigit()])
51+
@property
52+
def get_size_letter(self):
53+
return {
54+
"b": 1, # 1-byte, byte
55+
"h": 2, # 2-byte, halfword
56+
"w": 4, # 4-byte, word
57+
"g": 8, # 8-byte, giant
58+
}
5059

51-
def get_fmt(self, text):
52-
f, s, c = self.DEFAULT_FMT
53-
if self.extract_count(text):
54-
c = int(self.extract_count(text))
60+
def extract_count(self, t):
61+
return "".join([s for s in t if s.isdigit()])
5562

56-
for char in text.strip(str(c)):
57-
if char in self.SIZE_LETTER.keys():
58-
s = self.SIZE_LETTER.get(char)
63+
def get_fmt(self, text):
64+
f, s, c = self.get_default_fmt
65+
if self.extract_count(text):
66+
c = int(self.extract_count(text))
5967

60-
elif char in self.FORMAT_LETTER:
61-
f = char
68+
for char in text.strip(str(c)):
69+
if char in self.get_size_letter.keys():
70+
s = self.get_size_letter.get(char)
6271

63-
return (f, s, c)
72+
elif char in self.get_format_letter:
73+
f = char
6474

65-
def fmt_unpack(self, bs: bytes, sz: int) -> int:
66-
return {
67-
1: lambda x: x[0],
68-
2: self.unpack16,
69-
4: self.unpack32,
70-
8: self.unpack64,
71-
}.get(sz)(bs)
75+
return (f, s, c)
7276

73-
def parse(self, line: str):
77+
def fmt_unpack(self, bs: bytes, sz: int) -> int:
78+
return {
79+
1: lambda x: x[0],
80+
2: self.unpack16,
81+
4: self.unpack32,
82+
8: self.unpack64,
83+
}.get(sz)(bs)
7484

75-
# test case
76-
# x/wx address
77-
# x/i address
78-
# x $sp
79-
# x $sp +0xc
80-
# x $sp+0xc
81-
# x $sp + 0xc
85+
def handle_i(self, addr, ct=1):
86+
result = []
8287

83-
if line.startswith("/"): # followed by format letter and size letter
88+
for offset in range(addr, addr+ct*4, 4):
89+
if (line := self.disasm(offset)):
90+
result.append(line)
8491

85-
fmt, *rest = line.strip("/").split()
92+
return result
8693

87-
fmt = self.get_fmt(fmt)
8894

89-
else:
90-
args = line.split()
91-
rest = args[0] if len(args) == 1 else args
92-
fmt = self.DEFAULT_FMT
95+
def parse(self, line: str):
9396

94-
if (regs_dict := getattr(self, "regs_need_swapped", None)):
95-
for each in rest:
96-
if each in regs_dict:
97+
# test case
98+
# x/wx address
99+
# x/i address
100+
# x $sp
101+
# x $sp +0xc
102+
# x $sp+0xc
103+
# x $sp + 0xc
97104

98-
# for simple calculation with register and address
99-
new_line = rest
105+
if line.startswith("/"): # followed by format letter and size letter
100106

101-
# substitue register name with real value
102-
for each_reg in filter(lambda r: len(r) == 3, self.ql.reg.register_mapping.keys()):
103-
if each_reg in new_line:
104-
new_line = re.sub(each_reg, hex(self.read_reg(each_reg)), new_line)
107+
fmt, *rest = line.strip("/").split()
105108

106-
items = []
109+
fmt = self.get_fmt(fmt)
107110

108-
for elem in elems:
109-
if elem in self.ql.reg.register_mapping.keys():
110-
if (value := self.ql.reg.read(elem)):
111-
items.append(value)
112111
else:
113-
items.append(self.read_int(elem))
112+
args = line.split()
114113

115-
addr = sum(items)
114+
rest = args[0] if len(args) == 1 else args
116115

117-
ft, sz, ct = fmt
116+
fmt = self.get_default_fmt
118117

119-
if ft == "i":
118+
if len(rest) == 0:
119+
return
120120

121-
for offset in range(addr, addr+ct*4, 4):
122-
line = self.disasm(offset)
123-
if line:
124-
print(f"0x{line.address:x}: {line.mnemonic}\t{line.op_str}")
121+
line = []
122+
if (regs_dict := getattr(self, "regs_need_swapped", None)):
123+
for each in rest:
124+
for reg in regs_dict:
125+
line.append(regs_dict[each] if each in regs_dict else each)
126+
127+
# for simple calculation with register and address
125128

129+
line = " ".join(line)
130+
# substitue register name with real value
131+
for each_reg in filter(lambda r: len(r) == 2, self.ql.reg.register_mapping):
132+
reg = f"${each_reg}"
133+
if reg in line:
134+
line = re.sub(f"\{reg}", hex(self.ql.reg.read(each_reg)), line)
135+
breakpoint()
136+
137+
class AST_checker(ast.NodeVisitor):
138+
def generic_visit(self, node):
139+
if type(node) in (ast.Module, ast.Expr, ast.BinOp, ast.Constant, ast.Add, ast.Mult, ast.Sub):
140+
ast.NodeVisitor.generic_visit(self, node)
141+
else:
142+
raise ParseError("malform or invalid ast node")
143+
144+
ft, sz, ct = fmt
145+
146+
checker = AST_checker()
147+
ast_tree = ast.parse(line)
148+
checker.visit(ast_tree)
149+
150+
addr = eval(line)
151+
152+
if ft == "i":
153+
output = self.handle_i(addr, ct)
154+
for each in output:
155+
print(f"0x{each.address:x}: {each.mnemonic}\t{each.op_str}")
156+
157+
else:
158+
lines = 1 if ct <= 4 else math.ceil(ct / 4)
126159

127-
else:
128-
lines = 1 if ct <= 4 else math.ceil(ct / 4)
160+
mem_read = []
161+
for offset in range(ct):
162+
# append data if read successfully, otherwise return error message
163+
if (data := self.try_read(addr+(offset*sz), sz))[0] is not None:
164+
mem_read.append(data[0])
129165

130-
mem_read = []
131-
for offset in range(ct):
132-
# append data if read successfully, otherwise return error message
133-
if (data := self.try_read(addr+(offset*sz), sz))[0] is not None:
134-
mem_read.append(data[0])
166+
else:
167+
return data[1]
135168

136-
else:
137-
return data[1]
169+
for line in range(lines):
170+
offset = line * sz * 4
171+
print(f"0x{addr+offset:x}:\t", end="")
138172

139-
for line in range(lines):
140-
offset = line * sz * 4
141-
print(f"0x{addr+offset:x}:\t", end="")
173+
idx = line * self.ql.pointersize
174+
for each in mem_read[idx:idx+self.ql.pointersize]:
175+
data = self.fmt_unpack(each, sz)
176+
prefix = "0x" if ft in ("x", "a") else ""
177+
pad = '0' + str(sz*2) if ft in ('x', 'a', 't') else ''
178+
ft = ft.lower() if ft in ("x", "o", "b", "d") else ft.lower().replace("t", "b").replace("a", "x")
179+
print(f"{prefix}{data:{pad}{ft}}\t", end="")
142180

143-
idx = line * self.ql.pointersize
144-
for each in mem_read[idx:idx+self.ql.pointersize]:
145-
data = self.fmt_unpack(each, sz)
146-
prefix = "0x" if ft in ("x", "a") else ""
147-
pad = '0' + str(sz*2) if ft in ('x', 'a', 't') else ''
148-
ft = ft.lower() if ft in ("x", "o", "b", "d") else ft.lower().replace("t", "b").replace("a", "x")
149-
print(f"{prefix}{data:{pad}{ft}}\t", end="")
181+
print()
150182

151-
print()
183+
return True
152184

153-
return True
185+
return MemoryManager(ql)

qiling/debugger/qdb/qdb.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from qiling.debugger import QlDebugger
1313

1414
from .utils import setup_context_render, setup_branch_predictor, SnapshotManager
15-
from .memory import MemoryManager
15+
from .memory import setup_memory_Manager
1616
from .misc import parse_int, Breakpoint, TempBreakpoint
1717
from .const import color
1818

@@ -35,7 +35,7 @@ def __init__(self, ql: Qiling, init_hook: str = "", rr: bool = False) -> None:
3535
self.bp_list = {}
3636

3737
self.rr = SnapshotManager(ql) if rr else None
38-
self.mm = MemoryManager(ql)
38+
self.mm = setup_memory_Manager(ql)
3939
self.predictor = setup_branch_predictor(ql)
4040
self.render = setup_context_render(ql, self.predictor)
4141

0 commit comments

Comments
 (0)