source: mainline/kernel/generic/src/udebug/udebug_ipc.c@ 8cbf1c3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8cbf1c3 was 96b02eb9, checked in by Martin Decky <martin@…>, 15 years ago

more unification of basic types

  • use sysarg_t and native_t (unsigned and signed variant) in both kernel and uspace
  • remove ipcarg_t in favour of sysarg_t

(no change in functionality)

  • Property mode set to 100644
File size: 11.2 KB
Line 
1/*
2 * Copyright (c) 2008 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup generic
30 * @{
31 */
32
33/**
34 * @file
35 * @brief Udebug IPC message handling.
36 *
37 * This module handles udebug IPC messages and calls the appropriate
38 * functions from the udebug_ops module which implement them.
39 */
40
41#include <proc/task.h>
42#include <proc/thread.h>
43#include <mm/as.h>
44#include <arch.h>
45#include <errno.h>
46#include <ipc/ipc.h>
47#include <syscall/copy.h>
48#include <udebug/udebug.h>
49#include <udebug/udebug_ops.h>
50#include <udebug/udebug_ipc.h>
51
52int udebug_request_preprocess(call_t *call, phone_t *phone)
53{
54 switch (IPC_GET_ARG1(call->data)) {
55 /* future UDEBUG_M_REGS_WRITE, UDEBUG_M_MEM_WRITE: */
56 default:
57 break;
58 }
59
60 return 0;
61}
62
63/** Process a BEGIN call.
64 *
65 * Initiates a debugging session for the current task. The reply
66 * to this call may or may not be sent before this function returns.
67 *
68 * @param call The call structure.
69 */
70static void udebug_receive_begin(call_t *call)
71{
72 int rc;
73
74 rc = udebug_begin(call);
75 if (rc < 0) {
76 IPC_SET_RETVAL(call->data, rc);
77 ipc_answer(&TASK->kb.box, call);
78 return;
79 }
80
81 /*
82 * If the initialization of the debugging session has finished,
83 * send a reply.
84 */
85 if (rc != 0) {
86 IPC_SET_RETVAL(call->data, 0);
87 ipc_answer(&TASK->kb.box, call);
88 }
89}
90
91/** Process an END call.
92 *
93 * Terminates the debugging session for the current task.
94 * @param call The call structure.
95 */
96static void udebug_receive_end(call_t *call)
97{
98 int rc;
99
100 rc = udebug_end();
101
102 IPC_SET_RETVAL(call->data, rc);
103 ipc_answer(&TASK->kb.box, call);
104}
105
106/** Process a SET_EVMASK call.
107 *
108 * Sets an event mask for the current debugging session.
109 * @param call The call structure.
110 */
111static void udebug_receive_set_evmask(call_t *call)
112{
113 int rc;
114 udebug_evmask_t mask;
115
116 mask = IPC_GET_ARG2(call->data);
117 rc = udebug_set_evmask(mask);
118
119 IPC_SET_RETVAL(call->data, rc);
120 ipc_answer(&TASK->kb.box, call);
121}
122
123
124/** Process a GO call.
125 *
126 * Resumes execution of the specified thread.
127 * @param call The call structure.
128 */
129static void udebug_receive_go(call_t *call)
130{
131 thread_t *t;
132 int rc;
133
134 t = (thread_t *)IPC_GET_ARG2(call->data);
135
136 rc = udebug_go(t, call);
137 if (rc < 0) {
138 IPC_SET_RETVAL(call->data, rc);
139 ipc_answer(&TASK->kb.box, call);
140 return;
141 }
142}
143
144/** Process a STOP call.
145 *
146 * Suspends execution of the specified thread.
147 * @param call The call structure.
148 */
149static void udebug_receive_stop(call_t *call)
150{
151 thread_t *t;
152 int rc;
153
154 t = (thread_t *)IPC_GET_ARG2(call->data);
155
156 rc = udebug_stop(t, call);
157 IPC_SET_RETVAL(call->data, rc);
158 ipc_answer(&TASK->kb.box, call);
159}
160
161/** Process a THREAD_READ call.
162 *
163 * Reads the list of hashes of the (userspace) threads in the current task.
164 * @param call The call structure.
165 */
166static void udebug_receive_thread_read(call_t *call)
167{
168 uintptr_t uspace_addr;
169 size_t buf_size;
170 void *buffer;
171 size_t copied, needed;
172 int rc;
173
174 uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
175 buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
176
177 /*
178 * Read thread list. Variable n will be filled with actual number
179 * of threads times thread-id size.
180 */
181 rc = udebug_thread_read(&buffer, buf_size, &copied, &needed);
182 if (rc < 0) {
183 IPC_SET_RETVAL(call->data, rc);
184 ipc_answer(&TASK->kb.box, call);
185 return;
186 }
187
188 /*
189 * Make use of call->buffer to transfer data to caller's userspace
190 */
191
192 IPC_SET_RETVAL(call->data, 0);
193 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
194 same code in process_answer() can be used
195 (no way to distinguish method in answer) */
196 IPC_SET_ARG1(call->data, uspace_addr);
197 IPC_SET_ARG2(call->data, copied);
198 IPC_SET_ARG3(call->data, needed);
199 call->buffer = buffer;
200
201 ipc_answer(&TASK->kb.box, call);
202}
203
204/** Process a NAME_READ call.
205 *
206 * Returns a string containing the name of the task.
207 *
208 * @param call The call structure.
209 */
210static void udebug_receive_name_read(call_t *call)
211{
212 sysarg_t uspace_addr;
213 sysarg_t to_copy;
214 size_t data_size;
215 size_t buf_size;
216 void *data;
217
218 uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
219 buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
220
221 /*
222 * Read task name.
223 */
224 udebug_name_read((char **) &data, &data_size);
225
226 /* Copy MAX(buf_size, data_size) bytes */
227
228 if (buf_size > data_size)
229 to_copy = data_size;
230 else
231 to_copy = buf_size;
232
233 /*
234 * Make use of call->buffer to transfer data to caller's userspace
235 */
236
237 IPC_SET_RETVAL(call->data, 0);
238 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
239 same code in process_answer() can be used
240 (no way to distinguish method in answer) */
241 IPC_SET_ARG1(call->data, uspace_addr);
242 IPC_SET_ARG2(call->data, to_copy);
243
244 IPC_SET_ARG3(call->data, data_size);
245 call->buffer = data;
246
247 ipc_answer(&TASK->kb.box, call);
248}
249
250/** Process an AREAS_READ call.
251 *
252 * Returns a list of address space areas in the current task, as an array
253 * of as_area_info_t structures.
254 *
255 * @param call The call structure.
256 */
257static void udebug_receive_areas_read(call_t *call)
258{
259 sysarg_t uspace_addr;
260 sysarg_t to_copy;
261 size_t data_size;
262 size_t buf_size;
263 void *data;
264
265 uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
266 buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
267
268 /*
269 * Read area list.
270 */
271 as_get_area_info(AS, (as_area_info_t **) &data, &data_size);
272
273 /* Copy MAX(buf_size, data_size) bytes */
274
275 if (buf_size > data_size)
276 to_copy = data_size;
277 else
278 to_copy = buf_size;
279
280 /*
281 * Make use of call->buffer to transfer data to caller's userspace
282 */
283
284 IPC_SET_RETVAL(call->data, 0);
285 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
286 same code in process_answer() can be used
287 (no way to distinguish method in answer) */
288 IPC_SET_ARG1(call->data, uspace_addr);
289 IPC_SET_ARG2(call->data, to_copy);
290
291 IPC_SET_ARG3(call->data, data_size);
292 call->buffer = data;
293
294 ipc_answer(&TASK->kb.box, call);
295}
296
297
298/** Process an ARGS_READ call.
299 *
300 * Reads the argument of a current syscall event (SYSCALL_B or SYSCALL_E).
301 * @param call The call structure.
302 */
303static void udebug_receive_args_read(call_t *call)
304{
305 thread_t *t;
306 sysarg_t uspace_addr;
307 int rc;
308 void *buffer;
309
310 t = (thread_t *)IPC_GET_ARG2(call->data);
311
312 rc = udebug_args_read(t, &buffer);
313 if (rc != EOK) {
314 IPC_SET_RETVAL(call->data, rc);
315 ipc_answer(&TASK->kb.box, call);
316 return;
317 }
318
319 /*
320 * Make use of call->buffer to transfer data to caller's userspace
321 */
322
323 uspace_addr = IPC_GET_ARG3(call->data);
324
325 IPC_SET_RETVAL(call->data, 0);
326 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
327 same code in process_answer() can be used
328 (no way to distinguish method in answer) */
329 IPC_SET_ARG1(call->data, uspace_addr);
330 IPC_SET_ARG2(call->data, 6 * sizeof(sysarg_t));
331 call->buffer = buffer;
332
333 ipc_answer(&TASK->kb.box, call);
334}
335
336/** Receive a REGS_READ call.
337 *
338 * Reads the thread's register state (istate structure).
339 */
340static void udebug_receive_regs_read(call_t *call)
341{
342 thread_t *t;
343 sysarg_t uspace_addr;
344 sysarg_t to_copy;
345 void *buffer;
346 int rc;
347
348 t = (thread_t *) IPC_GET_ARG2(call->data);
349
350 rc = udebug_regs_read(t, &buffer);
351 if (rc < 0) {
352 IPC_SET_RETVAL(call->data, rc);
353 ipc_answer(&TASK->kb.box, call);
354 return;
355 }
356
357 /*
358 * Make use of call->buffer to transfer data to caller's userspace
359 */
360
361 uspace_addr = IPC_GET_ARG3(call->data);
362 to_copy = sizeof(istate_t);
363
364 IPC_SET_RETVAL(call->data, 0);
365 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
366 same code in process_answer() can be used
367 (no way to distinguish method in answer) */
368 IPC_SET_ARG1(call->data, uspace_addr);
369 IPC_SET_ARG2(call->data, to_copy);
370
371 call->buffer = buffer;
372
373 ipc_answer(&TASK->kb.box, call);
374}
375
376
377/** Process an MEM_READ call.
378 *
379 * Reads memory of the current (debugged) task.
380 * @param call The call structure.
381 */
382static void udebug_receive_mem_read(call_t *call)
383{
384 sysarg_t uspace_dst;
385 sysarg_t uspace_src;
386 unsigned size;
387 void *buffer;
388 int rc;
389
390 uspace_dst = IPC_GET_ARG2(call->data);
391 uspace_src = IPC_GET_ARG3(call->data);
392 size = IPC_GET_ARG4(call->data);
393
394 rc = udebug_mem_read(uspace_src, size, &buffer);
395 if (rc < 0) {
396 IPC_SET_RETVAL(call->data, rc);
397 ipc_answer(&TASK->kb.box, call);
398 return;
399 }
400
401 IPC_SET_RETVAL(call->data, 0);
402 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
403 same code in process_answer() can be used
404 (no way to distinguish method in answer) */
405 IPC_SET_ARG1(call->data, uspace_dst);
406 IPC_SET_ARG2(call->data, size);
407 call->buffer = buffer;
408
409 ipc_answer(&TASK->kb.box, call);
410}
411
412/** Handle a debug call received on the kernel answerbox.
413 *
414 * This is called by the kbox servicing thread. Verifies that the sender
415 * is indeed the debugger and calls the appropriate processing function.
416 */
417void udebug_call_receive(call_t *call)
418{
419 int debug_method;
420
421 debug_method = IPC_GET_ARG1(call->data);
422
423 if (debug_method != UDEBUG_M_BEGIN) {
424 /*
425 * Verify that the sender is this task's debugger.
426 * Note that this is the only thread that could change
427 * TASK->debugger. Therefore no locking is necessary
428 * and the sender can be safely considered valid until
429 * control exits this function.
430 */
431 if (TASK->udebug.debugger != call->sender) {
432 IPC_SET_RETVAL(call->data, EINVAL);
433 ipc_answer(&TASK->kb.box, call);
434 return;
435 }
436 }
437
438 switch (debug_method) {
439 case UDEBUG_M_BEGIN:
440 udebug_receive_begin(call);
441 break;
442 case UDEBUG_M_END:
443 udebug_receive_end(call);
444 break;
445 case UDEBUG_M_SET_EVMASK:
446 udebug_receive_set_evmask(call);
447 break;
448 case UDEBUG_M_GO:
449 udebug_receive_go(call);
450 break;
451 case UDEBUG_M_STOP:
452 udebug_receive_stop(call);
453 break;
454 case UDEBUG_M_THREAD_READ:
455 udebug_receive_thread_read(call);
456 break;
457 case UDEBUG_M_NAME_READ:
458 udebug_receive_name_read(call);
459 break;
460 case UDEBUG_M_AREAS_READ:
461 udebug_receive_areas_read(call);
462 break;
463 case UDEBUG_M_ARGS_READ:
464 udebug_receive_args_read(call);
465 break;
466 case UDEBUG_M_REGS_READ:
467 udebug_receive_regs_read(call);
468 break;
469 case UDEBUG_M_MEM_READ:
470 udebug_receive_mem_read(call);
471 break;
472 }
473}
474
475/** @}
476 */
Note: See TracBrowser for help on using the repository browser.