Skip to content

Commit bf39f1b

Browse files
committed
Merge remote-tracking branch 'qiling.io/dev' into dev
2 parents 9f27c67 + f714c8f commit bf39f1b

File tree

22 files changed

+1263
-741
lines changed

22 files changed

+1263
-741
lines changed

qiling/arch/arm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def effective_pc(self) -> int:
6868
"""
6969

7070
# append 1 to pc if in thumb mode, or 0 otherwise
71-
return self.regs.pc + int(self.is_thumb)
71+
return self.regs.pc | int(self.is_thumb)
7272

7373
@property
7474
def disassembler(self) -> Cs:

qiling/core.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -737,8 +737,14 @@ def emu_start(self, begin: int, end: int, timeout: int = 0, count: int = 0):
737737
count : max emulation steps (instructions count); unlimited by default
738738
"""
739739

740-
if self._arch.type in (QL_ARCH.ARM, QL_ARCH.CORTEX_M) and self._arch._init_thumb:
741-
begin |= 1
740+
# FIXME: we cannot use arch.is_thumb to determine this because unicorn sets the coresponding bit in cpsr
741+
# only when pc is set. unicorn sets or clears the thumb mode bit based on pc lsb, ignoring the mode it
742+
# was initialized with.
743+
#
744+
# either unicorn is patched to reflect thumb mode in cpsr upon initialization, or we pursue the same logic
745+
# by determining the endianess by address lsb. either way this condition should not be here
746+
if getattr(self.arch, '_init_thumb', False):
747+
begin |= 0b1
742748

743749
# reset exception status before emulation starts
744750
self._internal_exception = None

qiling/debugger/gdb/gdb.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ def __init__(self, ql: Qiling, ip: str = '127.0.0.1', port: int = 9999):
9595
else:
9696
entry_point = ql.os.entry_point
9797

98+
# though linkers set the entry point LSB to indicate arm thumb mode, the
99+
# effective entry point address is aligned. make sure we have it aligned
100+
if hasattr(ql.arch, 'is_thumb'):
101+
entry_point &= ~0b1
102+
98103
# Only part of the binary file will be debugged.
99104
if ql.entry_point is not None:
100105
entry_point = ql.entry_point
@@ -234,7 +239,7 @@ def handle_c(subcmd: str) -> Reply:
234239
reply = f'S{SIGINT:02x}'
235240

236241
else:
237-
if self.ql.arch.regs.arch_pc == self.gdb.last_bp:
242+
if getattr(self.ql.arch, 'effective_pc', self.ql.arch.regs.arch_pc) == self.gdb.last_bp:
238243
# emulation stopped because it hit a breakpoint
239244
reply = f'S{SIGTRAP:02x}'
240245
else:
@@ -666,12 +671,6 @@ def handle_s(subcmd: str) -> Reply:
666671
"""Perform a single step.
667672
"""
668673

669-
# BUG: a known unicorn caching issue causes it to emulate more
670-
# steps than requestes. until that issue is fixed, single stepping
671-
# is essentially broken.
672-
#
673-
# @see: https://github.com/unicorn-engine/unicorn/issues/1606
674-
675674
self.gdb.resume_emu(steps=1)
676675

677676
return f'S{SIGTRAP:02x}'
@@ -709,8 +708,9 @@ def handle_Z(subcmd: str) -> Reply:
709708
# 4 = access watchpoint
710709

711710
if type == 0:
712-
self.gdb.bp_insert(addr)
713-
return REPLY_OK
711+
success = self.gdb.bp_insert(addr, kind)
712+
713+
return REPLY_OK if success else 'E22'
714714

715715
return REPLY_EMPTY
716716

@@ -721,12 +721,9 @@ def handle_z(subcmd: str) -> Reply:
721721
type, addr, kind = (int(p, 16) for p in subcmd.split(','))
722722

723723
if type == 0:
724-
try:
725-
self.gdb.bp_remove(addr)
726-
except ValueError:
727-
return 'E22'
728-
else:
729-
return REPLY_OK
724+
success = self.gdb.bp_remove(addr, kind)
725+
726+
return REPLY_OK if success else 'E22'
730727

731728
return REPLY_EMPTY
732729

qiling/debugger/gdb/utils.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def __init__(self, ql: Qiling, entry_point: int, exit_point: int):
1818
self.ql = ql
1919

2020
self.exit_point = exit_point
21-
self.bp_list = []
21+
self.swbp = set()
2222
self.last_bp = None
2323

2424
def __entry_point_hook(ql: Qiling):
@@ -41,32 +41,44 @@ def dbg_hook(self, ql: Qiling, address: int, size: int):
4141
if address == self.last_bp:
4242
self.last_bp = None
4343

44-
elif address in self.bp_list:
44+
elif address in self.swbp:
4545
self.last_bp = address
4646

4747
ql.log.info(f'{PROMPT} breakpoint hit, stopped at {address:#x}')
4848
ql.stop()
4949

