[ECOS] Redboot GDB Stub

Quanren Xiong xiongqr@gmail.com
Wed Mar 16 22:09:00 GMT 2011

Hi Narinder,

Thank you for sharing. That is exactly what I need at the moment.

I am working with an ARM9 processor and the GDB remote debugging works
somewhat on the platform. I can "tar rem" to download the binary to
the target, set break proints, and run the binary by "continue".  It
will break, but from there on, I can not issue any GDB command.  The
error I got depending on the way I connected to the target.  If I
connected  via the TCP port 9000, I got "connection reset by the peer"
error message.
If I connected via the serial port, GDB would stuck in an infinite
loop and CPU usage became very high.

I can I debug it? Can you share some of your experience?
I know the hardware exception handling on the target is not set up
correctly on the target. For instance, bad memory alignment will not
raise an exception.


On Fri, Mar 11, 2011 at 6:38 PM, Narinder Dhillon
<narinder_dhillon@yahoo.ca> wrote:
> Redboot GDB Stub
> ----------------
> Introduction
> ------------
> Recently I ported eCos to Freescale MPC837X processor and could not get GDB
> working. I had to
> debug the GDB stub in redboot and got to know how it works. This little note is
> my attempt at
> explaining how the stub works, in case anyone else has to debug it.
> This explanation is geared towards the Redboot GDB stub on a POwerPC CPU but is
> equally applicable
> to all other platforms. The GDB was used through serial port only.
> How to enable GDB in Redboot
> ----------------------------
> My Redboot's startup type is ROMRAM and the following configuration is set.
> The CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS option is enabled. It depends on the
> presence of the
> following lines in my platform cdl file:
>    implements    CYGINT_HAL_DEBUG_GDB_STUBS
> The CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT option is selected to enable the Ctrl-C
> option to get into
> gdb stub.
> The CYGDBG_HAL_DIAG_TO_DEBUG_CHAN option is selected and the mangler used is
> 'GDB'. This enables
> GDB to use serial port for communication.
> This means that your serial port has to be working before you can get GDB
> working.
> All the relevant files
> ----------------------
> The generic stub implementation is located in
> 'hal/common/current/' 'generic_stub.h/.c', 'hal_stub.h/.c', 'thread-packets.c',
> 'thread-pkts.h'
> and some other files in this area.
> The platform specific files, for PowerPC implementation are located in
> 'hal/powerpc/arch/current' 'ppc_stub.h/.c', hal_arch.h'
> Again, other platforms should have similar files.
> How does the GDB stub kick in
> -----------------------------
> Once you have Redboot running on your platform, and you can see the Redboot
> prompt on your serial
> debug port you are ready.
> Anything that is typed on Redboot prompt is processed in a while loop in
> 'redboot/current/src/main.c'
> file. When GDB stub is included in Redboot, this loop looks for '+' and '$'
> characters. When a GDB
> client tries to connect to the target using the 'target remote < >' command, it
> sends a GDB packet
> to the target. Since GDB packet starts with '$' character, the while loop
> detects it and generates
> a break instruction exception. This exception causes the interrupt handler to
> eventually call the
> 'cyg_hal_exception_handler'. This handler is defined in
> 'hal/powerpc/arch/current/src/hal_misc.c'
> file on PowerPC platforms, it should defined similarly for other platforms.
> 'cyg_hal_exception_handler' is called with a pointer to the stack that has all
> the registers saved
> by the interrupt handler (cyg_hal_default_exception_vsr). This pointer is saved
> in a pointer variable
> '_hal_registers' (more on this later). Then '__handle_exception' is called. This
> function is in
> 'hal/common/current/src/generic-stub.c', now we are in GDB.
> In order to get into GDB stub, all we needed was a 'target remote' command to be
> issued. This command
> will now get processed.
> Handling Exception
> ------------------
> One of the first things that are done in '__handle_exception', is to save the
> registers that are on the
> stack (pointed to by _hal_registers) to the internal GDB array (_registers).
> This is done in
> 'handle_exception_cleanup' coded in hal_stub.c file.
> The next step is to find the what kind of signal was received. Since we just got
> into this function
> because of 'target remote' command, the Redboot has already indicated to the
> stub that there was a
> break received (either Ctrl-C or the first GDB packet in this case). Hence the
> signal is SIGINT. If
> we did not get here because of a break, then the signal value is determined by
> calling function
> '__computeSignal(__get_trap_number())'. The '__get_trap_number()' function
> returns the vector number.
> If the signal is a non-zero value, the exception further processes by calling
> 'process_exception'.
> Process Exception
> -----------------
> In this function we sit in a loop and keep reading the packets from serial port
> and processing them.
> The only way we get out of this loop is by 'continuing' with the application
> that we are debugging,
> single stepping, detaching, killing, or file IO.
> Process Packet
> --------------
> Every packet received in the above loop is processed by '__process_packet'
> function. This is where
> all the GDB commands are processed.
> Let take the example of two commands that are used to run an application from
> GDB.
>>powerpc-eabi-gdb --symbols app.elf -b 38400 -nw
> gdb>tar rem /dev/ttySI166
> gdb>jump *0x100000
> The fist call starts the gdb with the elf file of the application supplying the
> symbols. The '-b'
> option sets the baud rate and '-nw' asks for no window.
> Once GDB starts, you are at 'gdb' prompt. Here, we first connect to the target
> with the 'target remote'
> command and the serial device port that the target debug port is connected to.
> Then we tell GDB to start executing application at address 0x100000.
> The 'tar rem' command gets us all the way to the 'process_exception' function
> where we read the packet
> containing the 'tar rem' command and then process it. The '__process_packet'
> functions processes it
> and sends an ack back. Then it reads the next packet. It does this a few times
> to get connected to
> the client program.
> Then in response to 'jump' command, the client program tells the stub to set the
> program counter to
> 0x100000. This is done in the GDB internal register array (_registers). As part
> of the 'jump', the
> client program tells the stub to 'continue' from 0x100000. The process packet
> function at this time
> does some processing and returns with -1 and causes the loop in
> 'process_exception' to break and
> return back to '__handle_exception' function.
> At this point, the handle exception function copies the GDB internal register
> array (with
> PC = 0x100000) and copies it to _hal_registers (which is pointing to stack,
> effectively changing the
> save PC value to 0x100000).
> When this whole thing unwinds, we get back to the interrupt handler that was
> processing the break
> instruction exception. This interrupt handler then restores the saved registers
> and when CPU
> processes the return from interrupt command, the CPU ends up with program
> counter at 0x100000.
> This is how the continue commands ends up with application running from inside
> GDB.
> Single Step
> -----------
> The single step is exactly same code flow as 'continue' above, except that at
> one point, the CPU is
> setup to execute one instructions at a time.
> This is the first cut of this tutorial, feel free to critique.
> Narinder Dhillon
> --
> Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
> and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

More information about the Ecos-discuss mailing list