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
88from .context import Context
99from .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 )
0 commit comments