1212import importlib , os
1313
1414from configparser import ConfigParser
15- from typing import Any , Mapping , Optional , Tuple , Type , Union
15+ from typing import TYPE_CHECKING , Any , Callable , Mapping , Optional , Tuple , TypeVar , Union
1616
1717from unicorn import UC_ERR_READ_UNMAPPED , UC_ERR_FETCH_UNMAPPED
1818
1919from qiling .exception import *
2020from qiling .const import QL_ARCH , QL_ENDIAN , QL_OS , QL_DEBUGGER
2121from qiling .const import debugger_map , arch_map , os_map , arch_os_map
2222
23+ if TYPE_CHECKING :
24+ from qiling import Qiling
25+ from qiling .arch .arch import QlArch
26+ from qiling .debugger .debugger import QlDebugger
27+ from qiling .loader .loader import QlLoader
28+ from qiling .os .os import QlOs
29+
30+ T = TypeVar ('T' )
31+ QlClassInit = Callable [['Qiling' ], T ]
32+
2333def catch_KeyboardInterrupt (ql , func ):
2434 def wrapper (* args , ** kw ):
2535 try :
@@ -273,9 +283,12 @@ def ql_guess_emu_env(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], Opt
273283
274284 return arch , ostype , endian
275285
286+ def select_loader (ostype : QL_OS , libcache : bool ) -> QlClassInit ['QlLoader' ]:
287+ if ostype == QL_OS .WINDOWS :
288+ kwargs = {'libcache' : libcache }
276289
277- def loader_setup ( ql , ostype : QL_OS , libcache : bool ) :
278- args = [ libcache ] if ostype == QL_OS . WINDOWS else []
290+ else :
291+ kwargs = {}
279292
280293 module = {
281294 QL_OS .LINUX : r'elf' ,
@@ -295,45 +308,57 @@ def loader_setup(ql, ostype: QL_OS, libcache: bool):
295308
296309 obj = ql_get_module_function (qlloader_path , qlloader_class )
297310
298- return obj (ql , * args )
299-
311+ return partial (obj , ** kwargs )
300312
301- def component_setup (component_type : str , component_name : str , ql ) :
313+ def select_component (component_type : str , component_name : str , ** kwargs ) -> QlClassInit [ Any ] :
302314 component_path = f'qiling.{ component_type } .{ component_name } '
303315 component_class = f'Ql{ component_name .capitalize ()} Manager'
304316
305317 obj = ql_get_module_function (component_path , component_class )
306318
307- return obj ( ql )
319+ return partial ( obj , ** kwargs )
308320
309-
310- def debugger_setup (options : Union [str , bool ], ql ):
321+ def select_debugger (options : Union [str , bool ]) -> Optional [QlClassInit ['QlDebugger' ]]:
311322 if options is True :
312323 options = 'gdb'
313324
314325 if type (options ) is str :
315326 objname , * args = options .split (':' )
327+ dbgtype = debugger_convert (objname )
328+
329+ if dbgtype == QL_DEBUGGER .GDB :
330+ kwargs = dict (zip (('ip' , 'port' ), args ))
331+
332+ elif dbgtype == QL_DEBUGGER .QDB :
333+ kwargs = {}
334+
335+ if 'rr' in args :
336+ kwargs ['rr' ] = True
337+ args .remove ('rr' )
316338
317- if debugger_convert (objname ) not in enum_values (QL_DEBUGGER ):
339+ if args :
340+ kwargs ['init_hook' ] = args [0 ]
341+
342+ else :
318343 raise QlErrorOutput ('Debugger not supported' )
319344
320345 obj = ql_get_module_function (f'qiling.debugger.{ objname } .{ objname } ' , f'Ql{ str .capitalize (objname )} ' )
321346
322- return obj ( ql , * args )
347+ return partial ( obj , ** kwargs )
323348
324349 return None
325350
326- def arch_setup (archtype : QL_ARCH , endian : QL_ENDIAN , thumb : bool , ql ) :
351+ def select_arch (archtype : QL_ARCH , endian : QL_ENDIAN , thumb : bool ) -> QlClassInit [ 'QlArch' ] :
327352 # set endianess and thumb mode for arm-based archs
328353 if archtype == QL_ARCH .ARM :
329- args = [ endian , thumb ]
354+ kwargs = { ' endian' : endian , ' thumb' : thumb }
330355
331356 # set endianess for mips arch
332357 elif archtype == QL_ARCH .MIPS :
333- args = [ endian ]
358+ kwargs = { ' endian' : endian }
334359
335360 else :
336- args = []
361+ kwargs = {}
337362
338363 module = {
339364 QL_ARCH .A8086 : r'x86' ,
@@ -353,8 +378,7 @@ def arch_setup(archtype: QL_ARCH, endian: QL_ENDIAN, thumb: bool, ql):
353378
354379 obj = ql_get_module_function (qlarch_path , qlarch_class )
355380
356- return obj (ql , * args )
357-
381+ return partial (obj , ** kwargs )
358382
359383# This function is extracted from os_setup (QlOsPosix) so I put it here.
360384def ql_syscall_mapping_function (ostype : QL_OS , archtype : QL_ARCH ):
@@ -366,20 +390,16 @@ def ql_syscall_mapping_function(ostype: QL_OS, archtype: QL_ARCH):
366390
367391 return func (archtype )
368392
369-
370- def os_setup (ostype : QL_OS , ql ):
371- qlos_name = ostype_convert_str (ostype )
393+ def select_os (ostype : QL_OS ) -> QlClassInit ['QlOs' ]:
394+ qlos_name = ostype .name
372395 qlos_path = f'qiling.os.{ qlos_name .lower ()} .{ qlos_name .lower ()} '
373396 qlos_class = f'QlOs{ qlos_name .capitalize ()} '
374397
375398 obj = ql_get_module_function (qlos_path , qlos_class )
376399
377- return obj (ql )
378-
379-
380- def profile_setup (ql , ostype : QL_OS , filename : Optional [str ]):
381- ql .log .debug (f'Profile: { filename or "default" } ' )
400+ return partial (obj )
382401
402+ def profile_setup (ostype : QL_OS , filename : Optional [str ]):
383403 # mcu uses a yaml-based config
384404 if ostype == QL_OS .MCU :
385405 import yaml
0 commit comments