50-
# # TODO: not sure what this is about
51-
# if address + size == self.exit_point:
52-
# ql.log.debug(f'{PROMPT} emulation entrypoint at {self.entry_point:#x}')
53-
# ql.log.debug(f'{PROMPT} emulation exitpoint at {self.exit_point:#x}')
50+
def bp_insert(self, addr: int, size: int):
51+
targets = set(addr + i for i in range(size or 1))
5452

55-
def bp_insert(self, addr: int):
56-
if addr not in self.bp_list:
57-
self.bp_list.append(addr)
58-
self.ql.log.info(f'{PROMPT} breakpoint added at {addr:#x}')
53+
if targets.intersection(self.swbp):
54+
return False
55+
56+
for bp in targets:
57+
self.swbp.add(bp)
58+
59+
self.ql.log.info(f'{PROMPT} breakpoint added at {addr:#x}')
60+
61+
return True
62+
63+
def bp_remove(self, addr: int, size: int) -> bool:
64+
targets = set(addr + i for i in range(size or 1))
65+
66+
if not targets.issubset(self.swbp):
67+
return False
68+
69+
for bp in targets:
70+
self.swbp.remove(bp)
5971

60-
def bp_remove(self, addr: int):
61-
self.bp_list.remove(addr)
6272
self.ql.log.info(f'{PROMPT} breakpoint removed from {addr:#x}')
6373

74+
return True
75+
6476
def resume_emu(self, address: Optional[int] = None, steps: int = 0):
6577
if address is None:
6678
address = self.ql.arch.regs.arch_pc
6779

6880
if getattr(self.ql.arch, 'is_thumb', False):
69-
address |= 1
81+
address |= 0b1
7082

7183
op = f'stepping {steps} instructions' if steps else 'resuming'
7284
self.ql.log.info(f'{PROMPT} {op} from {address:#x}')

