qilingframework / qiling

A True Instrumentable Binary Emulation Framework
https://qiling.io
GNU General Public License v2.0
5.11k stars 741 forks source link

GDB debugging STM32f1xx stops execution after interrupt #1276

Open pieter-42 opened 1 year ago

pieter-42 commented 1 year ago

_[ disclaimer: to get below code to work I copied the gdb target XML files of 'arm' to 'qiling/debugger/gdb/xml/cortex_m' and put back the 'setupremap' function in 'hw/hw.py' (STM32 uses aliased memory). The former might have something to do with this? ]

I'm using -dev of today (+/- 1hr ago) to do remote GDB debugging on an STM32f10x target. Attaching works, GDB stops at the entry point but then when I just let the firmware continue 'c', an interrupt 0x2 is caught and directly afterwards my script stops execution.

    ql = Qiling(["firmware.hex"], archtype="cortex_m", env=stm32f105,verbose=QL_VERBOSE.DEBUG)
    ql.hw.create('rcc')
    ql.hw.create('flash interface')
    ql.hw.create('exti')
    ql.hw.create('usart1')
    ql.hw.create('gpioa')
    ql.hw.create('afio')
    ql.hw.create('spi2')
    ql.hw.create('dma1').watch()
    ql.debugger = True
    ql.run()

I'd expect either GDB to intercept the interrupt OR it just being handled internally by the firmware as it does when running without the debugger (without 'ql.debugger = True' the firmware just runs normally).

However, the debugger appears to think the target exited as no exception is raised, and then throws an Exception due to the MCU not having an exit code:

[+]     Received interrupt: 0x2
Traceback (most recent call last):
...
  File "/home/user/.local/lib/python3.10/site-packages/qiling/core.py", line 586, in run
    debugger.run()
  File "/home/user/.local/lib/python3.10/site-packages/qiling/debugger/gdb/gdb.py", line 767, in run
    reply = handler(subcmd.decode(ENCODING))
  File "/home/user/.local/lib/python3.10/site-packages/qiling/debugger/gdb/gdb.py", line 655, in handle_v
    return handle_c('')
  File "/home/user/.local/lib/python3.10/site-packages/qiling/debugger/gdb/gdb.py", line 243, in handle_c
    reply = f'W{self.ql.os.exit_code:02x}'
AttributeError: 'QlOsMcu' object has no attribute 'exit_code'

I tried letting the handle_c method run 'self.gdb.resume_emu()' in a loop, but then the interrupt is just looping and the firmware gets stuck. Wasn't able to find the code responsible for dropping out of the emulator loop when an interrupt is raised in debug mode versus non-debug mode. In any case the interrupt shouldn't be interpreted as the target exiting. I'd prefer the interrupt handler is simply called within the firmware as normal without dropping to the debugger; I can always put a bp on the handler address if needed.

xwings commented 1 year ago

I did not really test the GDB for MCU, i will spend some time look into it. Will update here if i have any findings.

elicn commented 1 year ago

@pieter-42, I recently fixed some stuff around gdb mishandling thumb code. Can you fetch the latest dev version and re-try?

pieter-42 commented 1 year ago

Thanks elicn and apologies for the long delay. I was on a long holiday and only now could test anything. Today's dev version didn't result in different behavior unfortunately:

[+]     Received interrupt: 0x2
Traceback (most recent call last):
...
  File "/home/user/.local/lib/python3.10/site-packages/qiling/core.py", line 586, in run
    debugger.run()
  File "/home/user/.local/lib/python3.10/site-packages/qiling/debugger/gdb/gdb.py", line 763, in run
    reply = handler(subcmd.decode(ENCODING))
  File "/home/user/.local/lib/python3.10/site-packages/qiling/debugger/gdb/gdb.py", line 659, in handle_v
    return handle_c('')
  File "/home/user/.local/lib/python3.10/site-packages/qiling/debugger/gdb/gdb.py", line 247, in handle_c
    reply = f'W{self.ql.os.exit_code:02x}'
AttributeError: 'QlOsMcu' object has no attribute 'exit_code'

This happens after I continue from gdb after the entry point breakpoint and the firmware receives an interrupt (0x2 in this case). Without the debugger the firmware just continues running and doing a lot of stuff.

elicn commented 1 year ago

@pieter-42 Could you drop me a ZIP file with the binary and Qiling script you are using (as clean as possible from irrelevant additions)?

pieter-42 commented 1 year ago

I prepared such a ZIP file, but is there a way to share it privately to avoid publicizing the firmware?

elicn commented 1 year ago

Can you set up a repro with one of the samples we already have on rootfs ?