diff --git a/.github/workflows/giteesync.yml b/.github/workflows/giteesync.yml
index 4e7104ba..dbf79749 100644
--- a/.github/workflows/giteesync.yml
+++ b/.github/workflows/giteesync.yml
@@ -5,6 +5,7 @@
jobs:
deploy:
runs-on: ubuntu-latest
+ if: github.repository_owner == 'qilingframework'
steps:
- uses: actions/checkout@v2
with:
diff --git a/CREDITS.md b/CREDITS.md
index b4e32331..9ea9f0ed 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -54,6 +54,7 @@
- danielmoos
- sigeryang
- bet4it
+- nullableVoidPtr
#### Legacy Core Developers
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index ead0863c..00000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,5 +0,0 @@
-recursive-include qiling/debugger/gdb/xml *
-recursive-include qiling/extensions/windows_sdk/defs *
-recursive-include qiling/profiles *
-include qiling/os/uefi/guids.csv
-include qiling/os/qnx/syspage.bin
diff --git a/qiling/arch/arm64.py b/qiling/arch/arm64.py
index 0367a818..65949669 100644
--- a/qiling/arch/arm64.py
+++ b/qiling/arch/arm64.py
@@ -26,7 +26,13 @@ class QlArchARM64(QlArch):
def regs(self) -> QlRegisterManager:
regs_map = dict(
**arm64_const.reg_map,
- **arm64_const.reg_map_w
+ **arm64_const.reg_map_b,
+ **arm64_const.reg_map_d,
+ **arm64_const.reg_map_h,
+ **arm64_const.reg_map_q,
+ **arm64_const.reg_map_s,
+ **arm64_const.reg_map_w,
+ **arm64_const.reg_map_v
)
pc_reg = 'pc'
diff --git a/qiling/arch/arm64_const.py b/qiling/arch/arm64_const.py
index c706d10c..ee2b5516 100644
--- a/qiling/arch/arm64_const.py
+++ b/qiling/arch/arm64_const.py
@@ -1,79 +1,289 @@
#!/usr/bin/env python3
-#
+#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#
from unicorn.arm64_const import *
reg_map = {
- "x0": UC_ARM64_REG_X0,
- "x1": UC_ARM64_REG_X1,
- "x2": UC_ARM64_REG_X2,
- "x3": UC_ARM64_REG_X3,
- "x4": UC_ARM64_REG_X4,
- "x5": UC_ARM64_REG_X5,
- "x6": UC_ARM64_REG_X6,
- "x7": UC_ARM64_REG_X7,
- "x8": UC_ARM64_REG_X8,
- "x9": UC_ARM64_REG_X9,
- "x10": UC_ARM64_REG_X10,
- "x11": UC_ARM64_REG_X11,
- "x12": UC_ARM64_REG_X12,
- "x13": UC_ARM64_REG_X13,
- "x14": UC_ARM64_REG_X14,
- "x15": UC_ARM64_REG_X15,
- "x16": UC_ARM64_REG_X16,
- "x17": UC_ARM64_REG_X17,
- "x18": UC_ARM64_REG_X18,
- "x19": UC_ARM64_REG_X19,
- "x20": UC_ARM64_REG_X20,
- "x21": UC_ARM64_REG_X21,
- "x22": UC_ARM64_REG_X22,
- "x23": UC_ARM64_REG_X23,
- "x24": UC_ARM64_REG_X24,
- "x25": UC_ARM64_REG_X25,
- "x26": UC_ARM64_REG_X26,
- "x27": UC_ARM64_REG_X27,
- "x28": UC_ARM64_REG_X28,
- "x29": UC_ARM64_REG_X29,
- "x30": UC_ARM64_REG_X30,
- "sp": UC_ARM64_REG_SP,
- "pc": UC_ARM64_REG_PC,
- "lr": UC_ARM64_REG_LR,
- "cpacr_el1": UC_ARM64_REG_CPACR_EL1,
- "tpidr_el0": UC_ARM64_REG_TPIDR_EL0,
+ "x0": UC_ARM64_REG_X0,
+ "x1": UC_ARM64_REG_X1,
+ "x2": UC_ARM64_REG_X2,
+ "x3": UC_ARM64_REG_X3,
+ "x4": UC_ARM64_REG_X4,
+ "x5": UC_ARM64_REG_X5,
+ "x6": UC_ARM64_REG_X6,
+ "x7": UC_ARM64_REG_X7,
+ "x8": UC_ARM64_REG_X8,
+ "x9": UC_ARM64_REG_X9,
+ "x10": UC_ARM64_REG_X10,
+ "x11": UC_ARM64_REG_X11,
+ "x12": UC_ARM64_REG_X12,
+ "x13": UC_ARM64_REG_X13,
+ "x14": UC_ARM64_REG_X14,
+ "x15": UC_ARM64_REG_X15,
+ "x16": UC_ARM64_REG_X16,
+ "x17": UC_ARM64_REG_X17,
+ "x18": UC_ARM64_REG_X18,
+ "x19": UC_ARM64_REG_X19,
+ "x20": UC_ARM64_REG_X20,
+ "x21": UC_ARM64_REG_X21,
+ "x22": UC_ARM64_REG_X22,
+ "x23": UC_ARM64_REG_X23,
+ "x24": UC_ARM64_REG_X24,
+ "x25": UC_ARM64_REG_X25,
+ "x26": UC_ARM64_REG_X26,
+ "x27": UC_ARM64_REG_X27,
+ "x28": UC_ARM64_REG_X28,
+ "x29": UC_ARM64_REG_X29,
+ "x30": UC_ARM64_REG_X30,
+ "sp": UC_ARM64_REG_SP,
+ "pc": UC_ARM64_REG_PC,
+ "lr": UC_ARM64_REG_LR,
+ "cpacr_el1": UC_ARM64_REG_CPACR_EL1,
+ "tpidr_el0": UC_ARM64_REG_TPIDR_EL0
+}
+
+reg_map_b = {
+ "b0" : UC_ARM64_REG_B0,
+ "b1" : UC_ARM64_REG_B1,
+ "b2" : UC_ARM64_REG_B2,
+ "b3" : UC_ARM64_REG_B3,
+ "b4" : UC_ARM64_REG_B4,
+ "b5" : UC_ARM64_REG_B5,
+ "b6" : UC_ARM64_REG_B6,
+ "b7" : UC_ARM64_REG_B7,
+ "b8" : UC_ARM64_REG_B8,
+ "b9" : UC_ARM64_REG_B9,
+ "b10" : UC_ARM64_REG_B10,
+ "b11" : UC_ARM64_REG_B11,
+ "b12" : UC_ARM64_REG_B12,
+ "b13" : UC_ARM64_REG_B13,
+ "b14" : UC_ARM64_REG_B14,
+ "b15" : UC_ARM64_REG_B15,
+ "b16" : UC_ARM64_REG_B16,
+ "b17" : UC_ARM64_REG_B17,
+ "b18" : UC_ARM64_REG_B18,
+ "b19" : UC_ARM64_REG_B19,
+ "b20" : UC_ARM64_REG_B20,
+ "b21" : UC_ARM64_REG_B21,
+ "b22" : UC_ARM64_REG_B22,
+ "b23" : UC_ARM64_REG_B23,
+ "b24" : UC_ARM64_REG_B24,
+ "b25" : UC_ARM64_REG_B25,
+ "b26" : UC_ARM64_REG_B26,
+ "b27" : UC_ARM64_REG_B27,
+ "b28" : UC_ARM64_REG_B28,
+ "b29" : UC_ARM64_REG_B29,
+ "b30" : UC_ARM64_REG_B30,
+ "b31" : UC_ARM64_REG_B31
+}
+
+reg_map_d = {
+ "d0" : UC_ARM64_REG_D0,
+ "d1" : UC_ARM64_REG_D1,
+ "d2" : UC_ARM64_REG_D2,
+ "d3" : UC_ARM64_REG_D3,
+ "d4" : UC_ARM64_REG_D4,
+ "d5" : UC_ARM64_REG_D5,
+ "d6" : UC_ARM64_REG_D6,
+ "d7" : UC_ARM64_REG_D7,
+ "d8" : UC_ARM64_REG_D8,
+ "d9" : UC_ARM64_REG_D9,
+ "d10" : UC_ARM64_REG_D10,
+ "d11" : UC_ARM64_REG_D11,
+ "d12" : UC_ARM64_REG_D12,
+ "d13" : UC_ARM64_REG_D13,
+ "d14" : UC_ARM64_REG_D14,
+ "d15" : UC_ARM64_REG_D15,
+ "d16" : UC_ARM64_REG_D16,
+ "d17" : UC_ARM64_REG_D17,
+ "d18" : UC_ARM64_REG_D18,
+ "d19" : UC_ARM64_REG_D19,
+ "d20" : UC_ARM64_REG_D20,
+ "d21" : UC_ARM64_REG_D21,
+ "d22" : UC_ARM64_REG_D22,
+ "d23" : UC_ARM64_REG_D23,
+ "d24" : UC_ARM64_REG_D24,
+ "d25" : UC_ARM64_REG_D25,
+ "d26" : UC_ARM64_REG_D26,
+ "d27" : UC_ARM64_REG_D27,
+ "d28" : UC_ARM64_REG_D28,
+ "d29" : UC_ARM64_REG_D29,
+ "d30" : UC_ARM64_REG_D30,
+ "d31" : UC_ARM64_REG_D31
+}
+
+reg_map_h = {
+ "h0" : UC_ARM64_REG_H0,
+ "h1" : UC_ARM64_REG_H1,
+ "h2" : UC_ARM64_REG_H2,
+ "h3" : UC_ARM64_REG_H3,
+ "h4" : UC_ARM64_REG_H4,
+ "h5" : UC_ARM64_REG_H5,
+ "h6" : UC_ARM64_REG_H6,
+ "h7" : UC_ARM64_REG_H7,
+ "h8" : UC_ARM64_REG_H8,
+ "h9" : UC_ARM64_REG_H9,
+ "h10" : UC_ARM64_REG_H10,
+ "h11" : UC_ARM64_REG_H11,
+ "h12" : UC_ARM64_REG_H12,
+ "h13" : UC_ARM64_REG_H13,
+ "h14" : UC_ARM64_REG_H14,
+ "h15" : UC_ARM64_REG_H15,
+ "h16" : UC_ARM64_REG_H16,
+ "h17" : UC_ARM64_REG_H17,
+ "h18" : UC_ARM64_REG_H18,
+ "h19" : UC_ARM64_REG_H19,
+ "h20" : UC_ARM64_REG_H20,
+ "h21" : UC_ARM64_REG_H21,
+ "h22" : UC_ARM64_REG_H22,
+ "h23" : UC_ARM64_REG_H23,
+ "h24" : UC_ARM64_REG_H24,
+ "h25" : UC_ARM64_REG_H25,
+ "h26" : UC_ARM64_REG_H26,
+ "h27" : UC_ARM64_REG_H27,
+ "h28" : UC_ARM64_REG_H28,
+ "h29" : UC_ARM64_REG_H29,
+ "h30" : UC_ARM64_REG_H30,
+ "h31" : UC_ARM64_REG_H31
+}
+
+reg_map_q = {
+ "q0" : UC_ARM64_REG_Q0,
+ "q1" : UC_ARM64_REG_Q1,
+ "q2" : UC_ARM64_REG_Q2,
+ "q3" : UC_ARM64_REG_Q3,
+ "q4" : UC_ARM64_REG_Q4,
+ "q5" : UC_ARM64_REG_Q5,
+ "q6" : UC_ARM64_REG_Q6,
+ "q7" : UC_ARM64_REG_Q7,
+ "q8" : UC_ARM64_REG_Q8,
+ "q9" : UC_ARM64_REG_Q9,
+ "q10" : UC_ARM64_REG_Q10,
+ "q11" : UC_ARM64_REG_Q11,
+ "q12" : UC_ARM64_REG_Q12,
+ "q13" : UC_ARM64_REG_Q13,
+ "q14" : UC_ARM64_REG_Q14,
+ "q15" : UC_ARM64_REG_Q15,
+ "q16" : UC_ARM64_REG_Q16,
+ "q17" : UC_ARM64_REG_Q17,
+ "q18" : UC_ARM64_REG_Q18,
+ "q19" : UC_ARM64_REG_Q19,
+ "q20" : UC_ARM64_REG_Q20,
+ "q21" : UC_ARM64_REG_Q21,
+ "q22" : UC_ARM64_REG_Q22,
+ "q23" : UC_ARM64_REG_Q23,
+ "q24" : UC_ARM64_REG_Q24,
+ "q25" : UC_ARM64_REG_Q25,
+ "q26" : UC_ARM64_REG_Q26,
+ "q27" : UC_ARM64_REG_Q27,
+ "q28" : UC_ARM64_REG_Q28,
+ "q29" : UC_ARM64_REG_Q29,
+ "q30" : UC_ARM64_REG_Q30,
+ "q31" : UC_ARM64_REG_Q31
+}
+
+reg_map_s = {
+ "s0" : UC_ARM64_REG_S0,
+ "s1" : UC_ARM64_REG_S1,
+ "s2" : UC_ARM64_REG_S2,
+ "s3" : UC_ARM64_REG_S3,
+ "s4" : UC_ARM64_REG_S4,
+ "s5" : UC_ARM64_REG_S5,
+ "s6" : UC_ARM64_REG_S6,
+ "s7" : UC_ARM64_REG_S7,
+ "s8" : UC_ARM64_REG_S8,
+ "s9" : UC_ARM64_REG_S9,
+ "s10" : UC_ARM64_REG_S10,
+ "s11" : UC_ARM64_REG_S11,
+ "s12" : UC_ARM64_REG_S12,
+ "s13" : UC_ARM64_REG_S13,
+ "s14" : UC_ARM64_REG_S14,
+ "s15" : UC_ARM64_REG_S15,
+ "s16" : UC_ARM64_REG_S16,
+ "s17" : UC_ARM64_REG_S17,
+ "s18" : UC_ARM64_REG_S18,
+ "s19" : UC_ARM64_REG_S19,
+ "s20" : UC_ARM64_REG_S20,
+ "s21" : UC_ARM64_REG_S21,
+ "s22" : UC_ARM64_REG_S22,
+ "s23" : UC_ARM64_REG_S23,
+ "s24" : UC_ARM64_REG_S24,
+ "s25" : UC_ARM64_REG_S25,
+ "s26" : UC_ARM64_REG_S26,
+ "s27" : UC_ARM64_REG_S27,
+ "s28" : UC_ARM64_REG_S28,
+ "s29" : UC_ARM64_REG_S29,
+ "s30" : UC_ARM64_REG_S30,
+ "s31" : UC_ARM64_REG_S31
}
reg_map_w = {
- "w0" : UC_ARM64_REG_W0,
- "w1" : UC_ARM64_REG_W1,
- "w2" : UC_ARM64_REG_W2,
- "w3" : UC_ARM64_REG_W3,
- "w4" : UC_ARM64_REG_W4,
- "w5" : UC_ARM64_REG_W5,
- "w6" : UC_ARM64_REG_W6,
- "w7" : UC_ARM64_REG_W7,
- "w8" : UC_ARM64_REG_W8,
- "w9" : UC_ARM64_REG_W9,
- "w10" : UC_ARM64_REG_W10,
- "w11" : UC_ARM64_REG_W11,
- "w12" : UC_ARM64_REG_W12,
- "w13" : UC_ARM64_REG_W13,
- "w14" : UC_ARM64_REG_W14,
- "w15" : UC_ARM64_REG_W15,
- "w16" : UC_ARM64_REG_W16,
- "w17" : UC_ARM64_REG_W17,
- "w18" : UC_ARM64_REG_W18,
- "w19" : UC_ARM64_REG_W19,
- "w20" : UC_ARM64_REG_W20,
- "w21" : UC_ARM64_REG_W21,
- "w22" : UC_ARM64_REG_W22,
- "w23" : UC_ARM64_REG_W23,
- "w24" : UC_ARM64_REG_W24,
- "w25" : UC_ARM64_REG_W25,
- "w26" : UC_ARM64_REG_W26,
- "w27" : UC_ARM64_REG_W27,
- "w28" : UC_ARM64_REG_W28,
- "w29" : UC_ARM64_REG_W29,
- "w30" : UC_ARM64_REG_W30,
-}
\ No newline at end of file
+ "w0" : UC_ARM64_REG_W0,
+ "w1" : UC_ARM64_REG_W1,
+ "w2" : UC_ARM64_REG_W2,
+ "w3" : UC_ARM64_REG_W3,
+ "w4" : UC_ARM64_REG_W4,
+ "w5" : UC_ARM64_REG_W5,
+ "w6" : UC_ARM64_REG_W6,
+ "w7" : UC_ARM64_REG_W7,
+ "w8" : UC_ARM64_REG_W8,
+ "w9" : UC_ARM64_REG_W9,
+ "w10" : UC_ARM64_REG_W10,
+ "w11" : UC_ARM64_REG_W11,
+ "w12" : UC_ARM64_REG_W12,
+ "w13" : UC_ARM64_REG_W13,
+ "w14" : UC_ARM64_REG_W14,
+ "w15" : UC_ARM64_REG_W15,
+ "w16" : UC_ARM64_REG_W16,
+ "w17" : UC_ARM64_REG_W17,
+ "w18" : UC_ARM64_REG_W18,
+ "w19" : UC_ARM64_REG_W19,
+ "w20" : UC_ARM64_REG_W20,
+ "w21" : UC_ARM64_REG_W21,
+ "w22" : UC_ARM64_REG_W22,
+ "w23" : UC_ARM64_REG_W23,
+ "w24" : UC_ARM64_REG_W24,
+ "w25" : UC_ARM64_REG_W25,
+ "w26" : UC_ARM64_REG_W26,
+ "w27" : UC_ARM64_REG_W27,
+ "w28" : UC_ARM64_REG_W28,
+ "w29" : UC_ARM64_REG_W29,
+ "w30" : UC_ARM64_REG_W30
+}
+
+reg_map_v = {
+ "v0" : UC_ARM64_REG_V0,
+ "v1" : UC_ARM64_REG_V1,
+ "v2" : UC_ARM64_REG_V2,
+ "v3" : UC_ARM64_REG_V3,
+ "v4" : UC_ARM64_REG_V4,
+ "v5" : UC_ARM64_REG_V5,
+ "v6" : UC_ARM64_REG_V6,
+ "v7" : UC_ARM64_REG_V7,
+ "v8" : UC_ARM64_REG_V8,
+ "v9" : UC_ARM64_REG_V9,
+ "v10" : UC_ARM64_REG_V10,
+ "v11" : UC_ARM64_REG_V11,
+ "v12" : UC_ARM64_REG_V12,
+ "v13" : UC_ARM64_REG_V13,
+ "v14" : UC_ARM64_REG_V14,
+ "v15" : UC_ARM64_REG_V15,
+ "v16" : UC_ARM64_REG_V16,
+ "v17" : UC_ARM64_REG_V17,
+ "v18" : UC_ARM64_REG_V18,
+ "v19" : UC_ARM64_REG_V19,
+ "v20" : UC_ARM64_REG_V20,
+ "v21" : UC_ARM64_REG_V21,
+ "v22" : UC_ARM64_REG_V22,
+ "v23" : UC_ARM64_REG_V23,
+ "v24" : UC_ARM64_REG_V24,
+ "v25" : UC_ARM64_REG_V25,
+ "v26" : UC_ARM64_REG_V26,
+ "v27" : UC_ARM64_REG_V27,
+ "v28" : UC_ARM64_REG_V28,
+ "v29" : UC_ARM64_REG_V29,
+ "v30" : UC_ARM64_REG_V30,
+ "v31" : UC_ARM64_REG_V31
+}
diff --git a/qiling/arch/arm_const.py b/qiling/arch/arm_const.py
index e9339366..2a268cdf 100644
--- a/qiling/arch/arm_const.py
+++ b/qiling/arch/arm_const.py
@@ -4,39 +4,63 @@
#
from unicorn.arm_const import *
-from enum import IntEnum
reg_map = {
- "r0": UC_ARM_REG_R0,
- "r1": UC_ARM_REG_R1,
- "r2": UC_ARM_REG_R2,
- "r3": UC_ARM_REG_R3,
- "r4": UC_ARM_REG_R4,
- "r5": UC_ARM_REG_R5,
- "r6": UC_ARM_REG_R6,
- "r7": UC_ARM_REG_R7,
- "r8": UC_ARM_REG_R8,
- "r9": UC_ARM_REG_R9,
- "r10": UC_ARM_REG_R10,
- "r11": UC_ARM_REG_R11,
- "r12": UC_ARM_REG_R12,
- "sp": UC_ARM_REG_SP,
- "lr": UC_ARM_REG_LR,
- "pc": UC_ARM_REG_PC,
-
- # CPSR needs to be at offset 25 for GDB, see https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/arch/arm.h;h=fa589fd0582c0add627a068e6f4947a909c45e86;hb=HEAD#l34
- # The fp registers inbetween have become obsolete
- "f0": UC_ARM_REG_INVALID,
- "f1": UC_ARM_REG_INVALID,
- "f2": UC_ARM_REG_INVALID,
- "f3": UC_ARM_REG_INVALID,
- "f4": UC_ARM_REG_INVALID,
- "f5": UC_ARM_REG_INVALID,
- "f6": UC_ARM_REG_INVALID,
- "f7": UC_ARM_REG_INVALID,
- "fps": UC_ARM_REG_INVALID,
- "cpsr": UC_ARM_REG_CPSR,
- "c1_c0_2": UC_ARM_REG_C1_C0_2,
- "c13_c0_3": UC_ARM_REG_C13_C0_3,
- "fpexc": UC_ARM_REG_FPEXC,
+ "r0": UC_ARM_REG_R0,
+ "r1": UC_ARM_REG_R1,
+ "r2": UC_ARM_REG_R2,
+ "r3": UC_ARM_REG_R3,
+ "r4": UC_ARM_REG_R4,
+ "r5": UC_ARM_REG_R5,
+ "r6": UC_ARM_REG_R6,
+ "r7": UC_ARM_REG_R7,
+ "r8": UC_ARM_REG_R8,
+ "r9": UC_ARM_REG_R9,
+ "r10": UC_ARM_REG_R10,
+ "r11": UC_ARM_REG_R11,
+ "r12": UC_ARM_REG_R12,
+ "sp": UC_ARM_REG_SP,
+ "lr": UC_ARM_REG_LR,
+ "pc": UC_ARM_REG_PC,
+
+ "cpsr": UC_ARM_REG_CPSR,
+ "c1_c0_2": UC_ARM_REG_C1_C0_2,
+ "c13_c0_3": UC_ARM_REG_C13_C0_3,
+ "fpexc": UC_ARM_REG_FPEXC
+}
+
+reg_vfp = {
+ "d0" : UC_ARM_REG_D0,
+ "d1" : UC_ARM_REG_D1,
+ "d2" : UC_ARM_REG_D2,
+ "d3" : UC_ARM_REG_D3,
+ "d4" : UC_ARM_REG_D4,
+ "d5" : UC_ARM_REG_D5,
+ "d6" : UC_ARM_REG_D6,
+ "d7" : UC_ARM_REG_D7,
+ "d8" : UC_ARM_REG_D8,
+ "d9" : UC_ARM_REG_D9,
+ "d10" : UC_ARM_REG_D10,
+ "d11" : UC_ARM_REG_D11,
+ "d12" : UC_ARM_REG_D12,
+ "d13" : UC_ARM_REG_D13,
+ "d14" : UC_ARM_REG_D14,
+ "d15" : UC_ARM_REG_D15,
+ "d16" : UC_ARM_REG_D16,
+ "d17" : UC_ARM_REG_D17,
+ "d18" : UC_ARM_REG_D18,
+ "d19" : UC_ARM_REG_D19,
+ "d20" : UC_ARM_REG_D20,
+ "d21" : UC_ARM_REG_D21,
+ "d22" : UC_ARM_REG_D22,
+ "d23" : UC_ARM_REG_D23,
+ "d24" : UC_ARM_REG_D24,
+ "d25" : UC_ARM_REG_D25,
+ "d26" : UC_ARM_REG_D26,
+ "d27" : UC_ARM_REG_D27,
+ "d28" : UC_ARM_REG_D28,
+ "d29" : UC_ARM_REG_D29,
+ "d30" : UC_ARM_REG_D30,
+ "d31" : UC_ARM_REG_D31,
+ "fpscr" : UC_ARM_REG_FPSCR
}
diff --git a/qiling/arch/evm/analysis/signatures.py b/qiling/arch/evm/analysis/signatures.py
index aebe55f0..e7eed509 100644
--- a/qiling/arch/evm/analysis/signatures.py
+++ b/qiling/arch/evm/analysis/signatures.py
@@ -1,4 +1,5 @@
-import os
+import inspect
+from pathlib import Path
import re
import logging
import json
@@ -92,8 +93,8 @@ def analysis_func_sign(insns:list, engine_num=1):
class signatures_engine_1:
@staticmethod
def find_signature(sign):
- path = os.path.split(os.path.realpath(__file__))[0] + '/signatures.json'
- with open(path) as data_file:
+ path = Path(inspect.getfile(inspect.getframe())).parent / 'signatures.json'
+ with path.open('r') as data_file:
data = json.load(data_file)
list_name = [name for name, hexa in data.items() if hexa == sign]
diff --git a/qiling/arch/mips.py b/qiling/arch/mips.py
index 8391becc..9368634f 100644
--- a/qiling/arch/mips.py
+++ b/qiling/arch/mips.py
@@ -37,7 +37,8 @@ class QlArchMIPS(QlArch):
def regs(self) -> QlRegisterManager:
regs_map = dict(
**mips_const.reg_map,
- **mips_const.reg_map_afpr128
+ **mips_const.reg_map_afpr128,
+ **mips_const.reg_map_fpu
)
pc_reg = 'pc'
diff --git a/qiling/arch/mips_const.py b/qiling/arch/mips_const.py
index 8dd8d48a..8e3141f4 100644
--- a/qiling/arch/mips_const.py
+++ b/qiling/arch/mips_const.py
@@ -6,6 +6,39 @@
from unicorn.mips_const import *
reg_map = {
+ "r0" : UC_MIPS_REG_0,
+ "r1" : UC_MIPS_REG_1,
+ "r2" : UC_MIPS_REG_2,
+ "r3" : UC_MIPS_REG_3,
+ "r4" : UC_MIPS_REG_4,
+ "r5" : UC_MIPS_REG_5,
+ "r6" : UC_MIPS_REG_6,
+ "r7" : UC_MIPS_REG_7,
+ "r8" : UC_MIPS_REG_8,
+ "r9" : UC_MIPS_REG_9,
+ "r10" : UC_MIPS_REG_10,
+ "r11" : UC_MIPS_REG_11,
+ "r12" : UC_MIPS_REG_12,
+ "r13" : UC_MIPS_REG_13,
+ "r14" : UC_MIPS_REG_14,
+ "r15" : UC_MIPS_REG_15,
+ "r16" : UC_MIPS_REG_16,
+ "r17" : UC_MIPS_REG_17,
+ "r18" : UC_MIPS_REG_18,
+ "r19" : UC_MIPS_REG_19,
+ "r20" : UC_MIPS_REG_20,
+ "r21" : UC_MIPS_REG_21,
+ "r22" : UC_MIPS_REG_22,
+ "r23" : UC_MIPS_REG_23,
+ "r24" : UC_MIPS_REG_24,
+ "r25" : UC_MIPS_REG_25,
+ "r26" : UC_MIPS_REG_26,
+ "r27" : UC_MIPS_REG_27,
+ "r28" : UC_MIPS_REG_28,
+ "r29" : UC_MIPS_REG_29,
+ "r30" : UC_MIPS_REG_30,
+ "r31" : UC_MIPS_REG_31,
+
"zero": UC_MIPS_REG_ZERO,
"at": UC_MIPS_REG_AT,
"v0": UC_MIPS_REG_V0,
@@ -49,4 +82,39 @@ reg_map = {
reg_map_afpr128 = {
"cp0_config3" : UC_MIPS_REG_CP0_CONFIG3,
"cp0_userlocal": UC_MIPS_REG_CP0_USERLOCAL,
-}
\ No newline at end of file
+}
+
+reg_map_fpu = {
+ "f0" : UC_MIPS_REG_F0,
+ "f1" : UC_MIPS_REG_F1,
+ "f2" : UC_MIPS_REG_F2,
+ "f3" : UC_MIPS_REG_F3,
+ "f4" : UC_MIPS_REG_F4,
+ "f5" : UC_MIPS_REG_F5,
+ "f6" : UC_MIPS_REG_F6,
+ "f7" : UC_MIPS_REG_F7,
+ "f8" : UC_MIPS_REG_F8,
+ "f9" : UC_MIPS_REG_F9,
+ "f10" : UC_MIPS_REG_F10,
+ "f11" : UC_MIPS_REG_F11,
+ "f12" : UC_MIPS_REG_F12,
+ "f13" : UC_MIPS_REG_F13,
+ "f14" : UC_MIPS_REG_F14,
+ "f15" : UC_MIPS_REG_F15,
+ "f16" : UC_MIPS_REG_F16,
+ "f17" : UC_MIPS_REG_F17,
+ "f18" : UC_MIPS_REG_F18,
+ "f19" : UC_MIPS_REG_F19,
+ "f20" : UC_MIPS_REG_F20,
+ "f21" : UC_MIPS_REG_F21,
+ "f22" : UC_MIPS_REG_F22,
+ "f23" : UC_MIPS_REG_F23,
+ "f24" : UC_MIPS_REG_F24,
+ "f25" : UC_MIPS_REG_F25,
+ "f26" : UC_MIPS_REG_F26,
+ "f27" : UC_MIPS_REG_F27,
+ "f28" : UC_MIPS_REG_F28,
+ "f29" : UC_MIPS_REG_F29,
+ "f30" : UC_MIPS_REG_F30,
+ "f31" : UC_MIPS_REG_F31
+}
diff --git a/qiling/arch/register.py b/qiling/arch/register.py
index fab8f3af..368864f6 100644
--- a/qiling/arch/register.py
+++ b/qiling/arch/register.py
@@ -102,12 +102,6 @@ class QlRegisterManager:
return self.uc.reg_write(self.uc_pc, value)
- @property
- def arch_pc_name(self) -> str:
- """Get the architectural program counter register name.
- """
-
- return next(k for k, v in self.register_mapping.items() if v == self.uc_pc)
@property
def arch_sp(self) -> int:
diff --git a/qiling/arch/x86.py b/qiling/arch/x86.py
index b634849f..97850ef6 100644
--- a/qiling/arch/x86.py
+++ b/qiling/arch/x86.py
@@ -4,14 +4,11 @@
#
from functools import cached_property
-from typing import Union
from unicorn import Uc, UC_ARCH_X86, UC_MODE_16, UC_MODE_32, UC_MODE_64
from capstone import Cs, CS_ARCH_X86, CS_MODE_16, CS_MODE_32, CS_MODE_64
from keystone import Ks, KS_ARCH_X86, KS_MODE_16, KS_MODE_32, KS_MODE_64
-from unicorn.x86_const import UC_X86_REG_EFLAGS
-
from qiling.arch.arch import QlArch
from qiling.arch.msr import QlMsrManager
from qiling.arch.register import QlRegisterManager
@@ -126,33 +123,3 @@ class QlArchX8664(QlArchIntel):
@cached_property
def assembler(self) -> Ks:
return Ks(KS_ARCH_X86, KS_MODE_64)
-
- # TODO: generalize this
- def __reg_bits(self, register: int) -> int:
- # all regs in reg_map_misc are 16 bits except of eflags
- if register == UC_X86_REG_EFLAGS:
- return 32
-
- regmaps = (
- (x86_const.reg_map_8, 8),
- (x86_const.reg_map_16, 16),
- (x86_const.reg_map_32, 32),
- (x86_const.reg_map_64, 64),
- (x86_const.reg_map_misc, 16),
- (x86_const.reg_map_cr, 64), # 32 bits for x86
- (x86_const.reg_map_st, 32),
- (x86_const.reg_map_seg_base, 64), # 32 bits for x86
- )
-
- return next((rsize for rmap, rsize in regmaps if register in rmap.values()), 0)
-
- # note: this method was not generalized for all archs since it requires a bookkeeping
- # of all registers, while it is used only by gdb and only for x86-64
- def reg_bits(self, reg: Union[str, int]) -> int:
- """Get register size in bits.
- """
-
- if type(reg) is str:
- reg = self.regs.register_mapping[reg]
-
- return self.__reg_bits(reg)
diff --git a/qiling/arch/x86_const.py b/qiling/arch/x86_const.py
index 798549ee..1e60479f 100644
--- a/qiling/arch/x86_const.py
+++ b/qiling/arch/x86_const.py
@@ -177,7 +177,7 @@ reg_map_st = {
}
reg_map_misc = {
- "ef": UC_X86_REG_EFLAGS,
+ "eflags": UC_X86_REG_EFLAGS,
"cs": UC_X86_REG_CS,
"ss": UC_X86_REG_SS,
"ds": UC_X86_REG_DS,
diff --git a/qiling/const.py b/qiling/const.py
index 1f97e4cb..d7ac9f8d 100644
--- a/qiling/const.py
+++ b/qiling/const.py
@@ -60,9 +60,8 @@ class QL_STOP(Flag):
QL_ARCH_INTERPRETER = (QL_ARCH.EVM,)
-QL_OS_NONPID = (QL_OS.DOS, QL_OS.UEFI)
-QL_OS_POSIX = (QL_OS.LINUX, QL_OS.FREEBSD, QL_OS.MACOS, QL_OS.QNX)
-QL_OS_BAREMETAL = (QL_OS.MCU,)
+QL_OS_POSIX = (QL_OS.LINUX, QL_OS.FREEBSD, QL_OS.MACOS, QL_OS.QNX)
+QL_OS_BAREMETAL = (QL_OS.MCU,)
QL_HOOK_BLOCK = 0b0001
QL_CALL_BLOCK = 0b0010
@@ -83,3 +82,8 @@ arch_os_map = {
QL_ARCH.EVM : QL_OS.EVM,
QL_ARCH.CORTEX_M : QL_OS.MCU
}
+
+__all__ = [
+ 'QL_ENDIAN', 'QL_ARCH', 'QL_OS', 'QL_VERBOSE', 'QL_DEBUGGER', 'QL_INTERCEPT', 'QL_STOP',
+ 'QL_ARCH_INTERPRETER', 'QL_OS_POSIX', 'QL_OS_BAREMETAL', 'QL_HOOK_BLOCK', 'QL_CALL_BLOCK'
+]
diff --git a/qiling/debugger/gdb/gdb.py b/qiling/debugger/gdb/gdb.py
index 8b341666..a8aeceb1 100644
--- a/qiling/debugger/gdb/gdb.py
+++ b/qiling/debugger/gdb/gdb.py
@@ -3,47 +3,68 @@
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#
-# gdbserver --remote-debug 0.0.0.0:9999 /path/to binary
-# documentation: according to https://sourceware.org/gdb/current/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol
+# for watching actual protocol messages:
+# server: gdbserver --remote-debug 127.0.0.1:9999 /path/to/exec
+# client: gdb -q -ex "target remote 127.0.0.1:9999"
+#
+# also, run this command on the gdb client:
+# (gdb) set debug remote 1
+#
+# gdb remote protocol:
+# https://sourceware.org/gdb/current/onlinedocs/gdb/Remote-Protocol.html
-import struct, os, socket
-from binascii import unhexlify
-from typing import Iterator, Literal
+import os, socket, re
+from logging import Logger
+from typing import Iterator, Optional, Union
+
+from unicorn import UcError
+from unicorn.unicorn_const import (
+ UC_ERR_READ_UNMAPPED, UC_ERR_WRITE_UNMAPPED, UC_ERR_FETCH_UNMAPPED,
+ UC_ERR_READ_PROT, UC_ERR_WRITE_PROT, UC_ERR_FETCH_PROT,
+ UC_ERR_READ_UNALIGNED, UC_ERR_WRITE_UNALIGNED, UC_ERR_FETCH_UNALIGNED,
+ UC_ERR_INSN_INVALID
+)
from qiling import Qiling
-from qiling.const import *
-from qiling.utils import *
+from qiling.const import QL_ARCH, QL_ENDIAN, QL_OS
from qiling.debugger import QlDebugger
-from qiling.arch.x86_const import reg_map_16 as x86_reg_map_16
-from qiling.arch.x86_const import reg_map_32 as x86_reg_map_32
-from qiling.arch.x86_const import reg_map_64 as x86_reg_map_64
-from qiling.arch.x86_const import reg_map_misc as x86_reg_map_misc
-from qiling.arch.x86_const import reg_map_st as x86_reg_map_st
-from qiling.arch.arm_const import reg_map as arm_reg_map
-from qiling.arch.arm64_const import reg_map as arm64_reg_map
-from qiling.arch.mips_const import reg_map as mips_reg_map
-from qiling.loader.elf import AUX
+from qiling.debugger.gdb import xmlregs
+from qiling.debugger.gdb.utils import QlGdbUtils
-from .utils import QlGdbUtils
+# gdb logging prompt
+PROMPT = r'gdb>'
-GDB_SIGNAL_INT = 2
-GDB_SIGNAL_SEGV = 11
-GDB_SIGNAL_GILL = 4
-GDB_SIGNAL_STOP = 17
-GDB_SIGNAL_TRAP = 5
-GDB_SIGNAL_BUS = 10
+# default string encoding
+ENCODING = 'latin'
+# define a few handy linux signals
+SIGINT = 2
+SIGILL = 4
+SIGTRAP = 5
+SIGABRT = 6
+SIGBUS = 7
+SIGKILL = 9
+SIGSEGV = 11
+SIGALRM = 14
+SIGTERM = 15
+SIGCHLD = 16
+SIGCONT = 17
+SIGSTOP = 18
+
+# common replies
+REPLY_ACK = b'+'
+REPLY_EMPTY = b''
+REPLY_OK = b'OK'
+
+# reply type
+Reply = Union[bytes, str]
+
+class QlGdb(QlDebugger):
+ """A simple gdbserver implementation.
+ """
-class QlGdb(QlDebugger, object):
- """docstring for Debugsession"""
def __init__(self, ql: Qiling, ip: str = '127.0.01', port: int = 9999):
- super(QlGdb, self).__init__(ql)
-
- self.ql = ql
- self.last_pkt = None
- self.exe_abspath = os.path.abspath(self.ql.argv[0])
- self.rootfs_abspath = os.path.abspath(self.ql.rootfs)
- self.gdb = QlGdbUtils()
+ super().__init__(ql)
if type(port) is str:
port = int(port, 0)
@@ -51,763 +72,904 @@ class QlGdb(QlDebugger, object):
self.ip = ip
self.port = port
- if self.ql.baremetal:
- load_address = self.ql.loader.load_address
+ if ql.baremetal:
+ load_address = ql.loader.load_address
exit_point = load_address + os.path.getsize(ql.path)
- elif self.ql.code:
- load_address = self.ql.os.entry_point
+ elif ql.code:
+ load_address = ql.os.entry_point
exit_point = load_address + len(ql.code)
else:
load_address = ql.loader.load_address
exit_point = load_address + os.path.getsize(ql.path)
- if self.ql.baremetal:
- self.entry_point = self.ql.loader.entry_point
- elif self.ql.os.type in (QL_OS.LINUX, QL_OS.FREEBSD) and not self.ql.code:
- self.entry_point = self.ql.os.elf_entry
+ if ql.baremetal:
+ entry_point = ql.loader.entry_point
+ elif ql.os.type in (QL_OS.LINUX, QL_OS.FREEBSD) and not ql.code:
+ entry_point = ql.os.elf_entry
else:
- self.entry_point = self.ql.os.entry_point
+ entry_point = ql.os.entry_point
# Only part of the binary file will be debugged.
- if self.ql.entry_point is not None and self.ql.exit_point is not None:
- self.entry_point = self.ql.entry_point
- exit_point = self.ql.exit_point
+ if ql.entry_point is not None:
+ entry_point = ql.entry_point
- self.gdb.initialize(self.ql, self.entry_point, exit_point=exit_point, mappings=[(hex(load_address))])
+ if ql.exit_point is not None:
+ exit_point = ql.exit_point
- #Setup register tables, order of tables is important
- self.tables = {
- QL_ARCH.A8086 : list({**x86_reg_map_16, **x86_reg_map_misc}.keys()),
- QL_ARCH.X86 : list({**x86_reg_map_32, **x86_reg_map_misc, **x86_reg_map_st}.keys()),
- QL_ARCH.X8664 : list({**x86_reg_map_64, **x86_reg_map_misc, **x86_reg_map_st}.keys()),
- QL_ARCH.ARM : list({**arm_reg_map}.keys()),
- QL_ARCH.CORTEX_M : list({**arm_reg_map}.keys()),
- QL_ARCH.ARM64 : list({**arm64_reg_map}.keys()),
- QL_ARCH.MIPS : list({**mips_reg_map}.keys()),
+ self.gdb = QlGdbUtils(ql, entry_point, exit_point)
+
+ self.regsmap = xmlregs.load_regsmap(self.ql.arch.type)
+
+ def run(self):
+ server = GdbSerialConn(self.ip, self.port, self.ql.log)
+ killed = False
+
+ def __hexstr(value: int, nibbles: int = 0) -> str:
+ """Encode a value into a hex string.
+ """
+
+ length = (nibbles or self.ql.arch.bits // 4) // 2
+ byteorder = 'little' if self.ql.arch.endian == QL_ENDIAN.EL else 'big'
+
+ return value.to_bytes(length, byteorder).hex()
+
+ def __unkown_reg_value(nibbles: int) -> str:
+ """Encode the hex string for unknown regsiter value.
+ """
+
+ return 'x' * nibbles
+
+ def __get_reg_value(reg: Optional[int], pos: int, nibbles: int) -> str:
+ # reg is either None or uc reg invalid
+ if reg:
+ value = self.ql.arch.regs.read(reg)
+ assert type(value) is int
+
+ hexstr = __hexstr(value, nibbles)
+ else:
+ hexstr = __unkown_reg_value(nibbles)
+
+ return hexstr
+
+ def __set_reg_value(reg: Optional[int], pos: int, nibbles: int, hexval: str) -> None:
+ # reg is neither None nor uc reg invalid
+ if reg and hexval != __unkown_reg_value(nibbles):
+ assert len(hexval) == nibbles
+
+ val = int(hexval, 16)
+
+ if self.ql.arch.endian == QL_ENDIAN.EL:
+ val = __swap_endianess(val)
+
+ self.ql.arch.regs.write(reg, val)
+
+ def __swap_endianess(value: int) -> int:
+ length = (value.bit_length() + 7) // 8
+ raw = value.to_bytes(length, 'little')
+
+ return int.from_bytes(raw, 'big')
+
+
+ def handle_exclaim(subcmd: str) -> Reply:
+ return REPLY_OK
+
+
+ def handle_qmark(subcmd: str) -> Reply:
+ """Request status.
+
+ @see: https://sourceware.org/gdb/current/onlinedocs/gdb/Stop-Reply-Packets.html
+ """
+
+ from unicorn.x86_const import UC_X86_REG_EBP
+ from unicorn.x86_const import UC_X86_REG_RBP
+ from unicorn.arm_const import UC_ARM_REG_R11
+ from unicorn.arm64_const import UC_ARM64_REG_X29
+ from unicorn.mips_const import UC_MIPS_REG_INVALID
+
+ arch_uc_bp = {
+ QL_ARCH.X86 : UC_X86_REG_EBP,
+ QL_ARCH.X8664 : UC_X86_REG_RBP,
+ QL_ARCH.ARM : UC_ARM_REG_R11,
+ QL_ARCH.ARM64 : UC_ARM64_REG_X29,
+ QL_ARCH.MIPS : UC_MIPS_REG_INVALID, # skipped
+ QL_ARCH.A8086 : UC_X86_REG_EBP,
+ QL_ARCH.CORTEX_M : UC_ARM_REG_R11
+ }[self.ql.arch.type]
+
+ def __get_reg_idx(ucreg: int) -> int:
+ """Get the index of a uc reg whithin the regsmap array.
+
+ Returns: array index where this reg's info is stored, or -1 if not found
+ """
+
+ return next((i for i, (regnum, _, _) in enumerate(self.regsmap) if regnum == ucreg), -1)
+
+ def __get_reg_info(ucreg: int) -> str:
+ """Retrieve register info and pack it as a pair.
+ """
+
+ regnum = __get_reg_idx(ucreg)
+ hexval = __get_reg_value(*self.regsmap[regnum])
+
+ return f'{regnum:02x}:{hexval};'
+
+ # mips targets skip this reg info pair
+ bp_info = '' if self.ql.arch.type == QL_ARCH.MIPS else __get_reg_info(arch_uc_bp)
+
+ # FIXME: a8086 should use 'esp' and 'eip' here instead of 'sp' and 'ip' set by its arch instance
+ sp_info = __get_reg_info(self.ql.arch.regs.uc_sp)
+ pc_info = __get_reg_info(self.ql.arch.regs.uc_pc)
+
+ return f'T{SIGTRAP:02x}{bp_info}{sp_info}{pc_info}'
+
+
+ def handle_c(subcmd: str) -> Reply:
+ try:
+ self.gdb.resume_emu()
+ except UcError as err:
+ sigmap = {
+ UC_ERR_READ_UNMAPPED : SIGSEGV,
+ UC_ERR_WRITE_UNMAPPED : SIGSEGV,
+ UC_ERR_FETCH_UNMAPPED : SIGSEGV,
+ UC_ERR_WRITE_PROT : SIGSEGV,
+ UC_ERR_READ_PROT : SIGSEGV,
+ UC_ERR_FETCH_PROT : SIGSEGV,
+ UC_ERR_READ_UNALIGNED : SIGBUS,
+ UC_ERR_WRITE_UNALIGNED : SIGBUS,
+ UC_ERR_FETCH_UNALIGNED : SIGBUS,
+ UC_ERR_INSN_INVALID : SIGILL
+ }
+
+ # determine signal from uc error; default to SIGTERM
+ reply = f'S{sigmap.get(err.errno, SIGTERM):02x}'
+
+ except KeyboardInterrupt:
+ # emulation was interrupted with ctrl+c
+ reply = f'S{SIGINT:02x}'
+
+ else:
+ if self.ql.arch.regs.arch_pc == self.gdb.last_bp:
+ # emulation stopped because it hit a breakpoint
+ reply = f'S{SIGTRAP:02x}'
+ else:
+ # emulation has completed successfully
+ reply = f'W{self.ql.os.exit_code:02x}'
+
+ return reply
+
+
+ def handle_g(subcmd: str) -> Reply:
+ # NOTE: in the past the 'g' reply packet for arm included the f0-f7 and fps registers between pc
+ # and cpsr, which placed cpsr at index (regnum) 25. as the f-registers became obsolete the cpsr
+ # index decreased. in order to maintain backward compatibility with older gdb versions, the gap
+ # between pc and cpsr that used to represent the f-registers (96 bits each + 32 bits for fps) is
+ # filled with unknown reg values.
+ #
+ # gdb clients that follow the xml definitions no longer need these placeholders, as registers
+ # indices are flexible and may be defined arbitrarily though xml.
+ #
+ # see: ./xml/arm/arm-fpa.xml
+
+ return ''.join(__get_reg_value(*entry) for entry in self.regsmap)
+
+
+ def handle_G(subcmd: str) -> Reply:
+ data = subcmd
+
+ for reg, pos, nibbles in self.regsmap:
+ hexval = data[pos : pos + nibbles]
+
+ __set_reg_value(reg, pos, nibbles, hexval)
+
+ return REPLY_OK
+
+
+ def handle_H(subcmd: str) -> Reply:
+ op = subcmd[0]
+
+ if op in ('c', 'g'):
+ return REPLY_OK
+
+ return REPLY_EMPTY
+
+
+ def handle_k(subcmd: str) -> Reply:
+ global killed
+
+ killed = True
+ return REPLY_OK
+
+
+ def handle_m(subcmd: str) -> Reply:
+ """Read target memory.
+ """
+
+ addr, size = (int(p, 16) for p in subcmd.split(','))
+
+ try:
+ data = self.ql.mem.read(addr, size).hex()
+ except UcError:
+ return 'E14'
+ else:
+ return data
+
+
+ def handle_M(subcmd: str) -> Reply:
+ """Write target memory.
+ """
+
+ addr, data = subcmd.split(',')
+ size, data = data.split(':')
+
+ addr = int(addr, 16)
+ data = bytes.fromhex(data)
+
+ assert len(data) == size
+
+ try:
+ self.ql.mem.write(addr, data)
+ except UcError:
+ return 'E01'
+ else:
+ return REPLY_OK
+
+
+ def handle_p(subcmd: str) -> Reply:
+ """Read register value by index.
+ """
+
+ idx = int(subcmd, 16)
+
+ return __get_reg_value(*self.regsmap[idx])
+
+
+ def handle_P(subcmd: str) -> Reply:
+ """Write register value by index.
+ """
+
+ idx, data = subcmd.split('=')
+ idx = int(idx, 16)
+
+ if idx < len(self.regsmap):
+ __set_reg_value(*self.regsmap[idx], hexval=data)
+
+ return REPLY_OK
+
+ return 'E00'
+
+
+ def handle_Q(subcmd: str) -> Reply:
+ """General queries.
+
+ @see: https://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html
+ """
+
+ feature, *data = subcmd.split(':', maxsplit=1)
+
+ supported = (
+ 'DisableRandomization',
+ 'NonStop',
+ 'PassSignals',
+ 'ProgramSignals',
+ 'StartNoAckMode'
+ )
+
+ if feature == 'StartNoAckMode':
+ server.ack_mode = False
+ server.log.debug('[noack mode enabled]')
+
+ return REPLY_OK if feature in supported else REPLY_EMPTY
+
+
+ def handle_D(subcmd: str) -> Reply:
+ """Detach.
+ """
+
+ return REPLY_OK
+
+
+ def handle_q(subcmd: str) -> Reply:
+ query, *data = subcmd.split(':')
+
+ # qSupported command
+ #
+ # @see: https://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html#qSupported
+
+ if query == 'Supported':
+ # list of supported features excluding the multithreading-related ones
+ common = (
+ 'BreakpointCommands+',
+ 'ConditionalBreakpoints+',
+ 'ConditionalTracepoints+',
+ 'DisconnectedTracing+',
+ 'EnableDisableTracepoints+',
+ 'InstallInTrace+',
+ 'QAgent+',
+ 'QCatchSyscalls+',
+ 'QDisableRandomization+',
+ 'QEnvironmentHexEncoded+',
+ 'QEnvironmentReset+',
+ 'QEnvironmentUnset+',
+ 'QNonStop+',
+ 'QPassSignals+',
+ 'QProgramSignals+',
+ 'QSetWorkingDir+',
+ 'QStartNoAckMode+',
+ 'QStartupWithShell+',
+ 'QTBuffer:size+',
+ 'StaticTracepoints+',
+ 'TraceStateVariables+',
+ 'TracepointSource+',
+ # 'augmented-libraries-svr4-read+',
+ 'exec-events+',
+ 'fork-events+',
+ 'hwbreak+',
+ 'multiprocess+',
+ 'no-resumed+',
+ 'qXfer:auxv:read+',
+ 'qXfer:exec-file:read+',
+ 'qXfer:features:read+',
+ # 'qXfer:libraries-svr4:read+',
+ # 'qXfer:osdata:read+',
+ 'qXfer:siginfo:read+',
+ 'qXfer:siginfo:write+',
+ 'qXfer:statictrace:read+',
+ 'qXfer:threads:read+',
+ 'qXfer:traceframe-info:read+',
+ 'swbreak+',
+ 'tracenz+',
+ 'vfork-events+'
+ )
+
+ # might or might not need for multi thread
+ if self.ql.multithread:
+ features = (
+ 'PacketSize=47ff',
+ 'FastTracepoints+',
+ 'QThreadEvents+',
+ 'Qbtrace-conf:bts:size+',
+ 'Qbtrace-conf:pt:size+',
+ 'Qbtrace:bts+',
+ 'Qbtrace:off+',
+ 'Qbtrace:pt+',
+ 'qXfer:btrace-conf:read+',
+ 'qXfer:btrace:read+',
+ 'vContSupported+'
+ )
+
+ else:
+ features = (
+ 'PacketSize=3fff',
+ 'qXfer:spu:read+',
+ 'qXfer:spu:write+'
+ )
+
+ return ';'.join(common + features)
+
+ elif query == 'Xfer':
+ feature, op, annex, params = data
+ offset, length = (int(p, 16) for p in params.split(','))
+
+ if feature == 'features' and op == 'read':
+ xfercmd_abspath = os.path.dirname(os.path.abspath(__file__))
+ xml_folder = self.ql.arch.type.name.lower()
+ xfercmd_file = os.path.join(xfercmd_abspath, 'xml', xml_folder, annex)
+
+ if self.ql.os.type == QL_OS.WINDOWS:
+ self.ql.log.info(f'{PROMPT} Qiling does not support XML for this platform yet')
+ content = ''
+
+ elif not os.path.exists(xfercmd_file):
+ self.ql.log.info(f'{PROMPT} XML file not found: "{xfercmd_file}"')
+ content = ''
+
+ else:
+ with open(xfercmd_file, 'r') as f:
+ f.seek(offset, os.SEEK_SET)
+ content = f.read(length)
+
+ return f'{"l" if len(content) < length else "m"}{content}'
+
+ elif feature == 'threads' and op == 'read':
+ if not self.ql.baremetal and hasattr(self.ql.os, 'pid'):
+ content = '\r\n'.join((
+ '',
+ f'',
+ ''
+ ))
+
+ else:
+ content = ''
+
+ return f'l{content}'
+
+ elif feature == 'auxv' and op == 'read':
+ auxv_data = bytearray()
+
+ if hasattr(self.ql.loader, 'auxv'):
+ nbytes = self.ql.arch.bits // 8
+
+ auxv_addr = self.ql.loader.auxv + offset
+ null_entry = bytes(nbytes * 2)
+
+ # keep reading until AUXV.AT_NULL is reached
+ while not auxv_data.endswith(null_entry):
+ auxv_data.extend(self.ql.mem.read(auxv_addr, nbytes))
+ auxv_addr += nbytes
+
+ auxv_data.extend(self.ql.mem.read(auxv_addr, nbytes))
+ auxv_addr += nbytes
+
+ return b'l' + auxv_data[:length]
+
+ elif feature == 'exec-file' and op == 'read':
+ return f'l{os.path.abspath(self.ql.path)}'
+
+ elif feature == 'libraries-svr4' and op == 'read':
+ # TODO: this one requires information of loaded libraries which currently not provided
+ # by the ELF loader. until we gather that information, we cannot fulfill this request
+ #
+ # see: https://sourceware.org/gdb/current/onlinedocs/gdb/Library-List-Format-for-SVR4-Targets.html
+ return REPLY_EMPTY
+
+ # if self.ql.os.type in (QL_OS.LINUX, QL_OS.FREEBSD):
+ # tag = 'library-list-svr4'
+ # xml_lib_entries = (f'' for lbnd, ubnd, _, _, path in self.ql.mem.get_mapinfo() if path)
+ #
+ # xml = '\r\n'.join((f'<{tag} version="1.0">', *xml_lib_entries, f'{tag}>'))
+ #
+ # return f'l{xml}'
+ # else:
+ # return f''
+
+ elif feature == 'btrace-conf' and op == 'read':
+ return 'E.Btrace not enabled.'
+
+ elif query == 'Attached':
+ return REPLY_EMPTY
+
+ elif query == 'C':
+ return REPLY_EMPTY
+
+ elif query == 'L':
+ return 'M001'
+
+ elif query == 'fThreadInfo':
+ return 'm0'
+
+ elif query == 'sThreadInfo':
+ return 'l'
+
+ elif query == 'TStatus':
+ tsize = __hexstr(0x500000)
+
+ fields = (
+ 'T0',
+ 'tnotrun:0',
+ 'tframes:0',
+ 'tcreated:0',
+ f'tfree:{tsize}',
+ f'tsize:{tsize}',
+ 'circular:0',
+ 'disconn:0',
+ 'starttime:0',
+ 'stoptime:0',
+ 'username:',
+ 'notes::'
+ )
+
+ return ';'.join(fields)
+
+ elif query in ('TfV', 'TsV', 'TfP', 'TsP'):
+ return 'l'
+
+ elif query == 'Symbol':
+ return REPLY_OK
+
+ elif query == 'Offsets':
+ fields = ('Text=0', 'Data=0', 'Bss=0')
+
+ return ';'.join(fields)
+
+ return REPLY_EMPTY
+
+
+ def handle_v(subcmd: str) -> Reply:
+ if subcmd == 'MustReplyEmpty':
+ return REPLY_EMPTY
+
+ elif subcmd.startswith('File'):
+ _, op, data = subcmd.split(':', maxsplit=2)
+ params = data.split(',')
+
+ if op == 'open':
+ fd = -1
+
+ # files can be opened only where there is an os that supports filesystem
+ if not self.ql.interpreter and hasattr(self.ql.os, 'path'):
+ path, flags, mode = params
+
+ path = bytes.fromhex(path).decode(encoding='utf-8')
+ flags = int(flags, 16)
+ mode = int(mode, 16)
+
+ # try to guess whether this is an emulated path or real one
+ if path.startswith(os.path.abspath(self.ql.rootfs)):
+ host_path = path
+ else:
+ host_path = self.ql.os.path.virtual_to_host_path(path)
+
+ self.ql.log.debug(f'{PROMPT} target file: {host_path}')
+
+ if os.path.exists(host_path) and not path.startswith(r'/proc'):
+ fd = os.open(host_path, flags, mode)
+
+ return f'F{fd}'
+
+ elif op == 'pread':
+ fd, count, offset = (int(p, 16) for p in params)
+
+ data = os.pread(fd, count, offset)
+
+ return f'F{len(data):x};'.encode() + data
+
+ elif op == 'close':
+ fd, *_ = params
+ fd = int(fd, 16)
+
+ os.close(fd)
+ return 'F0'
+
+ return REPLY_EMPTY
+
+ elif subcmd.startswith('Kill'):
+ return handle_k('')
+
+ elif subcmd.startswith('Cont'):
+ # remove 'Cont' prefix
+ data = subcmd[len('Cont'):]
+
+ if data == '?':
+ # note 't' and 'r' are currently not supported
+ return ';'.join(('vCont', 'c', 'C', 's', 'S'))
+
+ elif data.startswith(';'):
+ groups = subcmd.split(';')[1:]
+
+ for grp in groups:
+ cmd, tid = grp.split(':', maxsplit=1)
+
+ if cmd in ('c', f'C{SIGTRAP:02x}'):
+ return handle_c('')
+
+ elif cmd in ('s', f'S{SIGTRAP:02x}'):
+ return handle_s('')
+
+ # FIXME: not sure how to handle multiple command
+ # groups, so handling just the first one
+ break
+
+ return REPLY_EMPTY
+
+
+ def handle_s(subcmd: str) -> Reply:
+ """Perform a single step.
+ """
+
+ # BUG: a known unicorn caching issue causes it to emulate more
+ # steps than requestes. until that issue is fixed, single stepping
+ # is essentially broken.
+ #
+ # @see: https://github.com/unicorn-engine/unicorn/issues/1606
+
+ self.gdb.resume_emu(steps=1)
+
+ return f'S{SIGTRAP:02x}'
+
+
+ def handle_X(subcmd: str) -> Reply:
+ """Write data to memory.
+ """
+
+ params, data = subcmd.split(':', maxsplit=1)
+ addr, length = (int(p, 16) for p in params.split(','))
+
+ if length != len(data):
+ return 'E00'
+
+ try:
+ if data:
+ self.ql.mem.write(addr, data.encode(ENCODING))
+ except UcError:
+ return 'E01'
+ else:
+ return REPLY_OK
+
+
+ def handle_Z(subcmd: str) -> Reply:
+ """Insert breakpoints or watchpoints.
+ """
+
+ params, *conds = subcmd.split(';')
+ type, addr, kind = (int(p, 16) for p in params.split(','))
+
+ # type values:
+ # 0 = sw breakpoint
+ # 1 = hw breakpoint
+ # 2 = write watchpoint
+ # 3 = read watchpoint
+ # 4 = access watchpoint
+
+ if type == 0:
+ self.gdb.bp_insert(addr)
+ return REPLY_OK
+
+ return REPLY_EMPTY
+
+
+ def handle_z(subcmd: str) -> Reply:
+ """Remove breakpoints or watchpoints.
+ """
+
+ type, addr, kind = (int(p, 16) for p in subcmd.split(','))
+
+ if type == 0:
+ try:
+ self.gdb.bp_remove(addr)
+ except ValueError:
+ return 'E22'
+ else:
+ return REPLY_OK
+
+ return REPLY_EMPTY
+
+
+ handlers = {
+ '!': handle_exclaim,
+ '?': handle_qmark,
+ 'c': handle_c,
+ 'C': handle_c, # this is intentional; not a typo
+ 'D': handle_D,
+ 'g': handle_g,
+ 'G': handle_G,
+ 'H': handle_H,
+ 'k': handle_k,
+ 'm': handle_m,
+ 'M': handle_M,
+ 'p': handle_p,
+ 'P': handle_P,
+ 'q': handle_q,
+ 'Q': handle_Q,
+ 's': handle_s,
+ 'v': handle_v,
+ 'X': handle_X,
+ 'Z': handle_Z,
+ 'z': handle_z
}
- def addr_to_str(self, addr: int, short: bool = False, endian: Literal['little', 'big'] = 'big') -> str:
- # a hacky way to divide archbits by 2 if short, and leave it unchanged if not
- nbits = self.ql.arch.bits // (int(short) + 1)
+ # main server loop
+ for packet in server.readpackets():
+ if server.ack_mode:
+ server.send(REPLY_ACK, raw=True)
+ server.log.debug('[sent ack]')
- if nbits == 64:
- s = f'{int.from_bytes(self.ql.pack64(addr), byteorder=endian):016x}'
+ cmd, subcmd = packet[0], packet[1:]
+ handler = handlers.get(f'{cmd:c}')
- elif nbits == 32:
- s = f'{int.from_bytes(self.ql.pack32(addr), byteorder=endian):08x}'
+ if handler:
+ reply = handler(subcmd.decode(ENCODING))
+ server.send(reply)
- elif nbits == 16:
- s = f'{int.from_bytes(self.ql.pack16(addr), byteorder=endian):04x}'
-
- else:
- raise RuntimeError
-
- return s
-
- def bin_to_escstr(self, rawbin):
- rawbin_escape = ""
-
- def incomplete_hex_check(hexchar):
- if len(hexchar) == 1:
- hexchar = "0" + hexchar
- return hexchar
-
- for a in rawbin:
-
- # The binary data representation uses 7d (ASCII ‘}’) as an escape character.
- # Any escaped byte is transmitted as the escape character followed by the original character XORed with 0x20.
- # For example, the byte 0x7d would be transmitted as the two bytes 0x7d 0x5d. The bytes 0x23 (ASCII ‘#’), 0x24 (ASCII ‘$’), and 0x7d (ASCII ‘}’)
- # must always be escaped. Responses sent by the stub must also escape 0x2a (ASCII ‘*’),
- # so that it is not interpreted as the start of a run-length encoded sequence (described next).
-
- if a in (42,35,36, 125):
- a = a ^ 0x20
- a = (str(hex(a)[2:]))
- a = incomplete_hex_check(a)
- a = str("7d%s" % a)
+ if killed:
+ break
else:
- a = (str(hex(a)[2:]))
- a = incomplete_hex_check(a)
+ self.ql.log.info(f'{PROMPT} command not supported')
+ server.send(REPLY_EMPTY)
- rawbin_escape += a
+ server.close()
- return unhexlify(rawbin_escape)
- def setup_server(self):
- self.ql.log.info("gdb> Listening on %s:%u" % (self.ip, self.port))
+class GdbSerialConn:
+ """Serial connection handler.
+ """
+
+ # default recieve buffer size
+ BUFSIZE = 4096
+
+ def __init__(self, ipaddr: str, port: int, logger: Logger) -> None:
+ """Create a new gdb serial connection handler.
+
+ Args:
+ ipaddr : ip address to bind the socket to
+ port : port number to listen on
+ logger : logger instance to use
+ """
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- sock.bind((self.ip, self.port))
- sock.listen(1)
- clientsocket, addr = sock.accept()
+ sock.bind((ipaddr, port))
+ sock.listen()
- self.sock = sock
- self.clientsocket = clientsocket
- self.netin = clientsocket.makefile('r')
- self.netout = clientsocket.makefile('w')
+ self.log = logger
+ self.log.info(f'{PROMPT} listening on {ipaddr}:{port:d}')
+
+ client, _ = sock.accept()
+
+ self.sock = sock
+ self.client = client
+
+ # ack mode should be turend on by default
+ self.ack_mode = True
def close(self):
- self.netin.close()
- self.netout.close()
- self.clientsocket.close()
+ """Close the gdb serial connection handler and release its resources.
+ """
+
+ self.client.close()
self.sock.close()
- def run(self):
- self.setup_server()
-
- while self.receive() == 'Good':
- pkt = self.last_pkt
- self.send_raw('+')
-
- def handle_qmark(subcmd):
- def gdbqmark_converter(arch):
- """
- MIPS32_EL : gdbserver response ("$T051d:00e7ff7f;25:40ccfc77;#65")
- MIPS32_EB : gdbserver response ("$T051d:7fff6dc0;25:77fc4880;thread:28fa;core:0;");
- ARM64: gdbserver response "$T051d:0*,;1f:80f6f*"ff0* ;20:c02cfdb7f* 0* ;thread:p1f9.1f9;core:0;#56");
- ARM: gdbserver $T050b:0*"00;0d:e0f6ffbe;0f:8079fdb6;#ae"
- """
- adapter = {
- QL_ARCH.A8086 : [ 0x05, 0x04, 0x08 ],
- QL_ARCH.X86 : [ 0x05, 0x04, 0x08 ],
- QL_ARCH.X8664 : [ 0x06, 0x07, 0x10 ],
- QL_ARCH.MIPS : [ 0x1d, 0x00, 0x25 ],
- QL_ARCH.ARM : [ 0x0b, 0x0d, 0x0f ],
- QL_ARCH.CORTEX_M : [ 0x0b, 0x0d, 0x0f ],
- QL_ARCH.ARM64 : [ 0x1d, 0xf1, 0x20 ]
- }
- return adapter.get(arch)
-
- idhex, spid, pcid = gdbqmark_converter(self.ql.arch.type)
- sp = self.addr_to_str(self.ql.arch.regs.arch_sp)
- pc = self.addr_to_str(self.ql.arch.regs.arch_pc)
- nullfill = "0" * int(self.ql.arch.bits / 4)
-
- if self.ql.arch.type == QL_ARCH.MIPS:
- self.send('T%.2x%.2x:%s;%.2x:%s;' %(GDB_SIGNAL_TRAP, idhex, sp, pcid, pc))
- else:
- self.send('T%.2x%.2x:%s;%.2x:%s;%.2x:%s;' %(GDB_SIGNAL_TRAP, idhex, nullfill, spid, sp, pcid, pc))
-
-
- def handle_c(subcmd):
- self.gdb.resume_emu(self.ql.arch.regs.arch_pc)
-
- if self.gdb.bp_list == [self.entry_point]:
- self.send("W00")
- else:
- self.send(('S%.2x' % GDB_SIGNAL_TRAP))
-
-
- handle_C = handle_c
-
-
- def handle_g(subcmd):
- s = ''
-
- if self.ql.arch.type == QL_ARCH.A8086:
- for reg in self.tables[QL_ARCH.A8086][:16]:
- r = self.ql.arch.regs.read(reg)
- tmp = self.addr_to_str(r)
- s += tmp
-
- elif self.ql.arch.type == QL_ARCH.X86:
- for reg in self.tables[QL_ARCH.X86][:16]:
- r = self.ql.arch.regs.read(reg)
- tmp = self.addr_to_str(r)
- s += tmp
-
- elif self.ql.arch.type == QL_ARCH.X8664:
- for reg in self.tables[QL_ARCH.X8664][:24]:
- r = self.ql.arch.regs.read(reg)
- if self.ql.arch.reg_bits(reg) == 64:
- tmp = self.addr_to_str(r)
- elif self.ql.arch.reg_bits(reg) == 32:
- tmp = self.addr_to_str(r, short = True)
- s += tmp
-
- elif self.ql.arch.type == QL_ARCH.ARM:
-
-
- # r0-r12,sp,lr,pc,cpsr ,see https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/arch/arm.h;h=fa589fd0582c0add627a068e6f4947a909c45e86;hb=HEAD#l127
- for reg in self.tables[QL_ARCH.ARM][:16] + [self.tables[QL_ARCH.ARM][25]]:
- # if reg is pc, make sure to take thumb mode into account
- r = self.ql.arch.effective_pc if reg == "pc" else self.ql.arch.regs.read(reg)
-
- tmp = self.addr_to_str(r)
- s += tmp
-
- elif self.ql.arch.type == QL_ARCH.ARM64:
- for reg in self.tables[QL_ARCH.ARM64][:33]:
- r = self.ql.arch.regs.read(reg)
- tmp = self.addr_to_str(r)
- s += tmp
-
- elif self.ql.arch.type == QL_ARCH.MIPS:
- for reg in self.tables[QL_ARCH.MIPS][:38]:
- r = self.ql.arch.regs.read(reg)
- tmp = self.addr_to_str(r)
- s += tmp
-
- self.send(s)
-
-
- def handle_G(subcmd):
- count = 0
-
- if self.ql.arch.type == QL_ARCH.A8086:
- for i in range(0, len(subcmd), 8):
- reg_data = subcmd[i:i+7]
- reg_data = int(reg_data, 16)
- self.ql.arch.regs.write(self.tables[QL_ARCH.A8086][count], reg_data)
- count += 1
-
- elif self.ql.arch.type == QL_ARCH.X86:
- for i in range(0, len(subcmd), 8):
- reg_data = subcmd[i:i+7]
- reg_data = int(reg_data, 16)
- self.ql.arch.regs.write(self.tables[QL_ARCH.X86][count], reg_data)
- count += 1
-
-
- elif self.ql.arch.type == QL_ARCH.X8664:
- for i in range(0, 17*16, 16):
- reg_data = subcmd[i:i+15]
- reg_data = int(reg_data, 16)
- self.ql.arch.regs.write(self.tables[QL_ARCH.X8664][count], reg_data)
- count += 1
- for j in range(17*16, 17*16+15*8, 8):
- reg_data = subcmd[j:j+7]
- reg_data = int(reg_data, 16)
- self.ql.arch.regs.write(self.tables[QL_ARCH.X8664][count], reg_data)
- count += 1
-
- elif self.ql.arch.type == QL_ARCH.ARM:
- for i in range(0, len(subcmd), 8):
- reg_data = subcmd[i:i + 7]
- reg_data = int(reg_data, 16)
- self.ql.arch.regs.write(self.tables[QL_ARCH.ARM][count], reg_data)
- count += 1
-
- elif self.ql.arch.type == QL_ARCH.ARM64:
- for i in range(0, len(subcmd), 16):
- reg_data = subcmd[i:i+15]
- reg_data = int(reg_data, 16)
- self.ql.arch.regs.write(self.tables[QL_ARCH.ARM64][count], reg_data)
- count += 1
-
- elif self.ql.arch.type == QL_ARCH.MIPS:
- for i in range(0, len(subcmd), 8):
- reg_data = subcmd[i:i+7]
- reg_data = int(reg_data, 16)
- self.ql.arch.regs.write(self.tables[QL_ARCH.MIPS][count], reg_data)
- count += 1
-
- self.send('OK')
-
-
- def handle_H(subcmd):
- if subcmd.startswith('g'):
- self.send('OK')
- if subcmd.startswith('c'):
- self.send('OK')
-
-
- def handle_m(subcmd):
- addr, size = subcmd.split(',')
- addr = int(addr, 16)
- size = int(size, 16)
-
- try:
- tmp = ''
- for s in range(size):
- mem = self.ql.mem.read(addr + s, 1)
- mem = "".join(
- [str("{:02x}".format(ord(c))) for c in mem.decode('latin1')])
- tmp += mem
- self.send(tmp)
-
- except:
- self.send('E14')
-
-
- def handle_M(subcmd):
- addr, data = subcmd.split(',')
- size, data = data.split(':')
- addr = int(addr, 16)
- data = bytes.fromhex(data)
- try:
- self.ql.mem.write(addr, data)
- self.send('OK')
- except:
- self.send('E01')
-
-
- def handle_p(subcmd):
- reg_index = int(subcmd, 16)
- reg_value = None
- try:
- if self.ql.arch.type == QL_ARCH.A8086:
- if reg_index <= 9:
- reg_value = self.ql.arch.regs.read(self.tables[QL_ARCH.A8086][reg_index-1])
- else:
- reg_value = 0
- reg_value = self.addr_to_str(reg_value)
-
- elif self.ql.arch.type == QL_ARCH.X86:
- if reg_index <= 24:
- reg_value = self.ql.arch.regs.read(self.tables[QL_ARCH.X86][reg_index-1])
- else:
- reg_value = 0
- reg_value = self.addr_to_str(reg_value)
-
- elif self.ql.arch.type == QL_ARCH.X8664:
- if reg_index <= 32:
- reg_value = self.ql.arch.regs.read(self.tables[QL_ARCH.X8664][reg_index-1])
- else:
- reg_value = 0
- if reg_index <= 17:
- reg_value = self.addr_to_str(reg_value)
- elif 17 < reg_index:
- reg_value = self.addr_to_str(reg_value, short = True)
-
- elif self.ql.arch.type == QL_ARCH.ARM:
- if reg_index < 26:
- reg_value = self.ql.arch.regs.read(self.tables[QL_ARCH.ARM][reg_index - 1])
- else:
- reg_value = 0
- reg_value = self.addr_to_str(reg_value)
-
- elif self.ql.arch.type == QL_ARCH.ARM64:
- if reg_index <= 32:
- reg_value = self.ql.arch.regs.read(self.tables[QL_ARCH.ARM64][reg_index - 1])
- else:
- reg_value = 0
- reg_value = self.addr_to_str(reg_value)
-
- elif self.ql.arch.type == QL_ARCH.MIPS:
- if reg_index <= 37:
- reg_value = self.ql.arch.regs.read(self.tables[QL_ARCH.MIPS][reg_index - 1])
- else:
- reg_value = 0
- reg_value = self.addr_to_str(reg_value)
-
- if type(reg_value) is not str:
- reg_value = self.addr_to_str(reg_value)
-
- self.send(reg_value)
- except:
- self.close()
- raise
-
-
- def handle_P(subcmd):
- reg_index, reg_data = subcmd.split('=')
- reg_index = int(reg_index, 16)
- reg_name = self.tables[self.ql.arch.type][reg_index]
-
- if self.ql.arch.type == QL_ARCH.A8086:
- reg_data = int(reg_data, 16)
- reg_data = int.from_bytes(struct.pack(' Write to register %s with %x\n" % (self.tables[self.ql.arch.type][reg_index], reg_data))
- self.send('OK')
-
-
- def handle_Q(subcmd):
- if subcmd.startswith('StartNoAckMode'):
- self.send('OK')
-
- elif subcmd.startswith('DisableRandomization'):
- self.send('OK')
-
- elif subcmd.startswith('ProgramSignals'):
- self.send('OK')
-
- elif subcmd.startswith('NonStop'):
- self.send('OK')
-
- elif subcmd.startswith('PassSignals'):
- self.send('OK')
-
- elif subcmd.startswith('qemu'):
- self.send('')
-
- def handle_D(subcmd):
- self.send('OK')
-
- def handle_q(subcmd):
- if subcmd.startswith('Supported:'):
- # might or might not need for multi thread
- if self.ql.multithread == False:
- self.send("PacketSize=3fff;QPassSignals+;QProgramSignals+;QStartupWithShell+;QEnvironmentHexEncoded+;QEnvironmentReset+;QEnvironmentUnset+;QSetWorkingDir+;QCatchSyscalls+;qXfer:libraries-svr4:read+;augmented-libraries-svr4-read+;qXfer:auxv:read+;qXfer:spu:read+;qXfer:spu:write+;qXfer:siginfo:read+;qXfer:siginfo:write+;qXfer:features:read+;QStartNoAckMode+;qXfer:osdata:read+;multiprocess+;fork-events+;vfork-events+;exec-events+;QNonStop+;QDisableRandomization+;qXfer:threads:read+;ConditionalTracepoints+;TraceStateVariables+;TracepointSource+;DisconnectedTracing+;StaticTracepoints+;InstallInTrace+;qXfer:statictrace:read+;qXfer:traceframe-info:read+;EnableDisableTracepoints+;QTBuffer:size+;tracenz+;ConditionalBreakpoints+;BreakpointCommands+;QAgent+;swbreak+;hwbreak+;qXfer:exec-file:read+;no-resumed+")
- else:
- self.send("PacketSize=47ff;QPassSignals+;QProgramSignals+;QStartupWithShell+;QEnvironmentHexEncoded+;QEnvironmentReset+;QEnvironmentUnset+;QSetWorkingDir+;QCatchSyscalls+;qXfer:libraries-svr4:read+;augmented-libraries-svr4-read+;qXfer:auxv:read+;qXfer:siginfo:read+;qXfer:siginfo:write+;qXfer:features:read+;QStartNoAckMode+;qXfer:osdata:read+;multiprocess+;fork-events+;vfork-events+;exec-events+;QNonStop+;QDisableRandomization+;qXfer:threads:read+;ConditionalTracepoints+;TraceStateVariables+;TracepointSource+;DisconnectedTracing+;FastTracepoints+;StaticTracepoints+;InstallInTrace+;qXfer:statictrace:read+;qXfer:traceframe-info:read+;EnableDisableTracepoints+;QTBuffer:size+;tracenz+;ConditionalBreakpoints+;BreakpointCommands+;QAgent+;Qbtrace:bts+;Qbtrace-conf:bts:size+;Qbtrace:pt+;Qbtrace-conf:pt:size+;Qbtrace:off+;qXfer:btrace:read+;qXfer:btrace-conf:read+;swbreak+;hwbreak+;qXfer:exec-file:read+;vContSupported+;QThreadEvents+;no-resumed+")
- elif subcmd.startswith('Xfer:features:read'):
- xfercmd_file = subcmd.split(':')[3]
- xfercmd_abspath = os.path.dirname(os.path.abspath(__file__))
- xml_folder = self.ql.arch.type.name.lower()
- xfercmd_file = os.path.join(xfercmd_abspath,"xml",xml_folder, xfercmd_file)
-
- if os.path.exists(xfercmd_file) and self.ql.os.type is not QL_OS.WINDOWS:
- with open(xfercmd_file, 'r') as f:
- file_contents = f.read()
- self.send("l%s" % file_contents)
- else:
- self.ql.log.info("gdb> Platform is not supported by xml or xml file not found: %s\n" % (xfercmd_file))
- self.send("l")
-
-
- elif subcmd.startswith('Xfer:threads:read::0,'):
- if self.ql.os.type in QL_OS_NONPID or self.ql.baremetal:
- self.send("l")
- else:
- file_contents = ("\r\n\r\n")
- self.send("l" + file_contents)
-
- elif subcmd.startswith('Xfer:auxv:read::'):
- if self.ql.code:
- return
-
- if self.ql.os.type in (QL_OS.LINUX, QL_OS.FREEBSD):
- def __read_auxv() -> Iterator[int]:
- auxv_entries = (
- AUX.AT_HWCAP,
- AUX.AT_PAGESZ,
- AUX.AT_CLKTCK,
- AUX.AT_PHDR,
- AUX.AT_PHENT,
- AUX.AT_PHNUM,
- AUX.AT_BASE,
- AUX.AT_FLAGS,
- AUX.AT_ENTRY,
- AUX.AT_UID,
- AUX.AT_EUID,
- AUX.AT_GID,
- AUX.AT_EGID,
- AUX.AT_SECURE,
- AUX.AT_RANDOM,
- AUX.AT_HWCAP2,
- AUX.AT_EXECFN,
- AUX.AT_PLATFORM,
- AUX.AT_NULL
- )
-
- for e in auxv_entries:
- yield e.value
- yield self.ql.loader.aux_vec[e]
-
- annex = self.addr_to_str(0)[:-2]
- sysinfo_ehdr = self.addr_to_str(0)
-
- auxvdata_c = unhexlify(''.join([annex, sysinfo_ehdr] + [self.addr_to_str(val) for val in __read_auxv()]))
- auxvdata = self.bin_to_escstr(auxvdata_c)
- else:
- auxvdata = b""
-
- self.send(b'l!%s' % auxvdata)
-
- elif subcmd.startswith('Xfer:exec-file:read:'):
- self.send("l%s" % str(self.exe_abspath))
-
-
- elif subcmd.startswith('Xfer:libraries-svr4:read:'):
- if self.ql.os.type in (QL_OS.LINUX, QL_OS.FREEBSD):
- xml_addr_mapping=("")
- """
- FIXME: need to find out when do we need this
- """
- #for s, e, info in self.ql.map_info:
- # addr_mapping += ("" %(info, e, s))
- xml_addr_mapping += ("")
- self.send("l%s" % xml_addr_mapping)
- else:
- self.send("l")
-
- elif subcmd.startswith("Xfer:btrace-conf:read:"):
- self.send("E.Btrace not enabled.")
-
- elif subcmd == "Attached":
- self.send("")
-
- elif subcmd.startswith("C"):
- self.send("")
-
- elif subcmd.startswith("L:"):
- self.send("M001")
-
- elif subcmd == "fThreadInfo":
- self.send("m0")
-
- elif subcmd == "sThreadInfo":
- self.send("l")
-
- elif subcmd == ("TStatus"):
- self.send("T0;tnotrun:0;tframes:0;tcreated:0;tfree:50*!;tsize:50*!;circular:0;disconn:0;starttime:0;stoptime:0;username:;notes::")
-
- elif subcmd == ("TfV"):
- self.send("l")
-
- elif subcmd == ("TsV"):
- self.send("l")
-
- elif subcmd == ("TfP"):
- self.send("l")
-
- elif subcmd == ("TsP"):
- self.send("l")
-
-
- elif subcmd.startswith("Symbol"):
- self.send("")
-
- elif subcmd.startswith("Attached"):
- self.send("")
-
- elif subcmd == "Offsets":
- self.send("Text=0;Data=0;Bss=0")
-
-
- def handle_v(subcmd):
-
- if subcmd == 'MustReplyEmpty':
- self.send("")
-
- elif subcmd.startswith('File:open'):
- if self.ql.os.type == QL_OS.UEFI or self.ql.baremetal:
- self.send("F-1")
- return
-
- (file_path, flags, mode) = subcmd.split(':')[-1].split(',')
- file_path = unhexlify(file_path).decode(encoding='UTF-8')
- flags = int(flags, base=16)
- mode = int(mode, base=16)
- if file_path.startswith(self.rootfs_abspath):
- file_abspath = file_path
- else:
- file_abspath = self.ql.os.path.transform_to_real_path(file_path)
-
- self.ql.log.debug("gdb> target file: %s" % (file_abspath))
- if os.path.exists(file_abspath) and not (file_path).startswith("/proc"):
- fd = os.open(file_abspath, flags, mode)
- self.send("F%x" % fd)
- else:
- self.send("F-1")
- return
-
- elif subcmd.startswith('File:pread:'):
- (fd, count, offset) = subcmd.split(':')[-1].split(',')
-
- fd = int(fd, base=16)
- offset = int(offset, base=16)
- count = int(count, base=16)
-
- data = os.pread(fd, count, offset)
- size = len(data)
- data = self.bin_to_escstr(data)
-
- if data:
- self.send(("F%x;" % size).encode() + (data))
- else:
- self.send("F0;")
-
- elif subcmd.startswith('File:close'):
- fd = subcmd.split(':')[-1]
- fd = int(fd, base=16)
- os.close(fd)
- self.send("F0")
-
- elif subcmd.startswith('Kill'):
- self.send('OK')
-
- elif subcmd.startswith('Cont'):
- self.ql.log.debug("gdb> Cont command received: %s" % subcmd)
- if subcmd == 'Cont?':
- self.send('vCont;c;C;t;s;S;r')
- elif subcmd.startswith ("Cont;"):
- subcmd = subcmd.split(';')
- subcmd = subcmd[1].split(':')
- if subcmd[0] in ('c', 'C05'):
- handle_c(subcmd)
- elif subcmd[0] in ('S', 's', 'S05'):
- handle_s(subcmd)
- else:
- self.send("")
-
-
- def handle_s(subcmd):
- current_address = self.gdb.current_address
- if current_address is None:
- entry_point = self.gdb.entry_point
- if entry_point is not None:
- self.gdb.soft_bp = True
- self.gdb.resume_emu(entry_point)
- else:
- self.gdb.soft_bp = True
- self.gdb.resume_emu()
- self.send('S%.2x' % GDB_SIGNAL_TRAP)
-
-
- def handle_X(subcmd):
- self.send('')
-
-
- def handle_Z(subcmd):
- data = subcmd
- ztype = data[data.find('Z') + 1:data.find(',')]
- if ztype == '0':
- ztype, address, value = data.split(',')
- address = int(address, 16)
- try:
- self.gdb.bp_insert(address)
- self.send('OK')
- except:
- self.send('E22')
- else:
- self.send('E22')
-
-
- def handle_z(subcmd):
- data = subcmd.split(',')
- if len(data) != 3:
- self.send('E22')
- try:
- type = data[0]
- addr = int(data[1], 16)
- length = data[2]
- self.gdb.bp_remove(addr, type, length)
- self.send('OK')
- except:
- self.send('E22')
-
-
- def handle_exclaim(subcmd):
- self.send('OK')
-
- commands = {
- '!': handle_exclaim,
- '?': handle_qmark,
- 'c': handle_c,
- 'C': handle_C,
- 'D': handle_D,
- 'g': handle_g,
- 'G': handle_G,
- 'H': handle_H,
- 'm': handle_m,
- 'M': handle_M,
- 'p': handle_p,
- 'P': handle_P,
- 'q': handle_q,
- 'Q': handle_Q,
- 's': handle_s,
- 'v': handle_v,
- 'X': handle_X,
- 'Z': handle_Z,
- 'z': handle_z
- }
-
- cmd, subcmd = pkt[0], pkt[1:]
- if cmd == 'k':
+ def readpackets(self) -> Iterator[bytes]:
+ """Iterate through incoming packets in an active connection until
+ it is terminated.
+ """
+
+ pattern = re.compile(br'^\$(?P[^#]*)#(?P[0-9a-fA-F]{2})')
+ buffer = bytearray()
+
+ while True:
+ try:
+ incoming = self.client.recv(self.BUFSIZE)
+ except ConnectionError:
break
- if cmd not in commands:
- self.send('')
- self.ql.log.info("gdb> Command not supported: %s\n" %(cmd))
+ # remote connection closed
+ if not incoming:
+ break
+
+ buffer += incoming
+
+ # discard incoming acks
+ if buffer[0:1] == REPLY_ACK:
+ del buffer[0]
+
+ packet = pattern.match(buffer)
+
+ # if there is no match, the rest of the packet might be missing
+ if not packet:
continue
- self.ql.log.debug("gdb> received: %s%s" % (cmd, subcmd))
- commands[cmd](subcmd)
- self.close()
+ data = packet['data']
+ read_csum = int(packet['checksum'], 16)
+ calc_csum = GdbSerialConn.checksum(data)
+ if read_csum != calc_csum:
+ raise IOError(f'checksum error: expected {calc_csum:02x} but got {read_csum:02x}')
- def receive(self):
- '''Receive a packet from a GDB client'''
- csum = 0
- state = 'Finding SOP'
- packet = ''
- try:
- while True:
- c = self.netin.read(1)
- if c == '\x03':
- return 'Error: CTRL+C'
+ # follow gdbserver debug output format
+ self.log.debug(f'getpkt ("{GdbSerialConn.__printable_prefix(data).decode(ENCODING)}");')
- if len(c) != 1:
- return 'Error: EOF'
+ data = GdbSerialConn.rle_decode(data)
+ data = GdbSerialConn.unescape(data)
- if state == 'Finding SOP':
- if c == '$':
- state = 'Finding EOP'
- elif state == 'Finding EOP':
- if c == '#':
- if csum != int(self.netin.read(2), 16):
- raise Exception('invalid checksum')
- self.last_pkt = packet
- return 'Good'
- else:
- packet += c
- csum = (csum + ord(c)) & 0xff
- else:
- raise Exception('should not be here')
- except:
- self.close()
- raise
+ del buffer[:packet.endpos]
+ yield data
- def checksum(self, data):
- checksum = 0
- for c in data:
- if type(c) == str:
- checksum += (ord(c))
- else:
- checksum += c
- return checksum & 0xff
+ def send(self, data: Reply, raw: bool = False) -> None:
+ """Send out a packet.
- def send(self, msg):
- """Send a packet to the GDB client"""
- if type(msg) == str:
- self.send_raw('$%s#%.2x' % (msg, self.checksum(msg)))
+ Args:
+ data : data to send out
+ raw : whether to encapsulate the data with standard header and
+ checksum or leave it raw
+ """
+
+ if type(data) is str:
+ data = data.encode(ENCODING)
+
+ assert type(data) is bytes
+
+ if raw:
+ packet = data
else:
- self.clientsocket.send(b'$%s#%.2x' % (msg, self.checksum(msg)))
- self.netout.flush()
+ data = GdbSerialConn.escape(data)
+ data = GdbSerialConn.rle_encode(data)
- self.ql.log.debug("gdb> send: $%s#%.2x" % (msg, self.checksum(msg)))
+ packet = b'$' + data + b'#' + f'{GdbSerialConn.checksum(data):02x}'.encode()
- def send_raw(self, r):
- self.netout.write(r)
- self.netout.flush()
+ # follow gdbserver debug output format
+ self.log.debug(f'putpkt ("{GdbSerialConn.__printable_prefix(data).decode(ENCODING)}");')
+
+ self.client.sendall(packet)
+
+ @staticmethod
+ def __printable_prefix(data: bytes) -> bytes:
+ """Follow the gnu gdbserver debug message format which emits only the
+ printable prefix of a packet (either incoming or outgoing). Note that
+ despite of its name, it includes non-printable characters as well.
+
+ Args:
+ data : packet data to scan
+
+ Returns: a prefix of the specified data buffer
+ """
+
+ def __isascii(ch: int) -> bool:
+ return 0 < ch < 0x80
+
+ if data.isascii():
+ return data
+
+ return data[:next((i for i, ch in enumerate(data) if not __isascii(ch)), len(data))]
+
+ @staticmethod
+ def escape(data: bytes) -> bytes:
+ """Escape data according to gdb protocol escaping rules.
+ """
+
+ def __repl(m: 're.Match[bytes]') -> bytes:
+ ch, *_ = m[0]
+
+ return bytes([ord('}'), ch ^ 0x20])
+
+ return re.sub(br'[*#$}]', __repl, data, flags=re.DOTALL)
+
+ @staticmethod
+ def unescape(data: bytes) -> bytes:
+ """Unescape data according to gdb protocol escaping rules.
+ """
+
+ def __repl(m: 're.Match[bytes]') -> bytes:
+ _, ch = m[0]
+
+ return bytes([ch ^ 0x20])
+
+ return re.sub(br'}.', __repl, data, flags=re.DOTALL)
+
+ @staticmethod
+ def rle_encode(data: bytes) -> bytes:
+ """Compact data using run-length encoding.
+ """
+
+ def __simple_rep(b: bytes, times: int) -> bytes:
+ return b * times
+
+ def __runlen_rep(b: bytes, times: int) -> bytes:
+ return b + b'*' + bytes([times - 1 + 29])
+
+ def __encode_rep(b: bytes, times: int) -> bytes:
+ assert times > 0, 'time should be a positive value'
+
+ if 0 < times < 4:
+ return __simple_rep(b, times)
+
+ elif times == 6+1 or times == 7+1:
+ return __runlen_rep(b, 6) + __encode_rep(b, times - 6)
+
+ else:
+ return __runlen_rep(b, times)
+
+ def __repl(m: 're.Match[bytes]') -> bytes:
+ repetition = m[0]
+
+ ch = repetition[0:1]
+ times = len(repetition)
+
+ return __encode_rep(ch, times)
+
+ return re.sub(br'(.)\1{3,96}', __repl, data, flags=re.DOTALL)
+
+ @staticmethod
+ def rle_decode(data: bytes) -> bytes:
+ """Expand run-length encoded data.
+ """
+
+ def __repl(m: 're.Match[bytes]') -> bytes:
+ ch, _, times = m[0]
+
+ return bytes([ch] * (1 + times - 29))
+
+ return re.sub(br'.\*.', __repl, data, flags=re.DOTALL)
+
+ @staticmethod
+ def checksum(data: bytes) -> int:
+ return sum(data) & 0xff
diff --git a/qiling/debugger/gdb/utils.py b/qiling/debugger/gdb/utils.py
index 4c8a5247..30bba47e 100644
--- a/qiling/debugger/gdb/utils.py
+++ b/qiling/debugger/gdb/utils.py
@@ -3,117 +3,76 @@
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#
+from typing import Optional
+
from qiling import Qiling
from qiling.const import QL_ARCH
+# this code is partially based on uDbg
+# @see: https://github.com/iGio90/uDdbg
+
PROMPT = r'gdb>'
class QlGdbUtils:
- def __init__(self):
- self.ql: Qiling
-
- self.current_address = 0x0
- self.current_address_size = 0x0
- self.last_bp = 0x0
- self.entry_point = None
- self.exit_point = None
- self.soft_bp = False
- self.has_soft_bp = False
- self.bp_list = []
- # self.mapping = []
- self.breakpoint_count = 0x0
- self.skip_bp_count = 0x0
-
-
- def initialize(self, ql: Qiling, hook_address: int, exit_point: int, mappings=[]):
+ def __init__(self, ql: Qiling, entry_point: int, exit_point: int):
self.ql = ql
- if ql.baremetal:
- self.current_address = self.entry_point
- else:
- self.current_address = self.entry_point = ql.os.entry_point
-
self.exit_point = exit_point
- # self.mapping = mappings
+ self.bp_list = []
+ self.last_bp = None
def __entry_point_hook(ql: Qiling):
ql.hook_del(ep_hret)
ql.hook_code(self.dbg_hook)
+
+ ql.log.info(f'{PROMPT} stopped at entry point: {ql.arch.regs.arch_pc:#x}')
ql.stop()
- ql.log.info(f'{PROMPT} Stop at entry point: {ql.arch.regs.arch_pc:#x}')
-
- ep_hret = ql.hook_address(__entry_point_hook, hook_address)
+ # set a one-time hook to be dispatched upon reaching program entry point.
+ # that hook will be used to set up the breakpoint handling hook
+ ep_hret = ql.hook_address(__entry_point_hook, entry_point)
def dbg_hook(self, ql: Qiling, address: int, size: int):
- """Modified this function for qiling.gdbserver by kabeor from https://github.com/iGio90/uDdbg
- """
+ if ql.arch.type == QL_ARCH.ARM and ql.arch.is_thumb:
+ address += 1
- try:
- if ql.arch.type == QL_ARCH.ARM:
- if ql.arch.is_thumb:
- address += 1
+ # resuming emulation after hitting a breakpoint will re-enter this hook.
+ # avoid an endless hooking loop by detecting and skipping this case
+ if address == self.last_bp:
+ self.last_bp = None
- # self.mapping.append([(hex(address))])
- self.current_address = address
- hit_soft_bp = False
+ elif address in self.bp_list:
+ self.last_bp = address
- if self.soft_bp == True:
- self.soft_bp = False
- hit_soft_bp = True
-
- # Breakpoints are always added without the LSB, even in Thumb, so they should be checked like this as well
- if ((address & ~1) in self.bp_list and (address & ~1) != self.last_bp) or self.has_soft_bp == True:
- if self.skip_bp_count > 0:
- self.skip_bp_count -= 1
- else:
- self.breakpoint_count += 1
- ql.stop()
- self.last_bp = address
- ql.log.info(f'{PROMPT} Breakpoint found, stop at address: {address:#x}')
-
- elif address == self.last_bp:
- self.last_bp = 0x0
-
- self.has_soft_bp = hit_soft_bp
-
- if self.current_address + size == self.exit_point:
- ql.log.debug(f'{PROMPT} emulation entrypoint at {self.entry_point:#x}')
- ql.log.debug(f'{PROMPT} emulation exitpoint at {self.exit_point:#x}')
-
- except KeyboardInterrupt:
- ql.log.info(f'{PROMPT} Paused at {address:#x}, instruction size = {size:d}')
+ ql.log.info(f'{PROMPT} breakpoint hit, stopped at {address:#x}')
ql.stop()
- except:
- raise
+ # # TODO: not sure what this is about
+ # if address + size == self.exit_point:
+ # ql.log.debug(f'{PROMPT} emulation entrypoint at {self.entry_point:#x}')
+ # ql.log.debug(f'{PROMPT} emulation exitpoint at {self.exit_point:#x}')
def bp_insert(self, addr: int):
if addr not in self.bp_list:
self.bp_list.append(addr)
- self.ql.log.info(f'{PROMPT} Breakpoint added at: {addr:#x}')
+ self.ql.log.info(f'{PROMPT} breakpoint added at {addr:#x}')
- def bp_remove(self, addr: int, type = None, len = None):
+ def bp_remove(self, addr: int):
self.bp_list.remove(addr)
- self.ql.log.info(f'{PROMPT} Breakpoint removed at: {addr:#x}')
+ self.ql.log.info(f'{PROMPT} breakpoint removed from {addr:#x}')
- def resume_emu(self, address: int = None, skip_bp: int = 0):
- """Modified this function for qiling.gdbserver by kabeor from https://github.com/iGio90/uDdbg
- """
+ def resume_emu(self, address: Optional[int] = None, steps: int = 0):
+ if address is None:
+ address = self.ql.arch.regs.arch_pc
- if address is not None:
- if self.ql.arch.type == QL_ARCH.ARM:
- if self.ql.arch.is_thumb:
- address += 1
+ if self.ql.arch.type == QL_ARCH.ARM and self.ql.arch.is_thumb:
+ address += 1
- self.current_address = address
+ op = f'stepping {steps} instructions' if steps else 'resuming'
+ self.ql.log.info(f'{PROMPT} {op} from {address:#x}')
- self.skip_bp_count = skip_bp
-
- if self.exit_point is not None:
- self.ql.log.info(f'{PROMPT} Resume at: {self.current_address:#x}')
- self.ql.emu_start(self.current_address, self.exit_point)
+ self.ql.emu_start(address, self.exit_point, count=steps)
diff --git a/qiling/debugger/gdb/xml/a8086/target.xml b/qiling/debugger/gdb/xml/a8086/target.xml
index 71daae8c..43bc64d7 100644
--- a/qiling/debugger/gdb/xml/a8086/target.xml
+++ b/qiling/debugger/gdb/xml/a8086/target.xml
@@ -1 +1,6 @@
-i8086
+
+
+
+ i8086
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/arm/arm-core.xml b/qiling/debugger/gdb/xml/arm/arm-core.xml
index a2c0a65b..5032c503 100644
--- a/qiling/debugger/gdb/xml/arm/arm-core.xml
+++ b/qiling/debugger/gdb/xml/arm/arm-core.xml
@@ -1,31 +1,31 @@
-
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/arm/arm-m-profile-with-fpa.xml b/qiling/debugger/gdb/xml/arm/arm-m-profile-with-fpa.xml
deleted file mode 100644
index dd30abe8..00000000
--- a/qiling/debugger/gdb/xml/arm/arm-m-profile-with-fpa.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/qiling/debugger/gdb/xml/arm/arm-m-profile.xml b/qiling/debugger/gdb/xml/arm/arm-m-profile.xml
index 5319d764..f0584a20 100644
--- a/qiling/debugger/gdb/xml/arm/arm-m-profile.xml
+++ b/qiling/debugger/gdb/xml/arm/arm-m-profile.xml
@@ -7,7 +7,7 @@
-
+
@@ -23,5 +23,6 @@
+
diff --git a/qiling/debugger/gdb/xml/arm/target.xml b/qiling/debugger/gdb/xml/arm/target.xml
index 579e84b0..89826d47 100644
--- a/qiling/debugger/gdb/xml/arm/target.xml
+++ b/qiling/debugger/gdb/xml/arm/target.xml
@@ -6,9 +6,9 @@
*!notice and this notice are preserved. -->
-
- arm
-
-
-
-
+
+ arm
+
+
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/arm64/aarch64-core.xml b/qiling/debugger/gdb/xml/arm64/aarch64-core.xml
index 5b2706e0..599d92b3 100644
--- a/qiling/debugger/gdb/xml/arm64/aarch64-core.xml
+++ b/qiling/debugger/gdb/xml/arm64/aarch64-core.xml
@@ -1,67 +1,67 @@
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
- *
- *
- *
- *
- *
- *
- *
- *
- *
+
+
+
+
+
+
+
+
+
+
- *
- *
+
+
- *
- *
- *
- *
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/arm64/aarch64-fpu.xml b/qiling/debugger/gdb/xml/arm64/aarch64-fpu.xml
index 0b37e15f..0cdf73e5 100644
--- a/qiling/debugger/gdb/xml/arm64/aarch64-fpu.xml
+++ b/qiling/debugger/gdb/xml/arm64/aarch64-fpu.xml
@@ -1,86 +1,93 @@
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
-
-
-
-
-
-
-
-
-
-
-
-
-
- *
- *
- *
-
-
- *
- *
- *
-
-
- *
- *
-
-
- *
- *
-
-
- *
- *
-
-
- *
- *
- *
- *
- *
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/arm64/target.xml b/qiling/debugger/gdb/xml/arm64/target.xml
index d4dbac66..c741efa6 100644
--- a/qiling/debugger/gdb/xml/arm64/target.xml
+++ b/qiling/debugger/gdb/xml/arm64/target.xml
@@ -1,14 +1,15 @@
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
-
- aarch64
-
-
+
+ aarch64
+
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/mips/target.xml b/qiling/debugger/gdb/xml/mips/target.xml
index a585dffd..0a6a1b62 100644
--- a/qiling/debugger/gdb/xml/mips/target.xml
+++ b/qiling/debugger/gdb/xml/mips/target.xml
@@ -6,14 +6,15 @@
*!notice and this notice are preserved. -->
-
- mips
- GNU/Linux
-
-
-
+
+ mips
+ GNU/Linux
-
- *
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/x86/32bit-core.xml b/qiling/debugger/gdb/xml/x86/32bit-core.xml
index 0958032a..702ae3b0 100644
--- a/qiling/debugger/gdb/xml/x86/32bit-core.xml
+++ b/qiling/debugger/gdb/xml/x86/32bit-core.xml
@@ -7,59 +7,59 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/x86/32bit-mpx.xml b/qiling/debugger/gdb/xml/x86/32bit-mpx.xml
index 7772954d..1798dbd8 100644
--- a/qiling/debugger/gdb/xml/x86/32bit-mpx.xml
+++ b/qiling/debugger/gdb/xml/x86/32bit-mpx.xml
@@ -7,39 +7,41 @@
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/x86/32bit-pkeys.xml b/qiling/debugger/gdb/xml/x86/32bit-pkeys.xml
index 6f3c65a8..71aa7dc1 100644
--- a/qiling/debugger/gdb/xml/x86/32bit-pkeys.xml
+++ b/qiling/debugger/gdb/xml/x86/32bit-pkeys.xml
@@ -7,7 +7,5 @@
-
-
-
-
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/x86/32bit-sse.xml b/qiling/debugger/gdb/xml/x86/32bit-sse.xml
index c57a2d84..e28536e5 100644
--- a/qiling/debugger/gdb/xml/x86/32bit-sse.xml
+++ b/qiling/debugger/gdb/xml/x86/32bit-sse.xml
@@ -7,46 +7,48 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/x86/target.xml b/qiling/debugger/gdb/xml/x86/target.xml
index a664320d..50270323 100644
--- a/qiling/debugger/gdb/xml/x86/target.xml
+++ b/qiling/debugger/gdb/xml/x86/target.xml
@@ -1,11 +1,11 @@
-i386
- GNU/Linux
-
-
-
-
-
-
-
+
+i386
+ GNU/Linux
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xml/x8664/target.xml b/qiling/debugger/gdb/xml/x8664/target.xml
index d58e543e..d68705f6 100644
--- a/qiling/debugger/gdb/xml/x8664/target.xml
+++ b/qiling/debugger/gdb/xml/x8664/target.xml
@@ -1 +1,13 @@
-i386:x86-64GNU/Linux
+
+
+
+ i386:x86-64
+ GNU/Linux
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qiling/debugger/gdb/xmlregs.py b/qiling/debugger/gdb/xmlregs.py
new file mode 100644
index 00000000..f872ee0f
--- /dev/null
+++ b/qiling/debugger/gdb/xmlregs.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+#
+# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
+#
+
+from typing import Iterator, Mapping, Optional, Sequence, Tuple
+from pathlib import PurePath
+
+from qiling.arch.arm_const import reg_map as arm_regs
+from qiling.arch.arm_const import reg_vfp as arm_regs_vfp
+from qiling.arch.arm64_const import reg_map as arm64_regs
+from qiling.arch.arm64_const import reg_map_v as arm64_regs_v
+from qiling.arch.mips_const import reg_map as mips_regs_gpr
+from qiling.arch.mips_const import reg_map_fpu as mips_regs_fpu
+from qiling.arch.x86_const import reg_map_16 as x86_regs_16
+from qiling.arch.x86_const import reg_map_32 as x86_regs_32
+from qiling.arch.x86_const import reg_map_64 as x86_regs_64
+from qiling.arch.x86_const import reg_map_misc as x86_regs_misc
+from qiling.arch.x86_const import reg_map_cr as x86_regs_cr
+from qiling.arch.x86_const import reg_map_st as x86_regs_st
+from qiling.arch.x86_const import reg_map_xmm as x86_regs_xmm
+from qiling.arch.x86_const import reg_map_ymm as x86_regs_ymm
+
+from qiling.const import QL_ARCH
+
+RegEntry = Tuple[Optional[int], int, int]
+
+# define a local dummy function to let us reference this module
+__anchor__ = lambda x: x
+
+def __get_xml_path(archtype: QL_ARCH) -> Tuple[str, PurePath]:
+ import inspect
+
+ p = PurePath(inspect.getfile(__anchor__))
+ basedir = p.parent / 'xml' / archtype.name.lower()
+ filename = basedir / 'target.xml'
+
+ return str(filename), basedir
+
+def __walk_xml_regs(filename: str, base_url: PurePath) -> Iterator[Tuple[int, str, int]]:
+ from xml.etree import ElementTree, ElementInclude
+
+ tree = ElementTree.parse(filename)
+ root = tree.getroot()
+
+ # NOTE: this is needed to load xinclude hrefs relative to the main xml file. starting
+ # from python 3.9 ElementInclude.include has an argument for that called 'base_url'.
+ # this is a workaround for earlier python versions such as 3.8
+
+ def my_loader(base: PurePath):
+ def __wrapped(href: str, parse, encoding=None):
+ abshref = base / href
+
+ return ElementInclude.default_loader(str(abshref), parse, encoding)
+
+ return __wrapped
+
+ ElementInclude.include(root, loader=my_loader(base_url))
+
+ regnum = -1
+
+ for reg in root.iter('reg'):
+ # if regnum is not specified, assume it follows the previous one
+ regnum = int(reg.get('regnum', regnum + 1))
+
+ name = reg.attrib['name']
+ bitsize = reg.attrib['bitsize']
+
+ yield regnum, name, int(bitsize)
+
+def load_regsmap(archtype: QL_ARCH) -> Sequence[RegEntry]:
+ """Initialize registers map using available target XML files.
+
+ Args:
+ archtype: target architecture type
+
+ Returns: a list representing registers data
+ """
+
+ # retreive the relevant set of registers; their order of appearance is not
+ # important as it is determined by the info read from the xml files
+ ucregs: Mapping[str, int] = {
+ QL_ARCH.A8086 : dict(**x86_regs_32, **x86_regs_misc, **x86_regs_cr, **x86_regs_st),
+ QL_ARCH.X86 : dict(**x86_regs_32, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm),
+ QL_ARCH.X8664 : dict(**x86_regs_64, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm, **x86_regs_ymm),
+ QL_ARCH.ARM : dict(**arm_regs, **arm_regs_vfp),
+ QL_ARCH.CORTEX_M : arm_regs,
+ QL_ARCH.ARM64 : dict(**arm64_regs, **arm64_regs_v),
+ QL_ARCH.MIPS : dict(**mips_regs_gpr, **mips_regs_fpu)
+ }[archtype]
+
+ xmlpath = __get_xml_path(archtype)
+ regsinfo = sorted(__walk_xml_regs(*xmlpath))
+
+ # pre-allocate regmap and occupy it with null entries
+ last_regnum = regsinfo[-1][0]
+ regmap: Sequence[RegEntry] = [(None, 0, 0)] * (last_regnum + 1)
+
+ pos = 0
+
+ for regnum, name, bitsize in sorted(regsinfo):
+ # reg value size in nibbles
+ nibbles = bitsize // 4
+
+ regmap[regnum] = (ucregs.get(name), pos, nibbles)
+
+ # value position of next reg
+ pos += nibbles
+
+ return regmap
+
+__all__ = ['RegEntry', 'load_regsmap']
diff --git a/qiling/debugger/qdb/arch/arch_x86.py b/qiling/debugger/qdb/arch/arch_x86.py
index 4aae910c..10617cbd 100644
--- a/qiling/debugger/qdb/arch/arch_x86.py
+++ b/qiling/debugger/qdb/arch/arch_x86.py
@@ -21,7 +21,7 @@ class ArchX86(Arch):
"eax", "ebx", "ecx", "edx",
"esp", "ebp", "esi", "edi",
"eip", "ss", "cs", "ds", "es",
- "fs", "gs", "ef",
+ "fs", "gs", "eflags",
)
def read_insn(self, address: int) -> bytes:
@@ -34,7 +34,7 @@ class ArchX86(Arch):
@staticmethod
def get_flags(bits: int) -> Mapping[str, bool]:
"""
- get flags from ql.reg.ef
+ get flags from ql.reg.eflags
"""
return {
diff --git a/qiling/debugger/qdb/branch_predictor/branch_predictor_x86.py b/qiling/debugger/qdb/branch_predictor/branch_predictor_x86.py
index ce92dd9f..656c64da 100644
--- a/qiling/debugger/qdb/branch_predictor/branch_predictor_x86.py
+++ b/qiling/debugger/qdb/branch_predictor/branch_predictor_x86.py
@@ -91,7 +91,7 @@ class BranchPredictorX86(BranchPredictor, ArchX86):
}
if line.mnemonic in jump_table:
- eflags = self.get_flags(self.ql.arch.regs.ef).values()
+ eflags = self.get_flags(self.ql.arch.regs.eflags).values()
prophecy.going = jump_table.get(line.mnemonic)(*eflags)
elif line.mnemonic in jump_reg_table:
diff --git a/qiling/debugger/qdb/frontend.py b/qiling/debugger/qdb/frontend.py
index d1f53f86..ed243446 100644
--- a/qiling/debugger/qdb/frontend.py
+++ b/qiling/debugger/qdb/frontend.py
@@ -389,7 +389,7 @@ class CtxManager_X86(CtxManager):
"eax", "ebx", "ecx", "edx",
"esp", "ebp", "esi", "edi",
"eip", "ss", "cs", "ds", "es",
- "fs", "gs", "ef",
+ "fs", "gs", "eflags",
)
@context_printer("[ REGISTERS ]")
def context_reg(self, saved_reg_dump):
@@ -416,7 +416,7 @@ class CtxManager_X86(CtxManager):
lines += line
print(lines.format(*cur_regs.values()))
- print(color.GREEN, "EFLAGS: [CF: {flags[CF]}, PF: {flags[PF]}, AF: {flags[AF]}, ZF: {flags[ZF]}, SF: {flags[SF]}, OF: {flags[OF]}]".format(flags=get_x86_eflags(self.ql.arch.regs.ef)), color.END, sep="")
+ print(color.GREEN, "EFLAGS: [CF: {flags[CF]}, PF: {flags[PF]}, AF: {flags[AF]}, ZF: {flags[ZF]}, SF: {flags[SF]}, OF: {flags[OF]}]".format(flags=get_x86_eflags(self.ql.arch.regs.eflags)), color.END, sep="")
@context_printer("[ DISASM ]", footer=True)
def context_asm(self):
diff --git a/qiling/debugger/qdb/render/render_x86.py b/qiling/debugger/qdb/render/render_x86.py
index 3597181e..5c43d0e5 100644
--- a/qiling/debugger/qdb/render/render_x86.py
+++ b/qiling/debugger/qdb/render/render_x86.py
@@ -22,7 +22,7 @@ class ContextRenderX86(ContextRender, ArchX86):
cur_regs = self.dump_regs()
diff_reg = self.reg_diff(cur_regs, saved_reg_dump)
self.render_regs_dump(cur_regs, diff_reg=diff_reg)
- print(color.GREEN, "EFLAGS: [CF: {flags[CF]}, PF: {flags[PF]}, AF: {flags[AF]}, ZF: {flags[ZF]}, SF: {flags[SF]}, OF: {flags[OF]}]".format(flags=self.get_flags(self.ql.arch.regs.ef)), color.END, sep="")
+ print(color.GREEN, "EFLAGS: [CF: {flags[CF]}, PF: {flags[PF]}, AF: {flags[AF]}, ZF: {flags[ZF]}, SF: {flags[SF]}, OF: {flags[OF]}]".format(flags=self.get_flags(self.ql.arch.regs.eflags)), color.END, sep="")
@Render.divider_printer("[ DISASM ]")
def context_asm(self):
diff --git a/qiling/extensions/report/report.py b/qiling/extensions/report/report.py
index ea46aaa6..1189e698 100644
--- a/qiling/extensions/report/report.py
+++ b/qiling/extensions/report/report.py
@@ -12,8 +12,8 @@ class Report:
def __init__(self, ql):
self.filename = ql.argv
self.rootfs = ql.rootfs
- self.arch = list(arch_map.keys())[list(arch_map.values()).index(ql.arch.type)]
- self.os = list(os_map.keys())[list(os_map.values()).index(ql.os.type)]
+ self.arch = ql.arch.type.name
+ self.os = ql.os.type.name
self.env = ql.env
self.strings = set()
for string in ql.os.stats.strings:
diff --git a/qiling/loader/elf.py b/qiling/loader/elf.py
index c6ba9573..a1be0ef6 100644
--- a/qiling/loader/elf.py
+++ b/qiling/loader/elf.py
@@ -29,7 +29,7 @@ from qiling.os.linux.kernel_api.kernel_api import hook_sys_open, hook_sys_read,
# auxiliary vector types
# see: https://man7.org/linux/man-pages/man3/getauxval.3.html
-class AUX(IntEnum):
+class AUXV(IntEnum):
AT_NULL = 0
AT_IGNORE = 1
AT_EXECFD = 2
@@ -317,36 +317,39 @@ class QlLoaderELF(QlLoader):
elf_hwcap = 0xd7b81f
# setup aux vector
- aux_entries = (
- (AUX.AT_PHDR, elf_phdr),
- (AUX.AT_PHENT, elf_phent),
- (AUX.AT_PHNUM, elf_phnum),
- (AUX.AT_PAGESZ, self.ql.mem.pagesize),
- (AUX.AT_BASE, interp_address),
- (AUX.AT_FLAGS, 0),
- (AUX.AT_ENTRY, self.elf_entry),
- (AUX.AT_UID, self.ql.os.uid),
- (AUX.AT_EUID, self.ql.os.euid),
- (AUX.AT_GID, self.ql.os.gid),
- (AUX.AT_EGID, self.ql.os.egid),
- (AUX.AT_HWCAP, elf_hwcap),
- (AUX.AT_CLKTCK, 100),
- (AUX.AT_RANDOM, randstraddr),
- (AUX.AT_HWCAP2, 0),
- (AUX.AT_EXECFN, execfn),
- (AUX.AT_PLATFORM, cpustraddr),
- (AUX.AT_SECURE, 0),
- (AUX.AT_NULL, 0)
+ auxv_entries = (
+ (AUXV.AT_HWCAP, elf_hwcap),
+ (AUXV.AT_PAGESZ, self.ql.mem.pagesize),
+ (AUXV.AT_CLKTCK, 100),
+ (AUXV.AT_PHDR, elf_phdr),
+ (AUXV.AT_PHENT, elf_phent),
+ (AUXV.AT_PHNUM, elf_phnum),
+ (AUXV.AT_BASE, interp_address),
+ (AUXV.AT_FLAGS, 0),
+ (AUXV.AT_ENTRY, self.elf_entry),
+ (AUXV.AT_UID, self.ql.os.uid),
+ (AUXV.AT_EUID, self.ql.os.euid),
+ (AUXV.AT_GID, self.ql.os.gid),
+ (AUXV.AT_EGID, self.ql.os.egid),
+ (AUXV.AT_SECURE, 0),
+ (AUXV.AT_RANDOM, randstraddr),
+ (AUXV.AT_HWCAP2, 0),
+ (AUXV.AT_EXECFN, execfn),
+ (AUXV.AT_PLATFORM, cpustraddr),
+ (AUXV.AT_NULL, 0)
)
- # add all aux entries
- for key, val in aux_entries:
- elf_table.extend(self.ql.pack(key) + self.ql.pack(val))
+ bytes_before_auxv = len(elf_table)
+
+ # add all auxv entries
+ for key, val in auxv_entries:
+ elf_table.extend(self.ql.pack(key))
+ elf_table.extend(self.ql.pack(val))
new_stack = self.ql.mem.align(new_stack - len(elf_table), 0x10)
self.ql.mem.write(new_stack, bytes(elf_table))
- self.aux_vec = dict(aux_entries)
+ self.auxv = new_stack + bytes_before_auxv
self.stack_address = new_stack
self.load_address = load_address
diff --git a/qiling/os/dos/dos.py b/qiling/os/dos/dos.py
index 6fb4d330..fb7f55c1 100644
--- a/qiling/os/dos/dos.py
+++ b/qiling/os/dos/dos.py
@@ -58,10 +58,10 @@ class QlOsDos(QlOs):
curses.endwin()
def set_flag_value(self, fl: Flags, val: int) -> None:
- self.ql.arch.regs.ef = self.ql.arch.regs.ef & (~fl) | (fl * val)
+ self.ql.arch.regs.eflags = self.ql.arch.regs.eflags & (~fl) | (fl * val)
def test_flags(self, fl):
- return self.ql.arch.regs.ef & fl == fl
+ return self.ql.arch.regs.eflags & fl == fl
def set_cf(self):
self.set_flag_value(Flags.CF, 0b1)
diff --git a/qiling/os/macos/utils.py b/qiling/os/macos/utils.py
index 351f0f0b..808fbe29 100644
--- a/qiling/os/macos/utils.py
+++ b/qiling/os/macos/utils.py
@@ -188,5 +188,5 @@ def page_align_end(addr, page_size):
def set_eflags_cf(ql, target_cf):
- ql.arch.regs.ef = ( ql.arch.regs.ef & 0xfffffffe ) | target_cf
- return ql.arch.regs.ef
+ ql.arch.regs.eflags = ( ql.arch.regs.eflags & 0xfffffffe ) | target_cf
+ return ql.arch.regs.eflags
diff --git a/qiling/os/memory.py b/qiling/os/memory.py
index 9526f90a..c8620259 100644
--- a/qiling/os/memory.py
+++ b/qiling/os/memory.py
@@ -4,12 +4,11 @@
#
import os, re
-from typing import Any, Callable, List, MutableSequence, Optional, Sequence, Tuple, Union
+from typing import Any, Callable, List, Mapping, MutableSequence, Optional, Sequence, Tuple, Union
from unicorn import UC_PROT_NONE, UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC, UC_PROT_ALL
from qiling import Qiling
-from qiling.const import *
from qiling.exception import *
# tuple: range start, range end, permissions mask, range label, is mmio?
diff --git a/qiling/os/posix/const_mapping.py b/qiling/os/posix/const_mapping.py
index 41036eb1..99fb31ca 100644
--- a/qiling/os/posix/const_mapping.py
+++ b/qiling/os/posix/const_mapping.py
@@ -3,11 +3,12 @@
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#
-from typing import MutableSequence
-from .const import *
+from typing import Mapping, MutableSequence
from qiling import Qiling
-from qiling.const import *
+from qiling.const import QL_ARCH, QL_OS
+
+from .const import *
def _invert_dict(d: Mapping) -> Mapping:
return { v:k for k, v in d.items()}
diff --git a/qiling/os/uefi/__init__.py b/qiling/os/uefi/__init__.py
index 5b8faeab..0e68ec3c 100644
--- a/qiling/os/uefi/__init__.py
+++ b/qiling/os/uefi/__init__.py
@@ -1,15 +1,15 @@
import csv
from typing import Mapping
-from os import path
+import inspect
+from pathlib import Path
def __init_guids_db() -> Mapping[str, str]:
"""Initialize GUIDs dictionary from a local database.
"""
- csv_path = path.dirname(path.abspath(__file__))
- csv_path = path.join(csv_path, 'guids.csv')
+ csv_path = Path(inspect.getfile(inspect.currentframe())).parent / 'guids.csv'
- with open(csv_path) as guids_file:
+ with csv_path.open('r') as guids_file:
guids_reader = csv.reader(guids_file)
return dict(tuple(entry) for entry in guids_reader)
diff --git a/qiling/utils.py b/qiling/utils.py
index 68607fe6..dc370305 100644
--- a/qiling/utils.py
+++ b/qiling/utils.py
@@ -9,7 +9,8 @@ thoughout the qiling framework
"""
from functools import partial
-import importlib, os
+from pathlib import Path
+import importlib, inspect, os
from configparser import ConfigParser
from types import ModuleType
@@ -415,8 +416,8 @@ def profile_setup(ostype: QL_OS, filename: Optional[str]):
config = {}
else:
- qiling_home = os.path.dirname(os.path.abspath(__file__))
- os_profile = os.path.join(qiling_home, 'profiles', f'{ostype.name.lower()}.ql')
+ qiling_home = Path(inspect.getfile(inspect.currentframe())).parent
+ os_profile = qiling_home / 'profiles' / f'{ostype.name.lower()}.ql'
profiles = [os_profile]
diff --git a/setup.py b/setup.py
index 5496da6c..3987cc25 100644
--- a/setup.py
+++ b/setup.py
@@ -84,7 +84,12 @@ setup(
packages=find_packages(),
scripts=['qltool'],
- include_package_data=True,
+ package_data={
+ 'qiling': ['profiles/*.ql'],
+ 'qiling.debugger.gdb': ['xml/*/*'],
+ 'qiling.os.uefi': ['guids.csv'],
+ 'qiling.arch.evm.analysis': ['signatures.json']
+ },
install_requires=requirements,
extras_require=extras,
)