source: mainline/kernel/generic/src/udebug/udebug_ipc.c@ 0b5203b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0b5203b was b389f95, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Allow as_get_area_info() to fail

  • Property mode set to 100644
File size: 11.4 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 kernel_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 <assert.h>
42#include <proc/task.h>
43#include <proc/thread.h>
44#include <mm/as.h>
45#include <arch.h>
46#include <errno.h>
47#include <ipc/ipc.h>
48#include <syscall/copy.h>
49#include <udebug/udebug.h>
50#include <udebug/udebug_ops.h>
51#include <udebug/udebug_ipc.h>
52
53errno_t udebug_request_preprocess(call_t *call, phone_t *phone)
54{
55 switch (IPC_GET_ARG1(call->data)) {
56 /* future UDEBUG_M_REGS_WRITE, UDEBUG_M_MEM_WRITE: */
57 default:
58 break;
59 }
60
61 return 0;
62}
63
64/** Process a BEGIN call.
65 *
66 * Initiates a debugging session for the current task. The reply
67 * to this call may or may not be sent before this function returns.
68 *
69 * @param call The call structure.
70 */
71static void udebug_receive_begin(call_t *call)
72{
73 errno_t rc;
74 bool active;
75
76 rc = udebug_begin(call, &active);
77 if (rc != EOK) {
78 IPC_SET_RETVAL(call->data, rc);
79 ipc_answer(&TASK->kb.box, call);
80 return;
81 }
82
83 /*
84 * If the initialization of the debugging session has finished,
85 * send a reply.
86 */
87 if (active) {
88 IPC_SET_RETVAL(call->data, EOK);
89 ipc_answer(&TASK->kb.box, call);
90 }
91}
92
93/** Process an END call.
94 *
95 * Terminates the debugging session for the current task.
96 * @param call The call structure.
97 */
98static void udebug_receive_end(call_t *call)
99{
100 errno_t rc;
101
102 rc = udebug_end();
103
104 IPC_SET_RETVAL(call->data, rc);
105 ipc_answer(&TASK->kb.box, call);
106}
107
108/** Process a SET_EVMASK call.
109 *
110 * Sets an event mask for the current debugging session.
111 * @param call The call structure.
112 */
113static void udebug_receive_set_evmask(call_t *call)
114{
115 errno_t rc;
116 udebug_evmask_t mask;
117
118 mask = IPC_GET_ARG2(call->data);
119 rc = udebug_set_evmask(mask);
120
121 IPC_SET_RETVAL(call->data, rc);
122 ipc_answer(&TASK->kb.box, call);
123}
124
125/** Process a GO call.
126 *
127 * Resumes execution of the specified thread.
128 * @param call The call structure.
129 */
130static void udebug_receive_go(call_t *call)
131{
132 thread_t *t;
133 errno_t rc;
134
135 t = (thread_t *)IPC_GET_ARG2(call->data);
136
137 rc = udebug_go(t, call);
138 if (rc != EOK) {
139 IPC_SET_RETVAL(call->data, rc);
140 ipc_answer(&TASK->kb.box, call);
141 return;
142 }
143}
144
145/** Process a STOP call.
146 *
147 * Suspends execution of the specified thread.
148 * @param call The call structure.
149 */
150static void udebug_receive_stop(call_t *call)
151{
152 thread_t *t;
153 errno_t rc;
154
155 t = (thread_t *)IPC_GET_ARG2(call->data);
156
157 rc = udebug_stop(t, call);
158 IPC_SET_RETVAL(call->data, rc);
159 ipc_answer(&TASK->kb.box, call);
160}
161
162/** Process a THREAD_READ call.
163 *
164 * Reads the list of hashes of the (userspace) threads in the current task.
165 * @param call The call structure.
166 */
167static void udebug_receive_thread_read(call_t *call)
168{
169 uintptr_t uspace_addr;
170 size_t buf_size;
171 void *buffer;
172 size_t copied, needed;
173 errno_t rc;
174
175 uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
176 buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
177
178 /*
179 * Read thread list. Variable n will be filled with actual number
180 * of threads times thread-id size.
181 */
182 rc = udebug_thread_read(&buffer, buf_size, &copied, &needed);
183 if (rc != EOK) {
184 IPC_SET_RETVAL(call->data, rc);
185 ipc_answer(&TASK->kb.box, call);
186 return;
187 }
188
189 /*
190 * Make use of call->buffer to transfer data to caller's userspace
191 */
192
193 IPC_SET_RETVAL(call->data, 0);
194 /*
195 * ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
196 * same code in process_answer() can be used
197 * (no way to distinguish method in answer)
198 */
199 IPC_SET_ARG1(call->data, uspace_addr);
200 IPC_SET_ARG2(call->data, copied);
201 IPC_SET_ARG3(call->data, needed);
202 call->buffer = buffer;
203
204 ipc_answer(&TASK->kb.box, call);
205}
206
207/** Process a NAME_READ call.
208 *
209 * Returns a string containing the name of the task.
210 *
211 * @param call The call structure.
212 */
213static void udebug_receive_name_read(call_t *call)
214{
215 sysarg_t uspace_addr;
216 sysarg_t to_copy;
217 size_t data_size;
218 size_t buf_size;
219 void *data;
220
221 uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
222 buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
223
224 /*
225 * Read task name.
226 */
227 udebug_name_read((char **) &data, &data_size);
228
229 /* Copy MAX(buf_size, data_size) bytes */
230
231 if (buf_size > data_size)
232 to_copy = data_size;
233 else
234 to_copy = buf_size;
235
236 /*
237 * Make use of call->buffer to transfer data to caller's userspace
238 */
239
240 IPC_SET_RETVAL(call->data, 0);
241 /*
242 * ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
243 * same code in process_answer() can be used
244 * (no way to distinguish method in answer)
245 */
246 IPC_SET_ARG1(call->data, uspace_addr);
247 IPC_SET_ARG2(call->data, to_copy);
248
249 IPC_SET_ARG3(call->data, data_size);
250 call->buffer = data;
251
252 ipc_answer(&TASK->kb.box, call);
253}
254
255/** Process an AREAS_READ call.
256 *
257 * Returns a list of address space areas in the current task, as an array
258 * of as_area_info_t structures.
259 *
260 * @param call The call structure.
261 */
262static void udebug_receive_areas_read(call_t *call)
263{
264 sysarg_t uspace_addr;
265 sysarg_t to_copy;
266 size_t data_size;
267 size_t buf_size;
268 as_area_info_t *data;
269
270 uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
271 buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
272
273 /*
274 * Read area list.
275 */
276 data = as_get_area_info(AS, &data_size);
277 if (!data) {
278 IPC_SET_RETVAL(call->data, ENOMEM);
279 ipc_answer(&TASK->kb.box, call);
280 return;
281 }
282
283 /* Copy MAX(buf_size, data_size) bytes */
284
285 if (buf_size > data_size)
286 to_copy = data_size;
287 else
288 to_copy = buf_size;
289
290 /*
291 * Make use of call->buffer to transfer data to caller's userspace
292 */
293
294 IPC_SET_RETVAL(call->data, 0);
295 /*
296 * ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
297 * same code in process_answer() can be used
298 * (no way to distinguish method in answer)
299 */
300 IPC_SET_ARG1(call->data, uspace_addr);
301 IPC_SET_ARG2(call->data, to_copy);
302
303 IPC_SET_ARG3(call->data, data_size);
304 call->buffer = (uint8_t *) data;
305
306 ipc_answer(&TASK->kb.box, call);
307}
308
309/** Process an ARGS_READ call.
310 *
311 * Reads the argument of a current syscall event (SYSCALL_B or SYSCALL_E).
312 * @param call The call structure.
313 */
314static void udebug_receive_args_read(call_t *call)
315{
316 thread_t *t;
317 sysarg_t uspace_addr;
318 errno_t rc;
319 void *buffer;
320
321 t = (thread_t *)IPC_GET_ARG2(call->data);
322
323 rc = udebug_args_read(t, &buffer);
324 if (rc != EOK) {
325 IPC_SET_RETVAL(call->data, rc);
326 ipc_answer(&TASK->kb.box, call);
327 return;
328 }
329
330 /*
331 * Make use of call->buffer to transfer data to caller's userspace
332 */
333
334 uspace_addr = IPC_GET_ARG3(call->data);
335
336 IPC_SET_RETVAL(call->data, 0);
337 /*
338 * ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
339 * same code in process_answer() can be used
340 * (no way to distinguish method in answer)
341 */
342 IPC_SET_ARG1(call->data, uspace_addr);
343 IPC_SET_ARG2(call->data, 6 * sizeof(sysarg_t));
344 call->buffer = buffer;
345
346 ipc_answer(&TASK->kb.box, call);
347}
348
349/** Receive a REGS_READ call.
350 *
351 * Reads the thread's register state (istate structure).
352 */
353static void udebug_receive_regs_read(call_t *call)
354{
355 thread_t *t;
356 sysarg_t uspace_addr;
357 sysarg_t to_copy;
358 void *buffer = NULL;
359 errno_t rc;
360
361 t = (thread_t *) IPC_GET_ARG2(call->data);
362
363 rc = udebug_regs_read(t, &buffer);
364 if (rc != EOK) {
365 IPC_SET_RETVAL(call->data, rc);
366 ipc_answer(&TASK->kb.box, call);
367 return;
368 }
369
370 assert(buffer != NULL);
371
372 /*
373 * Make use of call->buffer to transfer data to caller's userspace
374 */
375
376 uspace_addr = IPC_GET_ARG3(call->data);
377 to_copy = sizeof(istate_t);
378
379 IPC_SET_RETVAL(call->data, 0);
380 /*
381 * ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
382 * same code in process_answer() can be used
383 * (no way to distinguish method in answer)
384 */
385 IPC_SET_ARG1(call->data, uspace_addr);
386 IPC_SET_ARG2(call->data, to_copy);
387
388 call->buffer = buffer;
389
390 ipc_answer(&TASK->kb.box, call);
391}
392
393/** Process an MEM_READ call.
394 *
395 * Reads memory of the current (debugged) task.
396 * @param call The call structure.
397 */
398static void udebug_receive_mem_read(call_t *call)
399{
400 sysarg_t uspace_dst;
401 sysarg_t uspace_src;
402 unsigned size;
403 void *buffer = NULL;
404 errno_t rc;
405
406 uspace_dst = IPC_GET_ARG2(call->data);
407 uspace_src = IPC_GET_ARG3(call->data);
408 size = IPC_GET_ARG4(call->data);
409
410 rc = udebug_mem_read(uspace_src, size, &buffer);
411 if (rc != EOK) {
412 IPC_SET_RETVAL(call->data, rc);
413 ipc_answer(&TASK->kb.box, call);
414 return;
415 }
416
417 assert(buffer != NULL);
418
419 IPC_SET_RETVAL(call->data, 0);
420 /*
421 * ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
422 * same code in process_answer() can be used
423 * (no way to distinguish method in answer)
424 */
425 IPC_SET_ARG1(call->data, uspace_dst);
426 IPC_SET_ARG2(call->data, size);
427 call->buffer = buffer;
428
429 ipc_answer(&TASK->kb.box, call);
430}
431
432/** Handle a debug call received on the kernel answerbox.
433 *
434 * This is called by the kbox servicing thread. Verifies that the sender
435 * is indeed the debugger and calls the appropriate processing function.
436 */
437void udebug_call_receive(call_t *call)
438{
439 int debug_method;
440
441 debug_method = IPC_GET_ARG1(call->data);
442
443 if (debug_method != UDEBUG_M_BEGIN) {
444 /*
445 * Verify that the sender is this task's debugger.
446 * Note that this is the only thread that could change
447 * TASK->debugger. Therefore no locking is necessary
448 * and the sender can be safely considered valid until
449 * control exits this function.
450 */
451 if (TASK->udebug.debugger != call->sender) {
452 IPC_SET_RETVAL(call->data, EINVAL);
453 ipc_answer(&TASK->kb.box, call);
454 return;
455 }
456 }
457
458 switch (debug_method) {
459 case UDEBUG_M_BEGIN:
460 udebug_receive_begin(call);
461 break;
462 case UDEBUG_M_END:
463 udebug_receive_end(call);
464 break;
465 case UDEBUG_M_SET_EVMASK:
466 udebug_receive_set_evmask(call);
467 break;
468 case UDEBUG_M_GO:
469 udebug_receive_go(call);
470 break;
471 case UDEBUG_M_STOP:
472 udebug_receive_stop(call);
473 break;
474 case UDEBUG_M_THREAD_READ:
475 udebug_receive_thread_read(call);
476 break;
477 case UDEBUG_M_NAME_READ:
478 udebug_receive_name_read(call);
479 break;
480 case UDEBUG_M_AREAS_READ:
481 udebug_receive_areas_read(call);
482 break;
483 case UDEBUG_M_ARGS_READ:
484 udebug_receive_args_read(call);
485 break;
486 case UDEBUG_M_REGS_READ:
487 udebug_receive_regs_read(call);
488 break;
489 case UDEBUG_M_MEM_READ:
490 udebug_receive_mem_read(call);
491 break;
492 }
493}
494
495/** @}
496 */
Note: See TracBrowser for help on using the repository browser.