44#
55
66from __future__ import annotations
7- from typing import Callable , Optional , Mapping , Tuple
7+ from typing import Callable , Optional , Mapping , Tuple , Union
88
99import cmd
1010
@@ -24,7 +24,6 @@ def __init__(self: QlQdb, ql: Qiling, init_hook: str = "", rr: bool = False) ->
2424
2525 self .ql = ql
2626 self .prompt = f"{ color .BOLD } { color .RED } Qdb> { color .END } "
27- self .breakpoints = {}
2827 self ._saved_reg_dump = None
2928 self .bp_list = {}
3029 self .rr = rr
@@ -34,17 +33,10 @@ def __init__(self: QlQdb, ql: Qiling, init_hook: str = "", rr: bool = False) ->
3433
3534 super ().__init__ ()
3635
37- # setup a breakpoint at entry point or user specified address
38- address = self .ql .loader .entry_point if not init_hook else parse_int (init_hook )
39- self .set_breakpoint (address , is_temp = True )
40- self .dbg_hook ()
36+ self .cur_addr = self .ql .loader .entry_point
4137
42- def dbg_hook (self : QlQdb ):
43- """
44- hook every instruction with callback funtion _bp_handler
45- """
46-
47- self .ql .hook_code (self ._bp_handler )
38+ self .do_start ()
39+ self .interactive ()
4840
4941 @property
5042 def cur_addr (self : QlQdb ) -> int :
@@ -67,16 +59,20 @@ def _bp_handler(self: QlQdb, *args) -> None:
6759 internal function for handling once breakpoint hitted
6860 """
6961
70- if (bp := self .bp_list .get (self .cur_addr , None )) is not None :
62+ if (bp := self .bp_list .get (self .cur_addr , None )):
7163
72- if not isinstance (bp , TempBreakpoint ):
73- print (f"{ color .CYAN } [+] hit breakpoint at 0x{ self .cur_addr :08x} { color .END } " )
64+ if isinstance (bp , TempBreakpoint ):
65+ # remove TempBreakpoint once hitted
66+ self .del_breakpoint (bp )
7467
7568 else :
76- # remove TempBreakpoint once hitted
77- self . del_breakpoint ( self . cur_addr )
69+ if bp . hitted :
70+ return
7871
79- self .interactive ()
72+ print (f"{ color .CYAN } [+] hit breakpoint at 0x{ self .cur_addr :08x} { color .END } " )
73+ bp .hitted = True
74+
75+ self .do_context ()
8076
8177 def _save (self : QlQdb , * args ) -> None :
8278 """
@@ -92,12 +88,18 @@ def _restore(self: QlQdb, *args) -> None:
9288
9389 self .ql .restore (self ._states_list .pop ())
9490
95- def _run (self : Qldbg , * args ) -> None :
91+ def _run (self : Qldbg , address : int = 0 , count : int = 0 ) -> None :
9692 """
97- internal function for launching qiling instance
93+ internal function for emulating instruction
9894 """
9995
100- self .ql .run ()
96+ if not address :
97+ address = self .cur_addr
98+
99+ if self .ql .archtype in (QL_ARCH .ARM , QL_ARCH .ARM_THUMB ) and is_thumb (self .ql .reg .cpsr ):
100+ address |= 1
101+
102+ self .ql .emu_start (address , 0 , count = count )
101103
102104 def parseline (self : QlQdb , line : str ) -> Tuple [Optional [str ], Optional [str ], str ]:
103105 """
@@ -126,16 +128,14 @@ def interactive(self: QlQdb, *args) -> None:
126128 initial an interactive interface
127129 """
128130
129- self .do_context ()
130-
131131 return self .cmdloop ()
132132
133133 def run (self : QlQdb , * args ) -> None :
134134 """
135- do nothing, since it's already running when breakpoint hitted
135+ internal command for running debugger
136136 """
137137
138- pass
138+ self . _run ()
139139
140140 def emptyline (self : QlQdb , * args ) -> None :
141141 """
@@ -147,18 +147,9 @@ def emptyline(self: QlQdb, *args) -> None:
147147
148148 def do_run (self : QlQdb , * args ) -> None :
149149 """
150- launch qiling instance from a fresh start
150+ launching qiling instance
151151 """
152152
153- self .ql = Qiling (
154- argv = self .ql .argv ,
155- rootfs = self .ql .rootfs ,
156- verbose = self .ql .verbose ,
157- console = self .ql .console ,
158- log_file = self .ql .log_file ,
159- )
160-
161- self .dbg_hook ()
162153 self ._run ()
163154
164155 def do_context (self : QlQdb , * args ) -> None :
@@ -198,45 +189,54 @@ def do_step(self: QlQdb, *args) -> Optional[bool, None]:
198189 if next_stop is CODE_END :
199190 return True
200191
201- self .bp_list .update ({next_stop : TempBreakpoint ()})
202-
203192 if self .rr :
204193 self ._save ()
205194
206- return True
195+ count = 1
196+ if self .ql .archtype == QL_ARCH .MIPS and next_stop != self .cur_addr + 4 :
197+ # make sure delay slot executed
198+ count = 2
199+
200+ self ._run (count = count )
201+ self .do_context ()
207202
208203 def set_breakpoint (self : QlQdb , address : int , is_temp : bool = False ) -> None :
209204 """
210205 internal function for placing breakpoints
211206 """
212207
213- bp = TempBreakpoint () if is_temp else Breakpoint ()
208+ bp = TempBreakpoint (address ) if is_temp else Breakpoint (address )
209+
210+ bp .hook = self .ql .hook_address (self ._bp_handler , address )
214211
215212 self .bp_list .update ({address : bp })
216213
217- def del_breakpoint (self : QlQdb , address : int ) -> None :
214+ def del_breakpoint (self : QlQdb , bp : Union [ Breakpoint , TempBreakpoint ] ) -> None :
218215 """
219216 internal function for removing breakpoints
220217 """
221218
222- self .bp_list .pop (address , None )
219+ if self .bp_list .pop (bp .addr , None ):
220+ bp .hook .remove ()
223221
224222 def do_start (self : QlQdb , address : str = "" , * args ) -> None :
225223 """
226- pause at entry point by setting a temporary breakpoint on it
224+ move current context to ql.loader.entry_point
227225 """
228226
229- # entry = self.ql.loader.entry_point # ld.so
230- # entry = self.ql.loader.elf_entry # .text of binary
227+ self . cur_addr = self .ql .loader .entry_point # ld.so
228+ # self.cur_addr = self.ql.loader.elf_entry # .text of binary
231229
232- self ._run ()
230+ # need a proper method for this
231+ # self.ql.restore(self._init_state)
232+
233+ self .do_context ()
233234
234235 def do_breakpoint (self : QlQdb , address : str = "" ) -> None :
235236 """
236237 set breakpoint on specific address
237238 """
238239
239- # address = parse_int(address) if address else self.ql.reg.arch_pc
240240 address = parse_int (address ) if address else self .cur_addr
241241
242242 self .set_breakpoint (address )
@@ -249,10 +249,10 @@ def do_continue(self: QlQdb, address: str = "") -> None:
249249 """
250250
251251 if address :
252- self . cur_addr = parse_int (address )
252+ address = parse_int (address )
253253
254254 print (f"{ color .CYAN } continued from 0x{ self .cur_addr :08x} { color .END } " )
255- return True
255+ self . _run ( address )
256256
257257 def do_examine (self : QlQdb , line : str ) -> None :
258258 """
@@ -302,7 +302,7 @@ def do_quit(self: QlQdb, *args) -> bool:
302302 """
303303
304304 self .ql .stop ()
305- return True
305+ exit ()
306306
307307 do_r = do_run
308308 do_s = do_step
0 commit comments