qiling/debugger/qdb/arch/arch_arm.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,21 @@
1010
class ArchARM(Arch):
1111
def __init__(self):
1212
super().__init__()
13-
14-
@property
15-
def regs(self):
16-
return (
13+
self._regs = (
1714
"r0", "r1", "r2", "r3",
1815
"r4", "r5", "r6", "r7",
1916
"r8", "r9", "r10", "r11",
2017
"r12", "sp", "lr", "pc",
2118
)
2219

20+
@property
21+
def regs(self):
22+
return self._regs
23+
24+
@regs.setter
25+
def regs(self, regs):
26+
self._regs += regs
27+
2328
@property
2429
def regs_need_swapped(self):
2530
return {

qiling/debugger/qdb/qdb.py

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,7 @@ def bp_handler(ql, address, size, bp_list):
8282

8383
self.cur_addr = self.ql.loader.entry_point
8484

85-
if self.ql.arch.type == QL_ARCH.CORTEX_M:
86-
self._run()
87-
88-
else:
89-
self.init_state = self.ql.save()
85+
self.init_state = self.ql.save()
9086

9187
if self._script:
9288
run_qdb_script(self, self._script)
@@ -118,23 +114,6 @@ def _run(self, address: int = 0, end: int = 0, count: int = 0) -> None:
118114
if not address:
119115
address = self.cur_addr
120116

121-
if self.ql.arch.type == QL_ARCH.CORTEX_M and self.ql.count != 0:
122-
123-
while self.ql.count:
124-
125-
if (bp := self.bp_list.pop(self.cur_addr, None)):
126-
if isinstance(bp, TempBreakpoint):
127-
self.del_breakpoint(bp)
128-
else:
129-
qdb_print(QDB_MSG.INFO, f"hit breakpoint at 0x{self.cur_addr:08x}")
130-
131-
break
132-
133-
self.ql.arch.step()
134-
self.ql.count -= 1
135-
136-
return
137-
138117
if getattr(self.ql.arch, 'is_thumb', False):
139118
address |= 1
140119

@@ -227,13 +206,10 @@ def do_step_in(self, *args) -> Optional[bool]:
227206
if prophecy.where is True:
228207
return True
229208

230-
if self.ql.arch == QL_ARCH.CORTEX_M:
231-
self.ql.arch.step()
232-
else:
233-
step = 1
234-
# make sure follow branching
235-
if prophecy.going is True and self.ql.arch.type == QL_ARCH.MIPS:
236-
step += 1
209+
step = 1
210+
# make sure follow branching
211+
if prophecy.going is True and self.ql.arch.type == QL_ARCH.MIPS:
212+
step += 1
237213

238214
self._run(count=step)
239215
self.do_context()

qiling/debugger/qdb/render/render.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def wrapper(*args, **kwargs):
5151
def __init__(self):
5252
self.regs_a_row = 4
5353
self.stack_num = 10
54+
self.disasm_num = 0x10
5455
self.color = color
5556

5657
def reg_diff(self, cur_regs, saved_reg_dump):
@@ -206,13 +207,14 @@ def context_asm(self) -> None:
206207

207208
lines = {}
208209
past_list = []
209-
from_addr = self.cur_addr - 0x10
210-
to_addr = self.cur_addr + 0x10
210+
from_addr = self.cur_addr - self.disasm_num
211+
to_addr = self.cur_addr + self.disasm_num
211212

212213
cur_addr = from_addr
213214
while cur_addr != to_addr:
214215
insn = self.disasm(cur_addr)
215-
cur_addr += self.arch_insn_size
216+
# cur_addr += self.arch_insn_size
217+
cur_addr += insn.size
216218
if not insn:
217219
continue
218220
past_list.append(insn)

qiling/debugger/qdb/render/render_arm.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class ContextRenderARM(ContextRender, ArchARM):
1616
def __init__(self, ql, predictor):
1717
super().__init__(ql, predictor)
1818
ArchARM.__init__(self)
19+
self.disasm_num = 8
1920

2021
@staticmethod
2122
def print_mode_info(bits):

qiling/os/posix/const.py

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,45 @@
107107
"IP_MULTICAST_ALL" : 0x0031,
108108
}
109109

110+
# https://github.com/torvalds/linux/blob/master/include/uapi/linux/tcp.h
111+
linux_socket_tcp_options = {
112+
"TCP_NODELAY" : 0x1,
113+
"TCP_MAXSEG" : 0x2,
114+
"TCP_CORK" : 0x3,
115+
"TCP_KEEPIDLE" : 0x4,
116+
"TCP_KEEPINTVL" : 0x5,
117+
"TCP_KEEPCNT" : 0x6,
118+
"TCP_SYNCNT" : 0x7,
119+
"TCP_LINGER2" : 0x8,
120+
"TCP_DEFER_ACCEPT" : 0x9,
121+
"TCP_WINDOW_CLAMP" : 0xa,
122+
"TCP_INFO" : 0xb,
123+
"TCP_QUICKACK" : 0xc,
124+
"TCP_CONGESTION" : 0xd,
125+
"TCP_MD5SIG" : 0xe,
126+
"TCP_THIN_LINEAR_TIMEOUTS" : 0x10,
127+
"TCP_THIN_DUPACK" : 0x11,
128+
"TCP_USER_TIMEOUT" : 0x12,
129+
"TCP_REPAIR" : 0x13,
130+
"TCP_REPAIR_QUEUE" : 0x14,
131+
"TCP_QUEUE_SEQ" : 0x15,
132+
"TCP_REPAIR_OPTIONS" : 0x16,
133+
"TCP_FASTOPEN" : 0x17,
134+
"TCP_TIMESTAMP" : 0x18,
135+
"TCP_NOTSENT_LOWAT" : 0x19,
136+
"TCP_CC_INFO" : 0x1a,
137+
"TCP_SAVE_SYN" : 0x1b,
138+
"TCP_SAVED_SYN" : 0x1c,
139+
"TCP_REPAIR_WINDOW" : 0x1d,
140+
"TCP_FASTOPEN_CONNECT" : 0x1e,
141+
"TCP_ULP" : 0x1f,
142+
"TCP_MD5SIG_EXT" : 0x20,
143+
"TCP_FASTOPEN_KEY" : 0x21,
144+
"TCP_FASTOPEN_NO_COOKIE" : 0x22,
145+
"TCP_ZEROCOPY_RECEIVE" : 0x23,
146+
"TCP_INQ" : 0x24,
147+
"TCP_TX_DELAY" : 0x25,
148+
}
110149

111150
macos_socket_ip_options = {
112151
"IP_TOS" : 0x0003,
@@ -241,13 +280,15 @@
241280
linux_arm_socket_options = {
242281
"SO_DEBUG" : 0x0001,
243282
"SO_REUSEADDR" : 0x0002,
244-
"SO_KEEPALIVE" : 0x0009,
283+
"SO_TYPE" : 0x0003,
284+
"SO_ERROR" : 0x0004,
245285
"SO_DONTROUTE" : 0x0005,
246286
"SO_BROADCAST" : 0x0006,
247-
"SO_LINGER" : 0x000d,
248-
"SO_OOBINLINE" : 0x000a,
249287
"SO_SNDBUF" : 0x0007,
250288
"SO_RCVBUF" : 0x0008,
289+
"SO_KEEPALIVE" : 0x0009,
290+
"SO_OOBINLINE" : 0x000a,
291+
"SO_LINGER" : 0x000d,
251292
"SO_REUSEPORT" : 0x000f,
252293
"SO_SNDLOWAT" : 0x0013,
253294
"SO_RCVLOWAT" : 0x0012,
@@ -336,6 +377,7 @@
336377
"SO_REUSEADDR" : 0x0004,
337378
"SO_KEEPALIVE" : 0x0008,
338379
"SO_DONTROUTE" : 0x0010,
380+
"SO_BINDTODEVICE" : 0x0019,
339381
"SO_BROADCAST" : 0x0020,
340382
"SO_LINGER" : 0x0080,
341383
"SO_OOBINLINE" : 0x0100,

0 commit comments

Comments
 (0)