-
-
Notifications
You must be signed in to change notification settings - Fork 345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GDB and exception handling improvements #1655
Conversation
Makefile changes: * Remove esp-gdbstub as third-party module * Remove all GDB stuff from `Makefile` - gdbstub is compiled into application, not framework * gdbstub can be used with release or debug builds. * Add support in all makefiles for assembly code (both .s and .S files) * Remove all COM port settings from `Makefile` - application code does all this now * Bring `Makefile-project.mk`inline with `Makefile-rboot.mk` (compiler warnings, etc.) HardwareSerial * Fix so that end() and systemDebugOutput() don't screw up initialisation of other serial port(s) * Put callback handling code into static methods - saves IRAM and simplifies code HardwareTimer * Make HardwareTimer mode selectable (maskable or NMI) user_main.cpp * Don't change serial port baud rates - do that in gdb_init() instead which is compiled into application system/crash_handler.c * Remove stack dumping code and all serial port access - moved into gdb_hooks.cpp system/SerialBuffer.h * Move non-trivial code into .cpp module * Add `getReadData()` and `skipRead()` methods for efficient block reading esp_systemapi.h * Remove uart prototypes - driver must be used instead * Ensure wdt functions are available uart.h, uart.cpp * Add UART2 and provide generic notification callback handling * Add UART_OPT_CALLBACK_RAW option * Save some IRAM by moving uart_get_uart, uart_set_callback, uart_peek_last_char, uart_rx_available and moving uart_detach into flash * Use inline functions in preference to macros * Default debug port should be undefined, not UART0 * Use bit manipulation macros to simplify/clarify code * Disable interrupts in `uart_tx_free()` and `uart_rx_available()` to ensure result is accurate gdbstub, exception handling and stack dumping * appspecific/gdb/ code is always compiled into application, contains system exception handler and stack dumper * gdb/ code is only compiled when ENABLE_GDB=1 * gdbstub revised for readability and checking * uart handling code in separate module (gdbuart.cpp) * Add build option to support both patched and unpatched GDB versions * Extend GDBSTUB_CTRLC_BREAK to prevent accidental breaking * Add gdb_enable() function * Include options for stack dumping, with defaults to provide consistent behaviour (i.e. OFF in release builds, ON in debug builds) * Add debugging code to stub which can be optionally enabled to see realtime behaviour * Implement register read/write (p & P) commands LiveDebug sample * Revise to highlight possible debugging issues with hardware timer, and illustrate other timer types which are 'debug safe' * Add serial read callback to demonstrate UART2 function
@riban-bw Mike is updating and improving the GDB debugging code. Can you test this PR and give us your feedback? |
I will try to review this week (whilst I am on a business trip to Inverness, Scotland - nice!). I have it running but need to remind myself how to use gdb and look at how Mike has implemented the sample. Hope to respond this week. |
Whilst testing I idly pasted a large file into the serial terminal. In normal build (without gdbstub) it went pop. Behaved a little better with gdbstub included. Investigation showed task queue getting flooded (there should only be 1 or 2 tasks on there at a time) and too many interrupts getting fired. uart * Make `uart_disable_interrupts()` and `uart_restore_interrupts()` public * Add `uart_get_status()` function * Don't invoke callback on receive FIFO full unless buffer is almost full, subject to minimum headroom * Revise interrupt handler to store status flags (thus capturing a BREAK condition), and simplify loops/reduce code size. gdbstub * Use global structure to share state between code modules, simplifies code gdbuart * Use separate task callback function to avoid flooding task queue, so `sendUserDataQueued` isn't cleared when `gdbstub_send_user_data()` called directly. HardwareSerial * Add `getStatus()` method and `SerialStatus` enumeration for application use * Rework interrupt callback handling to prevent a task being queued if the previous one hasn't been handled yet.
…tly, e.g. if a receive overrun occurs.
…t quite right. Need to respond to overflow interrupt. Update Basic_Serial sample to check and display status. RX Overflow test: Paste a large block of data into the serial terminal Serial BREAK test: On miniterm, hit Ctrl+T then Ctrl+B, and repeat.
The last commits include additions to the LiveDebug sample so it interacts with GDB during a debug session. If you like the way it's going, I could take a look at revising the serial receive handler to process input in a similar way, so the program works the same whether using a regular terminal or GDB. |
Yep, that will be best. |
I am trying to achieve something very simple but it still does not work for me. I am setting a software breakpoint for the
Then I am trying to run the code until the breakpoint
But that ends up shortly after that with segfault
Any idea why is that happening? |
@slaff I get the same! It's because of an optimisation to the |
* Remove `ets_wdt_disable()` and `ets_wdt_enable()` calls from `dumpExceptionInfo()`, using normal watchdog reset instead. The `ets_wdt_enable()` call prevents the debugging breakpoint from working. Tested at 9600 baud shows reliable operation. * When GDB is attached, temporarily override any previously output routine (for m_printf, etc.) and write directly to the GDB console. This ensures that a proper explanation of the exception (or system restart) is dispayed in the GDB console. * Add `GDBSTUB_BREAK_ON_RESTART` to allow proper handling of unexpected system restarts ('crashes') with GDB. The cause of the restart is shown in the console with an appropriate signal. * Do not show stack dumps when using GDB (the cause is always shown though) * Add 'hang' command to LiveDebug sample to test behaviour (under GDB and using terminal in both GDB/non-GDB builds). Works as expected.
…ather than directly inside uart ISR. If application does not respond then repeating Ctrl+C twice will force a break.
… delete` commands * Code in separate module * Revise `fileDelete()` functions to return error code from SPIFFS * Add `GDBSTUB_ENABLE_HOSTIO` option
…may be in future.
* Add `Sming/System` and `Sming/gdb` directories * Enable extraction of static members, so `static inline` code gets picked up * Create GDB group * Doxygen misbehaves with `__attribute__((packed))` so use `#pragma pack()` instead
…G` works with both Linux and MinGW
@slaff @riban-bw Thank you both for your patience. I've tested the latest changes on Windows/Linux and reasonably happy with its behaviour. I've checked it using the LiveDebug sample in all three modes (GDB, Terminal and non-GDB) and behaves as expected. For the I do have a further point about the behaviour of |
I've been thinking about this one, and definitely the most critical part of this PR are that it doesn't break anything - and hopefully improves behaviour - when GDB is not enabled. The main culprit would be the uart driver here, of course, along with |
…e `break`, otherwise it's just a no-op. * Appeared to work as debug prompt appears, but that's the initial startup breakpoint. Function gets called at elevated interrupt level so need to drop it below DEBUG to enable break instruction. Now get correct signal (SIGPWR) in GDB in response to a crash.
@mikee47 Is the PR ready for merging? |
@slaff Yes, all done. |
Thanks a lot! |
|
||
static void IRAM_ATTR doCtrlBreak() | ||
{ | ||
if(break_requests != 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One side-effect that I am experiencing in Eclipse, and probably other debuggers where you cannot send twice Ctrl-C, is that it looks like the debugging session has paused in the block below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One side-effect that I am experiencing in Eclipse, and probably other debuggers where you cannot send twice Ctrl-C, is that it looks like the debugging session has paused in the block below.
@slaff Sorry, I don't understand - is this something you'd like me to look at before 3.8.0?
Don't do anything related to this for now. Let me first try to get used to it myself and I will open a new issue if needed. |
@slaff You can find pre-built version of this at SysProgs. Download and run the executable installer, then copy the |
@slaff All the Arduino toolchains are listed here. Their current toolchains use the unpatched version of GDB. Aside from the size of the register sets, I've noticed that they sometimes produce different stack trace results. Not sure why though, and probably never will without details of the Espressif GDB patch, which I believe is closed source. |
@mikee47 I am still experiencing issues with the debugger. For example a very simple session like the one below ends up in flames
A shorter version of the commands above needed to reproduce the issue:
|
Makefile changes:
Makefile
- gdbstub is compiled into application, not frameworkMakefile
- application code does all this nowMakefile-project.mk
inline withMakefile-rboot.mk
(compiler warnings, etc.)HardwareSerial
getStatus()
method to report serial errorsHardwareTimer
user_main.cpp
system/crash_handler.c
system/SerialBuffer.h
getReadData()
andskipRead()
methods for efficient block readingesp_systemapi.h
uart.h, uart.cpp
uart_tx_free()
anduart_rx_available()
to ensure result is accurateuart_get_status()
to support reporting of errors and Rx BREAK conditionuart_set_break()
functiongdbstub, exception handling and stack dumping
LiveDebug sample
Basic_Serial sample