summaryrefslogtreecommitdiffstats
path: root/doc/rgdb_specs/daemon.t
diff options
context:
space:
mode:
Diffstat (limited to 'doc/rgdb_specs/daemon.t')
-rw-r--r--doc/rgdb_specs/daemon.t420
1 files changed, 420 insertions, 0 deletions
diff --git a/doc/rgdb_specs/daemon.t b/doc/rgdb_specs/daemon.t
new file mode 100644
index 0000000000..fb505a8d07
--- /dev/null
+++ b/doc/rgdb_specs/daemon.t
@@ -0,0 +1,420 @@
+@c
+@c RTEMS Remote Debugger Server Specifications
+@c
+@c Written by: Eric Valette <valette@crf.canon.fr>
+@c Emmanuel Raguet <raguet@crf.canon.fr>
+@c
+@c
+@c $Id$
+@c
+
+@chapter RTEMS Debugger Server Daemon
+
+We will describe in this section how this debugger server will be
+implemented on RTEMS environment. Our initial target is based on Intel Pentium
+and we will use an Ethernet link to communicate between the host and the target.
+
+The RTEMS remote debugger will be composed by several tasks and exception
+handlers :
+
+@itemize @b
+@item an initialization task which opens the sockets and runs the SUN RPC
+server. This task will also connect the interrupt handlers and launch the communication
+task
+@item a communication task which receives the SUN RPC commands, executes
+them and sends the result to the GDB client,
+@item A debuggee event management task which waits for events. We need a different
+task than the command management task in order to be able to still accept commands
+while no event has yet occurred for the debuggee. An example could be a continue
+command from GDB and then hitting to DEL key to see what is currently going
+on on the target side because an expected breakpoint is not caught...
+@item a debug exception handler which manages the hardware breakpoint and
+single step exceptions (INT 1 on Intel x86),
+@item a breakpoint exception handler which manages the software breakpoints
+exceptions (INT 3 on Intel x86),
+@item a default exception handler used to catch every possible errors make on the
+target system,
+@end itemize
+
+@c XXX figure reference
+@c XXX references to other sections
+Figure @b{remote debugger tasks and handlers} represents these
+different tasks and handlers. The synchronization between the different task
+and exception handlers will be described below in the section
+@b{Synchronization Among Tasks and Exception Handlers}.
+Some open issues we have faced for a prototype implementation are described
+in the section @b{Open Issues}. The temporary workaround we chose are described
+in chapter @b{Workarounds for Open Issues in Prototype}.
+
+
+@subsection The INITIALIZATION task
+
+This is the task that must be executed at the boot phase of RTEMS.
+It initializes the debug context. It must :
+
+@itemize @b
+@item open the UDP sockets,
+@item run the SUN RPC server main loop,
+@item create the COMMAND MANAGEMENT task,
+@item connect the DEBUG EXCEPTION handler,
+@item connect the SOFTWARE BREAKPOINT handler,
+@item delete itself.
+@end itemize
+If an error occurs at any step of the execution, the connections established
+before the error will be closed, before the initialization task deletes itself.
+
+
+@subsection The COMMAND_MNGT task
+
+This task is in charge of receiving the SUN RPC messages and executing
+the associated commands. This task must have an important priority because it
+must be executed each time a command message comes from the debugger. It must
+be executed even if one or both exception handlers are executed. But the COMMAND
+MANAGEMENT task must not block the TCP/IP module without which no message can
+be received.
+
+When not executing a command, this task is waiting for a SUN RPC message
+on the primary port. This idle state blocks the task, so the other active tasks
+can run. Once a message comes from Ethernet via the primary port, the COMMAND
+MANAGEMENT task wakes up and receives the message which is a request from GDB.
+This request is sent to the SUN RPC server code which extracts the command and
+its arguments, executes it and, if needed, sends a result to GDB. After having
+performed these actions, the task sleeps, waiting for another message.
+
+A particular case is the reception of the ATTACH command : in this
+case the COMMAND_MNGT task creates the EVENT_MNGT task described below before
+going to wait on UDP socket again.
+
+
+@subsection The EVENT_MNGT task
+
+This task is in charge of managing events happening on the debuggee such as
+breakpoint, exceptions. This task does a basic simple loop waiting for event
+on a synchronization variable. It is waken up by exception handlers code. It
+then signals GDB that an event occurred and then go sleeping again as further
+requests will be processed by the COMMAND_MNGT task.
+
+
+@subsection The DEBUG EXCEPTION handler
+
+This handler is connected to the DEBUG exception (INT 1 on Intel ix86).
+This exception is entered when :
+
+@itemize @b
+@item executing a single-step instruction,
+@item hardware breakpoint condition is true,
+@end itemize
+These events will be treated by the debugger because they are the
+primary event used when debugging a software for instruction stepping. In both
+cases, the DEBUG EXCEPTION handler code is executed. Please note that the execution
+context of the exception handler is the supervisor stack of the task that generated
+the exception . This implies :
+
+@itemize @b
+@item We may sleep in this context,
+@item We have as many possible execution context for the DEBUG EXCEPTION handler as
+we need to,
+@item When we enter the high level exception handler code, a normalized exception
+context has been pushed on the system stack and a pointer to this context is
+available as the first argument (cf c/src/exec/score/cpu/i386/cpu.c for more
+details),
+@end itemize
+First the exception handler wakeup the EVENT_MNGT task. Then it will
+cause the faulting thread to sleep on a synchronization object. As soon as GDB
+receives the event notifying that the debuggee status has changed, it will start
+sending requests to get the debuggee status (registers set, faulty task id,
+...). These requests are handled by the COMMAND MANAGEMENT task. When this task
+receive a PTRACE_CONT command it will resume the execution of the task that
+caused the exception by doing a V on the synchronization object.
+
+
+@subsection The BREAKPOINT EXCEPTION handler
+
+This handler is connected to the BREAKPOINT exception (INT3 on Intel
+Ix86). Each time the debugger wants to place a software breakpoint in the debuggee,
+a debuggee opcode is temporarily replaced by an instruction causing BREAKPOINT
+exception (the ``INT 3'' instruction on Intel ix86). When ``INT 3'' is executed,
+the BREAKPOINT handler is executed. Otherwise, the exception processing is the
+same than the one described in previous section.
+
+
+@subsection Synchronization Among Tasks and Exception Handlers
+
+The previous chapters have presented a simplified and static view of the various
+tasks and exceptions handlers. This chapter is more focussed on synchronization
+requirements about the various pieces of code executed when RGDBSD is operating.
+
+
+@subsubsection Implicit Synchronization Using Task Priorities
+
+This chapter is relevant on Uniprocessor System (UP) only. However, it will
+also list the requirements for explicit synchronization on Multi-processor Systems
+(MP). Below are the task priorities sorted by high priority. They are not supposed
+to be equal :
+
+@enumerate
+@item Network Input Task. This is the highest priority task. This can be regarded
+as a software interrupt task for FreeBSD code,
+@item RGDBSD command task. As this task waits on UDP sockets, it shall not prevent
+the previous task from running. As the main debug entry point, it should preempt
+any other task in the system,
+@item RGDBSD event task. This task should preempt any task but the two mentionned
+before to signal a debug event to GDB. The command task shall be able to preempt
+this task for emergency command such as DEL, or REBOOT,
+@item Applications tasks (task we are able to debug),
+@end enumerate
+Using theses priorities eliminates the need for adding more synchronization
+objects in the next section. My belief is that symmetric MP support will require
+more important change in the RTEMS than RGDBSD itself like multiple scheduler
+queues, task to processor binding for non symmetric IO, use a different implementation
+for @emph{task_disable_preemption}, ...
+
+
+@subsubsection Explicit Synchronization
+
+This chapter will describe the synchronization variables that need to be implemented
+in order to sequence debug events in a way that is compatible with what GDB
+code expects. The root of the problem is that GDB code mainly expects that once
+a debug event has occurred on the debuggee, the entire debuggee is frozen and
+no other event will occur before the CONTINUE command is issued. This behavior
+is hard to achieve in our case as once we hit a breakpoint, only the task that
+hits the breakpoint will be asleep on a synchronization object. Other tasks
+may hit other breakpoints while we are waiting commands from GDB generating
+potential unexpected events. There is a solutions if RGDBSD itself use RTEMS
+threads to fix this problem by creating a task that loops forever at a priority
+superior to any debugged task but below RGDBSD task priorities. Unfortunately
+this will not work for the case we use the nano-kernel implementation and we
+think it is better to study synchronization problems now. We also expects that
+multi-thread debug support hardening in GDB will remove some event serializations
+requirements. Here is the list of synchronization variables we plan to use and
+their usage. They are all regular semaphores. They are not binary semaphores
+because the task that does V is not the task that has done the P.
+
+@itemize @b
+@item @emph{WakeUpEventTask} : used by exception handler code to wake up the EVENT_MNGT
+task by doing a V operation on this object. When target code is running normally
+the EVENT_MNGT task sleeps due to a P operation on this semaphore,
+@item @emph{SerializeDebugEvent} : used to serialize events in a way compatible to
+what GDB expects. Before doing a V operation on @emph{WakeUpEventTask,} the
+exception handler does a P on this semaphore to be sure processing of another
+exception is not in progress. Upon reception of a CONTINUE command, the COMMAND_MNGT
+task will issue a V operation so that the exception code can wake up EVENT_MNGT
+task using the mechanism described above,
+@item @emph{RestartFromException} : (in fact one semaphore per task) used by exception
+handling code to put a faulty task to sleep once it has generated an exception
+by doing a P operation on this semaphore. In the case the exception was generated
+due to a breakpoint, GDB command will modify back the BREAKPOINT opcode to the
+original value before doing the CONTINUE command. This command will perform
+a V on this semaphore. In the case it is a real non restartable exception (faulty
+memory reference via invalid pointer for example), GDB will not allow to restart
+the program avoiding any loop. So not special analysis of cause of exception
+is foreseen as far as RGDBSD code is concerned,
+@end itemize
+
+@subsection Open Issues
+
+Here are some problems we have faced while implementing our prototype :
+
+@table @b
+@item [Protected ReadMem/WriteMem (I1)]:
+A GDB user can request to see the content
+of a corrupted pointer. The request PEEK_DATA will be performed by the COMMAND_MNGT
+task. It shall not enter the default exception handler set by RGDBSD or it will
+cause a dead lock in the RGDBSD code. Replacing the default exception vector
+before calling @b{readMem/writeMem} can be temporarily sufficient but :
+
+@itemize @b
+@item It will never work on MP system as it will rely on task priorities to insure
+that other task will not cause exceptions while we have removed the default
+exception handler,
+
+@item This feature should not be usable in RGDBSD only but also by an embedded debugger
+that may run without any task. It is also unavoidable in case of protected memory
+and in this case no priority mechanism can be used,
+
+@item In the case of using RGDBSD code on a dedicated nano kernel, this code will
+be called from interrupt level and we need a way to be sure we can debug other
+interrupts that may also cause exceptions,
+@end itemize
+
+@item [ATTACH Command Implementation (I2)]:
+After the @emph{target rtems symbolic_ip_target_name}
+command, the normal operation is to issue an @emph{attach lid} command where
+@emph{lid} represents a valid execution context. For Unix this is a process
+id, for other multi-tasking system this is the id of a thread. After the attach
+command, GDB expects to be waken up in the same manner as it is for normal events.
+Once waken up it expects to have a complete register context available and also
+that the target task is in a stopped state and that it can restart it using
+the regular CONTINUE command. In RTEMS there is a way to get force a thread
+to become inactive via @emph{rtems_task_suspend} but no way to get the full
+registers set for the thread. A partial context can be retrieved from the task
+@emph{Registers} data structure. On the other hand, relying on @emph{rtems_task_suspend
+will be a problem for the nano-kernel implementation.
+
+@item [Stopping Target System (I3)]:
+Allthough it might not be obvious, most of the
+actions made by a GDB user assume the target is not running. If you modify a
+variable via the @emph{set variable = value} command you expect that the value
+is the one you have put when restarting. If a still running task modifies the
+same value in the mean time, this may be false. On the other hand, stopping
+all the tasks on the target system impose to have a very deep knowledge of the
+system. Using an interrupt driven RGDBSD, may facilitate the implementation
+on the nano-kernel.
+
+@item [Getting Tasks Contexts (I4)]:
+As previously mentionned there is no way to get
+tasks execution contexts via the RTEMS API. This is needed when debugging for
+example via this classical sequence :
+
+@enumerate
+
+@item @emph{(gdb) target rtems symbolic_ip_target_name}
+
+@item @emph{(gdb) info threads <=} get a thread list on screen
+
+@item @emph{(gdb)} @emph{attach thread_id} <= thread_id is one of the thread in
+the list
+
+@item @emph{(gdb) b a_function_of_interest }
+
+@item @emph{(gdb) continue}
+
+@item @emph{(gdb)} @emph{backtrace} <= print the call stack on the screen once we
+have hit the breakpoint
+
+@item @emph{(gdb) thread target another_thread_li <=} change implicit current thread
+value for gdb commands
+
+@item @emph{(gdb)} @emph{backtrace <=} should print the backtrace for the chosen thread
+@end enumerate
+In our execution model, we have a valid context only for the threads that hits
+the breakpoint as it has been pushed by the exception handler code. The other
+thread is still running and during the various RPC requesting memory access,
+it even changes as the COMMAND_MNGT thread is going to sleep. So the backtrace
+command will fail. We must find a way to make this work as it is very usefull
+when debugging multi-threaded programs,
+
+
+@item [Backtrace Stop convention (I5)]:
+The backtrace command on RTEMS task does not
+gracefully terminate as GDB does not find some backtrace termination condition
+it expects.
+@end table
+
+@subsection Workarounds for Open Issues in Prototype
+
+@table @b
+
+@item [(I1)]:
+Not implemented.We would rather like to work on the formalization of
+per thread flags and global flags that are much more general than any kludge
+we could implement,
+
+@item [(I2)]:
+We have tried two solutions in our prototype. The first one was to use
+the @emph{idle} thread context contained in the @emph{Registers} task control
+block field. The drawback of this solution was that we had to implement specific
+code for the continue operation immediately following the attach command. We
+then decided to create a dedicated task that will only exist during the attach
+phase. This task will call the ``ENTER_RGDB'' exception. This call will execute
+the Exception Handler that saves a valid context and that notifies a change
+to GDB. After the first CONTINUE command from GDB, this task will continue its
+execution and delete itself,
+
+@item [(I3)]:
+As explained above in the synchronization chapter, we choose to serialize
+events in a way that makes GDB think the system is frozen,
+
+@item [(I4)]:
+As a temporary fix, we have called @emph{rtems_task_suspend} and used
+the context switch contex for tasks that are unknown to RGDBSD,
+
+@item [(I5)]:
+Not Implemented yet. If I remember correctly, setting the frame pointer
+to 0 at task initialization for CISC processor solves this problem (ebp = 0x0
+on Intel or a6 = 0x0 on 680x0). This should be done in rtems_task_create function
+in the path to really starts the task for the first time. The processor/system
+specific stop condition can be found as macros in the GDB source tree.
+@end table
+
+@subsection Output of a Debug Session with the Prototype
+
+@example
+GNU gdb 4.17
+Copyright 1998 Free Software Foundation, Inc.
+GDB is free software, covered by the GNU General Public License, and you are
+welcome to change it and/or distribute copies of it under certain conditions.
+Type "show copying" to see the conditions.
+There is absolutely no warranty for GDB. Type "show warranty" for details.
+This GDB was configured as --host=i686-pc-linux-gnu --target=i386-rtems".
+Attaching remote machine across net...
+Connected to net-test.
+Now the "run" command will start a remote process.
+Setting up the environment for debugging gdb.
+(gdb) attach 1
+Attaching program: /build-rtems/pc386/tests/debug.exe pid 1
+0x230715 in enterRdbg ()
+(gdb) info threads
+There are 8 threads:
+Id. Name Detached Suspended
+134283273 Rini No No <= current target thread
+0x230715 in enterRdbg ()
+134283272 Evnt No No
+_Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315
+134283271 SPE2 No No
+_Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315
+134283270 SPE1 No No
+_Thread_Handler () at /rtems/c/src/exec/score/src/thread.c:1107
+134283269 RDBG No No
+0x230715 in enterRdbg ()
+134283268 SCrx No No
+_Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315
+134283267 SCtx No No
+_Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315
+134283266 ntwk No No
+_Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315
+(gdb) b init.c:89
+Breakpoint 1 at 0x200180: file /rtems/c/src/tests/samples/debug/init.c, line 89.
+(gdb) c
+Continuing.
+Thread 134283273 (Rini) has been deleted.
+[Switching to Rtems thread 134283271 (Not suspended) ( <= current target thread )]
+Breakpoint 1, example2 (argument=4) at /rtems/c/src/tests/samples/debug/init.c:89
+89 tuto += tuti;
+(gdb) s
+90 if (print_enable2)
+(gdb) c
+Continuing.
+Breakpoint 1, example2 (argument=4) at /rtems/c/src/tests/samples/debug/init.c:89
+89 tuto += tuti;
+(gdb) b init.c:66
+Breakpoint 2 at 0x200128: file /rtems/c/src/tests/samples/debug/init.c, line 66.
+(gdb) c
+Continuing.
+{Switching to Rtems thread 134283270 (Not suspended) ( <= current target thread )]
+Breakpoint 2, example1 (argument=4) at /rtems/c/src/tests/samples/debug/init.c:66
+66 toto += titi;
+(gdb) c
+Continuing.
+[Switching to Rtems thread 134283271 (Not suspended) ( <= current target thread )]
+Breakpoint 1, example2 (argument=4) at /rtems/c/src/tests/samples/debug/init.c:89
+89 tuto += tuti;
+(gdb) bt
+#0 example2 (argument=4)
+ at /rtems/c/src/tests/samples/debug/init.c:89
+#1 0xf0009bd0 in ?? ()
+(gdb) thread target 134283270
+thread 134283270 [SPE1], _Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315
+315 executing = _Thread_Executing;
+(gdb) c
+Continuing.
+Breakpoint 2, example1 (argument=4) at /rtems/c/src/tests/samples/debug/init.c:66
+66 toto += titi;
+(gdb) detach
+Detaching program: /build-rtems/pc386/tests/debug.exe pid 1
+Warning: the next command will be done localy! If you want to restart another remote
+program, reuse the target command
+(gdb)
+@end example
+
+