Skip to content

Commit 113ead0

Browse files
committed
Enable the MCU feature
1 parent 1483c71 commit 113ead0

File tree

3 files changed

+80
-31
lines changed

3 files changed

+80
-31
lines changed

qiling/const.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class QL_OS(IntEnum):
3030
DOS = 206
3131
EVM = 207
3232
QNX = 208
33+
CORTEX_M = 109
3334

3435
class QL_VERBOSE(IntEnum):
3536
OFF = 0
@@ -50,13 +51,17 @@ class QL_INTERCEPT(IntEnum):
5051

5152
QL_DEBUGGER_ALL = (QL_DEBUGGER.IDAPRO, QL_DEBUGGER.GDB, QL_DEBUGGER.QDB)
5253

54+
QL_ARCH_MCU32 = (QL_ARCH.CORTEX_M,)
5355
QL_ARCH_ENDIAN = (QL_ARCH.MIPS, QL_ARCH.ARM)
5456
QL_ARCH_1BIT = (QL_ARCH.EVM,)
5557
QL_ARCH_16BIT = (QL_ARCH.A8086,)
56-
QL_ARCH_32BIT = (QL_ARCH.ARM, QL_ARCH.ARM_THUMB, QL_ARCH.MIPS, QL_ARCH.X86)
58+
QL_ARCH_32BIT = (QL_ARCH.ARM, QL_ARCH.ARM_THUMB, QL_ARCH.MIPS, QL_ARCH.X86) + QL_ARCH_MCU32
5759
QL_ARCH_64BIT = (QL_ARCH.ARM64, QL_ARCH.X8664)
60+
QL_ARCH_MCU32 = (QL_ARCH.CORTEX_M,)
61+
QL_ARCH_MCU = QL_ARCH_MCU32
5862

5963
QL_OS_NONPID = (QL_OS.DOS, QL_OS.UEFI)
64+
QL_ARCH_HARDWARE = QL_ARCH_MCU
6065
QL_ARCH_NONEOS = (QL_ARCH.EVM,)
6166
QL_OS_POSIX = (QL_OS.LINUX, QL_OS.FREEBSD, QL_OS.MACOS, QL_OS.QNX)
6267
QL_OS_ALL = QL_OS_POSIX + QL_OS_NONPID + (QL_OS.WINDOWS,)
@@ -85,9 +90,11 @@ def __reverse_enum(e: EnumMeta) -> Mapping[str, __QL_CE]:
8590
QL_OS.WINDOWS : "PE",
8691
QL_OS.UEFI : "PE_UEFI",
8792
QL_OS.DOS : "DOS",
88-
QL_OS.EVM : "EVM"
93+
QL_OS.EVM : "EVM",
94+
QL_ARCH.CORTEX_M : "MCU",
8995
}
9096

9197
arch_os_map = {
92-
QL_ARCH.EVM: QL_OS.EVM
98+
QL_ARCH.EVM: QL_OS.EVM,
99+
QL_ARCH.CORTEX_M: QL_OS.CORTEX_M,
93100
}

qiling/core.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
from .arch.arch import QlArch
1717
from .os.os import QlOs
1818
from .os.memory import QlMemoryManager
19+
from .hw.hw import QlHwManager
1920
from .loader.loader import QlLoader
2021

