1 | @c |
---|
2 | @c RTEMS Remote Debugger Server Specifications |
---|
3 | @c |
---|
4 | @c Written by: Eric Valette <valette@crf.canon.fr> |
---|
5 | @c Emmanuel Raguet <raguet@crf.canon.fr> |
---|
6 | @c |
---|
7 | @c |
---|
8 | @c $Id$ |
---|
9 | @c |
---|
10 | |
---|
11 | @chapter RTEMS Debugger Server Daemon |
---|
12 | |
---|
13 | We will describe in this section how this debugger server will be |
---|
14 | implemented on RTEMS environment. Our initial target is based on Intel Pentium |
---|
15 | and we will use an Ethernet link to communicate between the host and the target. |
---|
16 | |
---|
17 | The RTEMS remote debugger will be composed by several tasks and exception |
---|
18 | handlers : |
---|
19 | |
---|
20 | @itemize @bullet |
---|
21 | @item an initialization task which opens the sockets and runs the SUN RPC |
---|
22 | server. This task will also connect the interrupt handlers and launch the communication |
---|
23 | task |
---|
24 | @item a communication task which receives the SUN RPC commands, executes |
---|
25 | them and sends the result to the GDB client, |
---|
26 | @item A debuggee event management task which waits for events. We need a different |
---|
27 | task than the command management task in order to be able to still accept commands |
---|
28 | while no event has yet occurred for the debuggee. An example could be a continue |
---|
29 | command from GDB and then hitting to DEL key to see what is currently going |
---|
30 | on on the target side because an expected breakpoint is not caught... |
---|
31 | @item a debug exception handler which manages the hardware breakpoint and |
---|
32 | single step exceptions (INT 1 on Intel x86), |
---|
33 | @item a breakpoint exception handler which manages the software breakpoints |
---|
34 | exceptions (INT 3 on Intel x86), |
---|
35 | @item a default exception handler used to catch every possible errors make on the |
---|
36 | target system, |
---|
37 | @end itemize |
---|
38 | |
---|
39 | @c XXX figure reference |
---|
40 | @c XXX references to other sections |
---|
41 | Figure @b{remote debugger tasks and handlers} represents these |
---|
42 | different tasks and handlers. The synchronization between the different task |
---|
43 | and exception handlers will be described below in the section |
---|
44 | @b{Synchronization Among Tasks and Exception Handlers}. |
---|
45 | Some open issues we have faced for a prototype implementation are described |
---|
46 | in the section @b{Open Issues}. The temporary workaround we chose are described |
---|
47 | in chapter @b{Workarounds for Open Issues in Prototype}. |
---|
48 | |
---|
49 | |
---|
50 | @section The INITIALIZATION task |
---|
51 | |
---|
52 | This is the task that must be executed at the boot phase of RTEMS. |
---|
53 | It initializes the debug context. It must : |
---|
54 | |
---|
55 | @itemize @bullet |
---|
56 | @item open the UDP sockets, |
---|
57 | @item run the SUN RPC server main loop, |
---|
58 | @item create the COMMAND MANAGEMENT task, |
---|
59 | @item connect the DEBUG EXCEPTION handler, |
---|
60 | @item connect the SOFTWARE BREAKPOINT handler, |
---|
61 | @item delete itself. |
---|
62 | @end itemize |
---|
63 | If an error occurs at any step of the execution, the connections established |
---|
64 | before the error will be closed, before the initialization task deletes itself. |
---|
65 | |
---|
66 | |
---|
67 | @section The COMMAND_MNGT task |
---|
68 | |
---|
69 | This task is in charge of receiving the SUN RPC messages and executing |
---|
70 | the associated commands. This task must have an important priority because it |
---|
71 | must be executed each time a command message comes from the debugger. It must |
---|
72 | be executed even if one or both exception handlers are executed. But the COMMAND |
---|
73 | MANAGEMENT task must not block the TCP/IP module without which no message can |
---|
74 | be received. |
---|
75 | |
---|
76 | When not executing a command, this task is waiting for a SUN RPC message |
---|
77 | on the primary port. This idle state blocks the task, so the other active tasks |
---|
78 | can run. Once a message comes from Ethernet via the primary port, the COMMAND |
---|
79 | MANAGEMENT task wakes up and receives the message which is a request from GDB. |
---|
80 | This request is sent to the SUN RPC server code which extracts the command and |
---|
81 | its arguments, executes it and, if needed, sends a result to GDB. After having |
---|
82 | performed these actions, the task sleeps, waiting for another message. |
---|
83 | |
---|
84 | A particular case is the reception of the ATTACH command : in this |
---|
85 | case the COMMAND_MNGT task creates the EVENT_MNGT task described below before |
---|
86 | going to wait on UDP socket again. |
---|
87 | |
---|
88 | |
---|
89 | @section The EVENT_MNGT task |
---|
90 | |
---|
91 | This task is in charge of managing events happening on the debuggee such as |
---|
92 | breakpoint, exceptions. This task does a basic simple loop waiting for event |
---|
93 | on a synchronization variable. It is waken up by exception handlers code. It |
---|
94 | then signals GDB that an event occurred and then go sleeping again as further |
---|
95 | requests will be processed by the COMMAND_MNGT task. |
---|
96 | |
---|
97 | |
---|
98 | @section The DEBUG EXCEPTION handler |
---|
99 | |
---|
100 | This handler is connected to the DEBUG exception (INT 1 on Intel ix86). |
---|
101 | This exception is entered when : |
---|
102 | |
---|
103 | @itemize @bullet |
---|
104 | @item executing a single-step instruction, |
---|
105 | @item hardware breakpoint condition is true, |
---|
106 | @end itemize |
---|
107 | These events will be treated by the debugger because they are the |
---|
108 | primary event used when debugging a software for instruction stepping. In both |
---|
109 | cases, the DEBUG EXCEPTION handler code is executed. Please note that the execution |
---|
110 | context of the exception handler is the supervisor stack of the task that generated |
---|
111 | the exception . This implies : |
---|
112 | |
---|
113 | @itemize @bullet |
---|
114 | @item We may sleep in this context, |
---|
115 | @item We have as many possible execution context for the DEBUG EXCEPTION handler as |
---|
116 | we need to, |
---|
117 | @item When we enter the high level exception handler code, a normalized exception |
---|
118 | context has been pushed on the system stack and a pointer to this context is |
---|
119 | available as the first argument (cf c/src/exec/score/cpu/i386/cpu.c for more |
---|
120 | details), |
---|
121 | @end itemize |
---|
122 | First the exception handler wakeup the EVENT_MNGT task. Then it will |
---|
123 | cause the faulting thread to sleep on a synchronization object. As soon as GDB |
---|
124 | receives the event notifying that the debuggee status has changed, it will start |
---|
125 | sending requests to get the debuggee status (registers set, faulty task id, |
---|
126 | ...). These requests are handled by the COMMAND MANAGEMENT task. When this task |
---|
127 | receive a PTRACE_CONT command it will resume the execution of the task that |
---|
128 | caused the exception by doing a V on the synchronization object. |
---|
129 | |
---|
130 | |
---|
131 | @section The BREAKPOINT EXCEPTION handler |
---|
132 | |
---|
133 | This handler is connected to the BREAKPOINT exception (INT3 on Intel |
---|
134 | Ix86). Each time the debugger wants to place a software breakpoint in the debuggee, |
---|
135 | a debuggee opcode is temporarily replaced by an instruction causing BREAKPOINT |
---|
136 | exception (the ``INT 3'' instruction on Intel ix86). When ``INT 3'' is executed, |
---|
137 | the BREAKPOINT handler is executed. Otherwise, the exception processing is the |
---|
138 | same than the one described in previous section. |
---|
139 | |
---|
140 | |
---|
141 | @section Synchronization Among Tasks and Exception Handlers |
---|
142 | |
---|
143 | The previous chapters have presented a simplified and static view of the various |
---|
144 | tasks and exceptions handlers. This chapter is more focussed on synchronization |
---|
145 | requirements about the various pieces of code executed when RGDBSD is operating. |
---|
146 | |
---|
147 | |
---|
148 | @subsection Implicit Synchronization Using Task Priorities |
---|
149 | |
---|
150 | This chapter is relevant on Uniprocessor System (UP) only. However, it will |
---|
151 | also list the requirements for explicit synchronization on Multi-processor Systems |
---|
152 | (MP). Below are the task priorities sorted by high priority. They are not supposed |
---|
153 | to be equal : |
---|
154 | |
---|
155 | @enumerate |
---|
156 | @item Network Input Task. This is the highest priority task. This can be regarded |
---|
157 | as a software interrupt task for FreeBSD code, |
---|
158 | @item RGDBSD command task. As this task waits on UDP sockets, it shall not prevent |
---|
159 | the previous task from running. As the main debug entry point, it should preempt |
---|
160 | any other task in the system, |
---|
161 | @item RGDBSD event task. This task should preempt any task but the two mentionned |
---|
162 | before to signal a debug event to GDB. The command task shall be able to preempt |
---|
163 | this task for emergency command such as DEL, or REBOOT, |
---|
164 | @item Applications tasks (task we are able to debug), |
---|
165 | @end enumerate |
---|
166 | Using theses priorities eliminates the need for adding more synchronization |
---|
167 | objects in the next section. My belief is that symmetric MP support will require |
---|
168 | more important change in the RTEMS than RGDBSD itself like multiple scheduler |
---|
169 | queues, task to processor binding for non symmetric IO, use a different implementation |
---|
170 | for @emph{task_disable_preemption}, ... |
---|
171 | |
---|
172 | |
---|
173 | @subsection Explicit Synchronization |
---|
174 | |
---|
175 | This chapter will describe the synchronization variables that need to be implemented |
---|
176 | in order to sequence debug events in a way that is compatible with what GDB |
---|
177 | code expects. The root of the problem is that GDB code mainly expects that once |
---|
178 | a debug event has occurred on the debuggee, the entire debuggee is frozen and |
---|
179 | no other event will occur before the CONTINUE command is issued. This behavior |
---|
180 | is hard to achieve in our case as once we hit a breakpoint, only the task that |
---|
181 | hits the breakpoint will be asleep on a synchronization object. Other tasks |
---|
182 | may hit other breakpoints while we are waiting commands from GDB generating |
---|
183 | potential unexpected events. There is a solutions if RGDBSD itself use RTEMS |
---|
184 | threads to fix this problem by creating a task that loops forever at a priority |
---|
185 | superior to any debugged task but below RGDBSD task priorities. Unfortunately |
---|
186 | this will not work for the case we use the nano-kernel implementation and we |
---|
187 | think it is better to study synchronization problems now. We also expects that |
---|
188 | multi-thread debug support hardening in GDB will remove some event serializations |
---|
189 | requirements. Here is the list of synchronization variables we plan to use and |
---|
190 | their usage. They are all regular semaphores. They are not binary semaphores |
---|
191 | because the task that does V is not the task that has done the P. |
---|
192 | |
---|
193 | @itemize @bullet |
---|
194 | @item @emph{WakeUpEventTask} : used by exception handler code to wake up the EVENT_MNGT |
---|
195 | task by doing a V operation on this object. When target code is running normally |
---|
196 | the EVENT_MNGT task sleeps due to a P operation on this semaphore, |
---|
197 | @item @emph{SerializeDebugEvent} : used to serialize events in a way compatible to |
---|
198 | what GDB expects. Before doing a V operation on @emph{WakeUpEventTask}, the |
---|
199 | exception handler does a P on this semaphore to be sure processing of another |
---|
200 | exception is not in progress. Upon reception of a CONTINUE command, the COMMAND_MNGT |
---|
201 | task will issue a V operation so that the exception code can wake up EVENT_MNGT |
---|
202 | task using the mechanism described above, |
---|
203 | @item @emph{RestartFromException} : (in fact one semaphore per task) used by exception |
---|
204 | handling code to put a faulty task to sleep once it has generated an exception |
---|
205 | by doing a P operation on this semaphore. In the case the exception was generated |
---|
206 | due to a breakpoint, GDB command will modify back the BREAKPOINT opcode to the |
---|
207 | original value before doing the CONTINUE command. This command will perform |
---|
208 | a V on this semaphore. In the case it is a real non restartable exception (faulty |
---|
209 | memory reference via invalid pointer for example), GDB will not allow to restart |
---|
210 | the program avoiding any loop. So not special analysis of cause of exception |
---|
211 | is foreseen as far as RGDBSD code is concerned, |
---|
212 | @end itemize |
---|
213 | |
---|
214 | @section Open Issues |
---|
215 | |
---|
216 | Here are some problems we have faced while implementing our prototype : |
---|
217 | |
---|
218 | @table @b |
---|
219 | @item [Protected ReadMem/WriteMem (I1)]: |
---|
220 | A GDB user can request to see the content |
---|
221 | of a corrupted pointer. The request PEEK_DATA will be performed by the COMMAND_MNGT |
---|
222 | task. It shall not enter the default exception handler set by RGDBSD or it will |
---|
223 | cause a dead lock in the RGDBSD code. Replacing the default exception vector |
---|
224 | before calling @b{readMem/writeMem} can be temporarily sufficient but : |
---|
225 | |
---|
226 | @itemize @bullet |
---|
227 | @item It will never work on MP system as it will rely on task priorities to insure |
---|
228 | that other task will not cause exceptions while we have removed the default |
---|
229 | exception handler, |
---|
230 | |
---|
231 | @item This feature should not be usable in RGDBSD only but also by an embedded debugger |
---|
232 | that may run without any task. It is also unavoidable in case of protected memory |
---|
233 | and in this case no priority mechanism can be used, |
---|
234 | |
---|
235 | @item In the case of using RGDBSD code on a dedicated nano kernel, this code will |
---|
236 | be called from interrupt level and we need a way to be sure we can debug other |
---|
237 | interrupts that may also cause exceptions, |
---|
238 | @end itemize |
---|
239 | |
---|
240 | @item [ATTACH Command Implementation (I2)]: |
---|
241 | After the @emph{target rtems symbolic_ip_target_name} |
---|
242 | command, the normal operation is to issue an @emph{attach lid} command where |
---|
243 | @emph{lid} represents a valid execution context. For Unix this is a process |
---|
244 | id, for other multi-tasking system this is the id of a thread. After the attach |
---|
245 | command, GDB expects to be waken up in the same manner as it is for normal events. |
---|
246 | Once waken up it expects to have a complete register context available and also |
---|
247 | that the target task is in a stopped state and that it can restart it using |
---|
248 | the regular CONTINUE command. In RTEMS there is a way to get force a thread |
---|
249 | to become inactive via @emph{rtems_task_suspend} but no way to get the full |
---|
250 | registers set for the thread. A partial context can be retrieved from the task |
---|
251 | @emph{Registers} data structure. On the other hand, relying on @emph{rtems_task_suspend} |
---|
252 | will be a problem for the nano-kernel implementation. |
---|
253 | |
---|
254 | @item [Stopping Target System (I3)]: |
---|
255 | Allthough it might not be obvious, most of the |
---|
256 | actions made by a GDB user assume the target is not running. If you modify a |
---|
257 | variable via the @emph{set variable = value} command you expect that the value |
---|
258 | is the one you have put when restarting. If a still running task modifies the |
---|
259 | same value in the mean time, this may be false. On the other hand, stopping |
---|
260 | all the tasks on the target system impose to have a very deep knowledge of the |
---|
261 | system. Using an interrupt driven RGDBSD, may facilitate the implementation |
---|
262 | on the nano-kernel. |
---|
263 | |
---|
264 | @item [Getting Tasks Contexts (I4)]: |
---|
265 | As previously mentionned there is no way to get |
---|
266 | tasks execution contexts via the RTEMS API. This is needed when debugging for |
---|
267 | example via this classical sequence : |
---|
268 | |
---|
269 | @enumerate |
---|
270 | |
---|
271 | @item @emph{(gdb) target rtems symbolic_ip_target_name} |
---|
272 | |
---|
273 | @item @emph{(gdb) info threads <=} get a thread list on screen |
---|
274 | |
---|
275 | @item @emph{(gdb)} @emph{attach thread_id} <= thread_id is one of the thread in |
---|
276 | the list |
---|
277 | |
---|
278 | @item @emph{(gdb) b a_function_of_interest } |
---|
279 | |
---|
280 | @item @emph{(gdb) continue} |
---|
281 | |
---|
282 | @item @emph{(gdb)} @emph{backtrace} <= print the call stack on the screen once we |
---|
283 | have hit the breakpoint |
---|
284 | |
---|
285 | @item @emph{(gdb) thread target another_thread_li <=} change implicit current thread |
---|
286 | value for gdb commands |
---|
287 | |
---|
288 | @item @emph{(gdb)} @emph{backtrace <=} should print the backtrace for the chosen thread |
---|
289 | @end enumerate |
---|
290 | In our execution model, we have a valid context only for the threads that hits |
---|
291 | the breakpoint as it has been pushed by the exception handler code. The other |
---|
292 | thread is still running and during the various RPC requesting memory access, |
---|
293 | it even changes as the COMMAND_MNGT thread is going to sleep. So the backtrace |
---|
294 | command will fail. We must find a way to make this work as it is very usefull |
---|
295 | when debugging multi-threaded programs, |
---|
296 | |
---|
297 | |
---|
298 | @item [Backtrace Stop convention (I5)]: |
---|
299 | The backtrace command on RTEMS task does not |
---|
300 | gracefully terminate as GDB does not find some backtrace termination condition |
---|
301 | it expects. |
---|
302 | @end table |
---|
303 | |
---|
304 | @section Workarounds for Open Issues in Prototype |
---|
305 | |
---|
306 | @table @b |
---|
307 | |
---|
308 | @item [(I1)]: |
---|
309 | Not implemented.We would rather like to work on the formalization of |
---|
310 | per thread flags and global flags that are much more general than any kludge |
---|
311 | we could implement, |
---|
312 | |
---|
313 | @item [(I2)]: |
---|
314 | We have tried two solutions in our prototype. The first one was to use |
---|
315 | the @emph{idle} thread context contained in the @emph{Registers} task control |
---|
316 | block field. The drawback of this solution was that we had to implement specific |
---|
317 | code for the continue operation immediately following the attach command. We |
---|
318 | then decided to create a dedicated task that will only exist during the attach |
---|
319 | phase. This task will call the ``ENTER_RGDB'' exception. This call will execute |
---|
320 | the Exception Handler that saves a valid context and that notifies a change |
---|
321 | to GDB. After the first CONTINUE command from GDB, this task will continue its |
---|
322 | execution and delete itself, |
---|
323 | |
---|
324 | @item [(I3)]: |
---|
325 | As explained above in the synchronization chapter, we choose to serialize |
---|
326 | events in a way that makes GDB think the system is frozen, |
---|
327 | |
---|
328 | @item [(I4)]: |
---|
329 | As a temporary fix, we have called @emph{rtems_task_suspend} and used |
---|
330 | the context switch contex for tasks that are unknown to RGDBSD, |
---|
331 | |
---|
332 | @item [(I5)]: |
---|
333 | Not Implemented yet. If I remember correctly, setting the frame pointer |
---|
334 | to 0 at task initialization for CISC processor solves this problem (ebp = 0x0 |
---|
335 | on Intel or a6 = 0x0 on 680x0). This should be done in rtems_task_create function |
---|
336 | in the path to really starts the task for the first time. The processor/system |
---|
337 | specific stop condition can be found as macros in the GDB source tree. |
---|
338 | @end table |
---|
339 | |
---|
340 | @section Output of a Debug Session with the Prototype |
---|
341 | |
---|
342 | @example |
---|
343 | GNU gdb 4.17 |
---|
344 | Copyright 1998 Free Software Foundation, Inc. |
---|
345 | GDB is free software, covered by the GNU General Public License, and you are |
---|
346 | welcome to change it and/or distribute copies of it under certain conditions. |
---|
347 | Type "show copying" to see the conditions. |
---|
348 | There is absolutely no warranty for GDB. Type "show warranty" for details. |
---|
349 | This GDB was configured as --host=i686-pc-linux-gnu --target=i386-rtems". |
---|
350 | Attaching remote machine across net... |
---|
351 | Connected to net-test. |
---|
352 | Now the "run" command will start a remote process. |
---|
353 | Setting up the environment for debugging gdb. |
---|
354 | (gdb) attach 1 |
---|
355 | Attaching program: /build-rtems/pc386/tests/debug.exe pid 1 |
---|
356 | 0x230715 in enterRdbg () |
---|
357 | (gdb) info threads |
---|
358 | There are 8 threads: |
---|
359 | Id. Name Detached Suspended |
---|
360 | 134283273 Rini No No <= current target thread |
---|
361 | 0x230715 in enterRdbg () |
---|
362 | 134283272 Evnt No No |
---|
363 | _Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315 |
---|
364 | 134283271 SPE2 No No |
---|
365 | _Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315 |
---|
366 | 134283270 SPE1 No No |
---|
367 | _Thread_Handler () at /rtems/c/src/exec/score/src/thread.c:1107 |
---|
368 | 134283269 RDBG No No |
---|
369 | 0x230715 in enterRdbg () |
---|
370 | 134283268 SCrx No No |
---|
371 | _Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315 |
---|
372 | 134283267 SCtx No No |
---|
373 | _Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315 |
---|
374 | 134283266 ntwk No No |
---|
375 | _Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315 |
---|
376 | (gdb) b init.c:89 |
---|
377 | Breakpoint 1 at 0x200180: file /rtems/c/src/tests/samples/debug/init.c, line 89. |
---|
378 | (gdb) c |
---|
379 | Continuing. |
---|
380 | Thread 134283273 (Rini) has been deleted. |
---|
381 | [Switching to Rtems thread 134283271 (Not suspended) ( <= current target thread )] |
---|
382 | Breakpoint 1, example2 (argument=4) at /rtems/c/src/tests/samples/debug/init.c:89 |
---|
383 | 89 tuto += tuti; |
---|
384 | (gdb) s |
---|
385 | 90 if (print_enable2) |
---|
386 | (gdb) c |
---|
387 | Continuing. |
---|
388 | Breakpoint 1, example2 (argument=4) at /rtems/c/src/tests/samples/debug/init.c:89 |
---|
389 | 89 tuto += tuti; |
---|
390 | (gdb) b init.c:66 |
---|
391 | Breakpoint 2 at 0x200128: file /rtems/c/src/tests/samples/debug/init.c, line 66. |
---|
392 | (gdb) c |
---|
393 | Continuing. |
---|
394 | Switching to Rtems thread 134283270 (Not suspended) ( <= current target thread )] |
---|
395 | Breakpoint 2, example1 (argument=4) at /rtems/c/src/tests/samples/debug/init.c:66 |
---|
396 | 66 toto += titi; |
---|
397 | (gdb) c |
---|
398 | Continuing. |
---|
399 | [Switching to Rtems thread 134283271 (Not suspended) ( <= current target thread )] |
---|
400 | Breakpoint 1, example2 (argument=4) at /rtems/c/src/tests/samples/debug/init.c:89 |
---|
401 | 89 tuto += tuti; |
---|
402 | (gdb) bt |
---|
403 | #0 example2 (argument=4) |
---|
404 | at /rtems/c/src/tests/samples/debug/init.c:89 |
---|
405 | #1 0xf0009bd0 in ?? () |
---|
406 | (gdb) thread target 134283270 |
---|
407 | thread 134283270 [SPE1], _Thread_Dispatch () at /rtems/c/src/exec/score/src/thread.c:315 |
---|
408 | 315 executing = _Thread_Executing; |
---|
409 | (gdb) c |
---|
410 | Continuing. |
---|
411 | Breakpoint 2, example1 (argument=4) at /rtems/c/src/tests/samples/debug/init.c:66 |
---|
412 | 66 toto += titi; |
---|
413 | (gdb) detach |
---|
414 | Detaching program: /build-rtems/pc386/tests/debug.exe pid 1 |
---|
415 | Warning: the next command will be done localy! If you want to restart another remote |
---|
416 | program, reuse the target command |
---|
417 | (gdb) |
---|
418 | @end example |
---|
419 | |
---|
420 | |
---|