Skip to content

Commit f058e67

Browse files
committed
Handle the interrupt infinite loop
1 parent 19646ae commit f058e67

File tree

1 file changed

+67
-53
lines changed

1 file changed

+67
-53
lines changed

qiling/arch/cortex_m.py

Lines changed: 67 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,60 @@
77
from capstone import Cs, CS_ARCH_ARM, CS_MODE_ARM, CS_MODE_MCLASS, CS_MODE_THUMB
88
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KS_MODE_THUMB
99

10+
from contextlib import ContextDecorator
11+
1012
from qiling.const import QL_VERBOSE
1113
from qiling.exception import QlErrorNotImplemented
1214

1315
from .arm import QlArchARM
1416
from .arm_const import IRQ, EXC_RETURN, CONTROL, EXCP
1517

18+
class QlInterruptContext(ContextDecorator):
19+
def __init__(self, ql):
20+
self.ql = ql
21+
self.reg_context = ['xpsr', 'pc', 'lr', 'r12', 'r3', 'r2', 'r1', 'r0']
22+
23+
def __enter__(self):
24+
for reg in self.reg_context:
25+
val = self.ql.reg.read(reg)
26+
self.ql.arch.stack_push(val)
27+
28+
if self.ql.verbose >= QL_VERBOSE.DISASM:
29+
self.ql.log.info(f'Enter into interrupt')
30+
31+
def __exit__(self, *exc):
32+
retval = self.ql.arch.get_pc()
33+
34+
if retval & EXC_RETURN.MASK != EXC_RETURN.MASK:
35+
self.ql.log.warning('Interrupt Crash')
36+
self.ql.stop()
37+
38+
else:
39+
# Exit handler mode
40+
self.ql.reg.write('ipsr', 0)
41+
42+
# switch the stack accroding exc_return
43+
old_ctrl = self.ql.reg.read('control')
44+
if retval & EXC_RETURN.RETURN_SP:
45+
self.ql.reg.write('control', old_ctrl | CONTROL.SPSEL)
46+
else:
47+
self.ql.reg.write('control', old_ctrl & ~CONTROL.SPSEL)
48+
49+
# Restore stack
50+
for reg in reversed(self.reg_context):
51+
val = self.ql.arch.stack_pop()
52+
if reg == 'xpsr':
53+
self.ql.reg.write('XPSR_NZCVQG', val)
54+
else:
55+
self.ql.reg.write(reg, val)
56+
57+
if self.ql.verbose >= QL_VERBOSE.DISASM:
58+
self.ql.log.info('Exit from interrupt')
1659

1760
class QlArchCORTEX_M(QlArchARM):
1861
def __init__(self, ql):
1962
super().__init__(ql)
2063

21-
self.reg_context = ['xpsr', 'pc', 'lr', 'r12', 'r3', 'r2', 'r1', 'r0']
22-
2364
def intr_cb(ql, intno):
2465
if intno == EXCP.SWI:
2566
ql.hw.nvic.set_pending(IRQ.SVCALL)
@@ -48,78 +89,51 @@ def step(self):
4889
self.ql.emu_start(self.get_pc(), 0, count=1)
4990
self.ql.hw.step()
5091

92+
def stop(self):
93+
self.runable = False
94+
5195
def run(self, count=-1, end=None):
96+
self.runable = True
97+
5298
if type(end) is int:
53-
end |= 1
99+
end |= 1
54100

55-
while count != 0:
101+
while self.runable and count != 0:
56102
if self.get_pc() == end:
57103
break
58104

59105
self.step()
60-
count -= 1
106+
count -= 1
61107

62108
def is_handler_mode(self):
63109
return self.ql.reg.read('ipsr') > 1
64110

65111
def using_psp(self):
66112
return not self.is_handler_mode() and (self.ql.reg.read('control') & CONTROL.SPSEL) > 0
67113

68-
def enter_intr(self):
69-
# Save Stack
70-
for reg in self.reg_context:
71-
val = self.ql.reg.read(reg)
72-
self.ql.arch.stack_push(val)
73-
74-
if self.ql.verbose >= QL_VERBOSE.DISASM:
75-
self.ql.log.info(f'Enter into interrupt')
76-
77-
def exit_intr(self):
78-
# Exit handler mode
79-
self.ql.reg.write('ipsr', 0)
80-
81-
# switch the stack accroding exc_return
82-
old_ctrl = self.ql.reg.read('control')
83-
if self.ql.arch.get_pc() & EXC_RETURN.RETURN_SP:
84-
self.ql.reg.write('control', old_ctrl | CONTROL.SPSEL)
85-
else:
86-
self.ql.reg.write('control', old_ctrl & ~CONTROL.SPSEL)
87-
88-
# Restore stack
89-
for reg in reversed(self.reg_context):
90-
val = self.ql.arch.stack_pop()
91-
if reg == 'xpsr':
92-
self.ql.reg.write('XPSR_NZCVQG', val)
93-
else:
94-
self.ql.reg.write(reg, val)
95-
96-
if self.ql.verbose >= QL_VERBOSE.DISASM:
97-
self.ql.log.info('Exit from interrupt')
114+
def handle_interupt(self, IRQn):
115+
basepri = self.ql.reg.read('basepri') & 0xf0
116+
if basepri and basepri <= self.ql.hw.nvic.get_priority(IRQn):
117+
return
98118

99-
def handle_interupt(self, IRQn):
100119
if IRQn > IRQ.HARD_FAULT and (self.ql.reg.read('primask') & 0x1):
101120
return
102-
121+
103122
if IRQn != IRQ.NMI and (self.ql.reg.read('faultmask') & 0x1):
104123
return
105124

106-
basepri = self.ql.reg.read('basepri') & 0xf0
107-
if basepri != 0 and basepri <= self.ql.hw.nvic.get_priority(IRQn):
108-
return
109-
110125
if self.ql.verbose >= QL_VERBOSE.DISASM:
111-
self.ql.log.info(f'Handle the IRQn: {IRQn}')
112-
113-
isr = IRQn + 16
114-
offset = isr << 2
115-
116-
entry = self.ql.mem.read_ptr(offset)
117-
exc_return = 0xFFFFFFFD if self.ql.arch.using_psp() else 0xFFFFFFF9
126+
self.ql.log.debug(f'Handle the IRQn: {IRQn}')
127+
128+
with QlInterruptContext(self.ql):
129+
isr = IRQn + 16
130+
offset = isr * 4
118131

119-
# Enter handler mode
120-
self.ql.reg.write('ipsr', isr)
132+
entry = self.ql.mem.read_ptr(offset)
133+
exc_return = 0xFFFFFFFD if self.ql.arch.using_psp() else 0xFFFFFFF9
121134

122-
self.ql.reg.write('pc', entry)
123-
self.ql.reg.write('lr', exc_return)
135+
self.ql.reg.write('ipsr', isr)
136+
self.ql.reg.write('pc', entry)
137+
self.ql.reg.write('lr', exc_return)
124138

125-
self.ql.emu_start(self.ql.arch.get_pc(), 0)
139+
self.ql.emu_start(self.ql.arch.get_pc(), 0, count=0xffffff)

0 commit comments

Comments
 (0)