21-
from .const import QL_ARCH_ENDIAN, QL_ENDIAN, QL_OS, QL_VERBOSE, QL_ARCH_NONEOS
22+
from .const import QL_ARCH_ENDIAN, QL_ENDIAN, QL_OS, QL_VERBOSE, QL_ARCH_NONEOS, QL_ARCH_HARDWARE
2223
from .exception import QlErrorFileNotFound, QlErrorArch, QlErrorOsType, QlErrorOutput
2324
from .utils import *
2425
from .core_struct import QlCoreStructs
@@ -170,7 +171,7 @@ def __init__(
170171
#####################
171172
# Profile & Logging #
172173
#####################
173-
self._profile, debugmsg = profile_setup(self.ostype, self.profile, self)
174+
self._profile, debugmsg = profile_setup(self)
174175

175176
# Log's configuration
176177

@@ -208,6 +209,9 @@ def __init__(
208209
if self.archtype not in QL_ARCH_NONEOS:
209210
self._mem = component_setup("os", "memory", self)
210211
self._reg = component_setup("arch", "register", self)
212+
213+
if self.archtype in QL_ARCH_HARDWARE:
214+
self._hw = component_setup("hw", "hw", self)
211215

212216
self._arch = arch_setup(self.archtype, self)
213217

@@ -220,23 +224,25 @@ def __init__(
220224
self.arch.utils.setup_output()
221225

222226
if (self.archtype not in QL_ARCH_NONEOS):
223-
self._os = os_setup(self.archtype, self.ostype, self)
227+
if (self.archtype not in QL_ARCH_HARDWARE):
228+
self._os = os_setup(self.archtype, self.ostype, self)
224229

225-
if stdin is not None:
226-
self._os.stdin = stdin
230+
if stdin is not None:
231+
self._os.stdin = stdin
227232

228-
if stdout is not None:
229-
self._os.stdout = stdout
233+
if stdout is not None:
234+
self._os.stdout = stdout
230235

231-
if stderr is not None:
232-
self._os.stderr = stderr
236+
if stderr is not None:
237+
self._os.stderr = stderr
233238

234239
# Run the loader
235240
self.loader.run()
236241

237242
if (self.archtype not in QL_ARCH_NONEOS):
238-
# Add extra guard options when configured to do so
239-
self._init_stop_guard()
243+
if (self.archtype not in QL_ARCH_HARDWARE):
244+
# Add extra guard options when configured to do so
245+
self._init_stop_guard()
240246

241247
#####################
242248
# Qiling Components #
@@ -258,6 +264,14 @@ def reg(self) -> "QlRegisterManager":
258264
"""
259265
return self._reg
260266

267+
@property
268+
def hw(self) -> "QlHwManager":
269+
""" Qiling hardware manager.
270+
271+
Example:
272+
"""
273+
return self._hw
274+
261275

262276
@property
263277
def arch(self) -> "QlArch":
@@ -630,6 +644,7 @@ def stop_options(self) -> "QlStopOptions":
630644
return self._stop_options
631645

632646
def __enable_bin_patch(self):
647+
633648
for addr, code in self.patch_bin:
634649
self.mem.write(self.loader.load_address + addr, code)
635650

@@ -692,13 +707,20 @@ def run(self, begin=None, end=None, timeout=0, count=0, code = None):
692707
self.exit_point = end
693708
self.timeout = timeout
694709
self.count = count
710+
self.end = end
695711

696712
if self.archtype in QL_ARCH_NONEOS:
697713
if code == None:
698714
return self.arch.run(self._code)
699715
else:
700716
return self.arch.run(code)
701717

718+
if self.archtype in QL_ARCH_HARDWARE:
719+
self.__enable_bin_patch()
720+
if self.count == 0:
721+
self.count = -1
722+
return self.arch.run(count=self.count, end=self.end)
723+
702724
self.write_exit_trap()
703725

704726
# init debugger
@@ -859,7 +881,4 @@ def emu_start(self, begin, end, timeout=0, count=0):
859881
self.uc.emu_start(begin, end, timeout, count)
860882

861883
if self._internal_exception != None:
862-
raise self._internal_exception
863-
864-
def __del__(self):
865-
del self._uc
884+
raise self._internal_exception

qiling/utils.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@
1515
from unicorn import UC_ERR_READ_UNMAPPED, UC_ERR_FETCH_UNMAPPED
1616

1717
from .exception import *
18-
from .const import QL_ARCH_NONEOS, QL_VERBOSE, QL_ARCH, QL_ENDIAN, QL_OS, QL_DEBUGGER, QL_ARCH_1BIT, QL_ARCH_16BIT, QL_ARCH_32BIT, QL_ARCH_64BIT
19-
from .const import debugger_map, arch_map, os_map, arch_os_map, loader_map
18+
from .const import (
19+
QL_VERBOSE, QL_ENDIAN,
20+
QL_ARCH, QL_OS, QL_DEBUGGER,
21+
QL_ARCH_HARDWARE, QL_ARCH_NONEOS,
22+
QL_ARCH_1BIT, QL_ARCH_16BIT, QL_ARCH_32BIT, QL_ARCH_64BIT,
23+
debugger_map, arch_map, os_map, arch_os_map, loader_map
24+
)
2025

2126
FMT_STR = "%(levelname)s\t%(message)s"
2227

@@ -157,7 +162,7 @@ def wrapper(*args, **kw):
157162
try:
158163
return func(*args, **kw)
159164
except BaseException as e:
160-
ql.os.stop()
165+
ql.stop()
161166
ql._internal_exception = e
162167

163168
return wrapper
@@ -208,9 +213,9 @@ def ostype_convert(ostype: str) -> Optional[QL_OS]:
208213
def arch_convert_str(arch: QL_ARCH) -> Optional[str]:
209214
return __reverse_mapping(arch_map).get(arch)
210215

211-
def arch_convert(arch: str) -> Optional[QL_ARCH]:
216+
def arch_convert(arch: str) -> Optional[QL_ARCH]:
212217
return arch_map.get(arch)
213-
218+
214219
def arch_os_convert(arch):
215220
adapter = {}
216221
adapter.update(arch_os_map)
@@ -480,22 +485,40 @@ def os_setup(archtype: QL_ARCH, ostype: QL_OS, ql):
480485
return ql_get_module_function(f"qiling.os.{ostype_str.lower()}.{ostype_str.lower()}", function_name)(ql)
481486

482487

483-
def profile_setup(ostype, profile, ql):
488+
def profile_setup(ql):
489+
if ql.archtype in QL_ARCH_HARDWARE:
490+
return ql_hw_profile_setup(ql)
491+
484492
_profile = "Default"
485-
if profile != None:
486-
_profile = profile
487-
493+
494+
if ql.profile != None:
495+
_profile = ql.profile
488496
debugmsg = "Profile: %s" % _profile
489497

490-
os_profile = os.path.join(os.path.dirname(os.path.abspath(__file__)), "profiles", ostype_convert_str(ostype) + ".ql")
498+
os_profile = os.path.join(os.path.dirname(os.path.abspath(__file__)), "profiles", ostype_convert_str(ql.ostype) + ".ql")
491499

492-
if profile:
493-
profiles = [os_profile, profile]
500+
if ql.profile:
501+
profiles = [os_profile, ql.profile]
494502
else:
495503
profiles = [os_profile]
496504

497505
config = configparser.ConfigParser()
498506
config.read(profiles)
507+
508+
return config, debugmsg
509+
510+
def ql_hw_profile_setup(ql):
511+
config = configparser.ConfigParser()
512+
debugmsg = "Profile: %s" % ql.profile
513+
514+
profile_name = '%s.ql' % ql.profile
515+
profile_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "profiles")
516+
517+
for path, _, files in os.walk(profile_dir):
518+
if profile_name in files:
519+
config.read(os.path.join(profile_dir, path, profile_name))
520+
break
521+
499522
return config, debugmsg
500523

501524
def ql_resolve_logger_level(verbose: QL_VERBOSE) -> int:
@@ -592,4 +615,4 @@ def verify_ret(ql, err):
592615
else:
593616
raise
594617
else:
595-
raise
618+
raise

0 commit comments

Comments
 (0)