source: mainline/kernel/generic/src/udebug/udebug_ipc.c@ 1b20da0

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

style: Remove trailing whitespace on non-empty lines, in certain file types.

Command used: tools/srepl '\([^[:space:]]\)\s\+$' '\1' -- *.c *.h *.py *.sh *.s *.S *.ag

  • Property mode set to 100644
File size: 11.3 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 <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
126/** Process a GO call.
127 *
128 * Resumes execution of the specified thread.
129 * @param call The call structure.
130 */
131static void udebug_receive_go(call_t *call)
132{
133 thread_t *t;
134 errno_t rc;
135
136 t = (thread_t *)IPC_GET_ARG2(call->data);
137
138 rc = udebug_go(t, call);
139 if (rc != EOK) {
140 IPC_SET_RETVAL(call->data, rc);
141 ipc_answer(&TASK->kb.box, call);
142 return;
143 }
144}
145
146/** Process a STOP call.
147 *
148 * Suspends execution of the specified thread.
149 * @param call The call structure.
150 */
151static void udebug_receive_stop(call_t *call)
152{
153 thread_t *t;
154 errno_t rc;
155
156 t = (thread_t *)IPC_GET_ARG2(call->data);
157
158 rc = udebug_stop(t, call);
159 IPC_SET_RETVAL(call->data, rc);
160 ipc_answer(&TASK->kb.box, call);
161}
162
163/** Process a THREAD_READ call.
164 *
165 * Reads the list of hashes of the (userspace) threads in the current task.
166 * @param call The call structure.
167 */
168static void udebug_receive_thread_read(call_t *call)
169{
170 uintptr_t uspace_addr;
171 size_t buf_size;
172 void *buffer;
173 size_t copied, needed;
174 errno_t rc;
175
176 uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
177 buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
178
179 /*
180 * Read thread list. Variable n will be filled with actual number
181 * of threads times thread-id size.
182 */
183 rc = udebug_thread_read(&buffer, buf_size, &copied, &needed);
184 if (rc != EOK) {
185 IPC_SET_RETVAL(call->data, rc);
186 ipc_answer(&TASK->kb.box, call);
187 return;
188 }
189
190 /*
191 * Make use of call->buffer to transfer data to caller's userspace
192 */
193
194 IPC_SET_RETVAL(call->data, 0);
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 IPC_SET_ARG1(call->data, uspace_addr);
199 IPC_SET_ARG2(call->data, copied);
200 IPC_SET_ARG3(call->data, needed);
201 call->buffer = buffer;
202
203 ipc_answer(&TASK->kb.box, call);
204}
205
206/** Process a NAME_READ call.
207 *
208 * Returns a string containing the name of the task.
209 *
210 * @param call The call structure.
211 */
212static void udebug_receive_name_read(call_t *call)
213{
214 sysarg_t uspace_addr;
215 sysarg_t to_copy;
216 size_t data_size;
217 size_t buf_size;
218 void *data;
219
220 uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
221 buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
222
223 /*
224 * Read task name.
225 */
226 udebug_name_read((char **) &data, &data_size);
227
228 /* Copy MAX(buf_size, data_size) bytes */
229
230 if (buf_size > data_size)
231 to_copy = data_size;
232 else
233 to_copy = buf_size;
234
235 /*
236 * Make use of call->buffer to transfer data to caller's userspace
237 */
238
239 IPC_SET_RETVAL(call->data, 0);
240 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
241 same code in process_answer() can be used
242 (no way to distinguish method in answer) */
243 IPC_SET_ARG1(call->data, uspace_addr);
244 IPC_SET_ARG2(call->data, to_copy);
245
246 IPC_SET_ARG3(call->data, data_size);
247 call->buffer = data;
248
249 ipc_answer(&TASK->kb.box, call);
250}
251
252/** Process an AREAS_READ call.
253 *
254 * Returns a list of address space areas in the current task, as an array
255 * of as_area_info_t structures.
256 *
257 * @param call The call structure.
258 */
259static void udebug_receive_areas_read(call_t *call)
260{
261 sysarg_t uspace_addr;
262 sysarg_t to_copy;
263 size_t data_size;
264 size_t buf_size;
265 void *data;
266
267 uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
268 buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
269
270 /*
271 * Read area list.
272 */
273 as_get_area_info(AS, (as_area_info_t **) &data, &data_size);
274
275 /* Copy MAX(buf_size, data_size) bytes */
276
277 if (buf_size > data_size)
278 to_copy = data_size;
279 else
280 to_copy = buf_size;
281
282 /*
283 * Make use of call->buffer to transfer data to caller's userspace
284 */
285
286 IPC_SET_RETVAL(call->data, 0);
287 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
288 same code in process_answer() can be used
289 (no way to distinguish method in answer) */
290 IPC_SET_ARG1(call->data, uspace_addr);
291 IPC_SET_ARG2(call->data, to_copy);
292
293 IPC_SET_ARG3(call->data, data_size);
294 call->buffer = data;
295
296 ipc_answer(&TASK->kb.box, call);
297}
298
299
300/** Process an ARGS_READ call.
301 *
302 * Reads the argument of a current syscall event (SYSCALL_B or SYSCALL_E).
303 * @param call The call structure.
304 */
305static void udebug_receive_args_read(call_t *call)
306{
307 thread_t *t;
308 sysarg_t uspace_addr;
309 errno_t rc;
310 void *buffer;
311
312 t = (thread_t *)IPC_GET_ARG2(call->data);
313
314 rc = udebug_args_read(t, &buffer);
315 if (rc != EOK) {
316 IPC_SET_RETVAL(call->data, rc);
317 ipc_answer(&TASK->kb.box, call);
318 return;
319 }
320
321 /*
322 * Make use of call->buffer to transfer data to caller's userspace
323 */
324
325 uspace_addr = IPC_GET_ARG3(call->data);
326
327 IPC_SET_RETVAL(call->data, 0);
328 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
329 same code in process_answer() can be used
330 (no way to distinguish method in answer) */
331 IPC_SET_ARG1(call->data, uspace_addr);
332 IPC_SET_ARG2(call->data, 6 * sizeof(sysarg_t));
333 call->buffer = buffer;
334
335 ipc_answer(&TASK->kb.box, call);
336}
337
338/** Receive a REGS_READ call.
339 *
340 * Reads the thread's register state (istate structure).
341 */
342static void udebug_receive_regs_read(call_t *call)
343{
344 thread_t *t;
345 sysarg_t uspace_addr;
346 sysarg_t to_copy;
347 void *buffer = NULL;
348 errno_t rc;
349
350 t = (thread_t *) IPC_GET_ARG2(call->data);
351
352 rc = udebug_regs_read(t, &buffer);
353 if (rc != EOK) {
354 IPC_SET_RETVAL(call->data, rc);
355 ipc_answer(&TASK->kb.box, call);
356 return;
357 }
358
359 assert(buffer != NULL);
360
361 /*
362 * Make use of call->buffer to transfer data to caller's userspace
363 */
364
365 uspace_addr = IPC_GET_ARG3(call->data);
366 to_copy = sizeof(istate_t);
367
368 IPC_SET_RETVAL(call->data, 0);
369 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
370 same code in process_answer() can be used
371 (no way to distinguish method in answer) */
372 IPC_SET_ARG1(call->data, uspace_addr);
373 IPC_SET_ARG2(call->data, to_copy);
374
375 call->buffer = buffer;
376
377 ipc_answer(&TASK->kb.box, call);
378}
379
380
381/** Process an MEM_READ call.
382 *
383 * Reads memory of the current (debugged) task.
384 * @param call The call structure.
385 */
386static void udebug_receive_mem_read(call_t *call)
387{
388 sysarg_t uspace_dst;
389 sysarg_t uspace_src;
390 unsigned size;
391 void *buffer = NULL;
392 errno_t rc;
393
394 uspace_dst = IPC_GET_ARG2(call->data);
395 uspace_src = IPC_GET_ARG3(call->data);
396 size = IPC_GET_ARG4(call->data);
397
398 rc = udebug_mem_read(uspace_src, size, &buffer);
399 if (rc != EOK) {
400 IPC_SET_RETVAL(call->data, rc);
401 ipc_answer(&TASK->kb.box, call);
402 return;
403 }
404
405 assert(buffer != NULL);
406
407 IPC_SET_RETVAL(call->data, 0);
408 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
409 same code in process_answer() can be used
410 (no way to distinguish method in answer) */
411 IPC_SET_ARG1(call->data, uspace_dst);
412 IPC_SET_ARG2(call->data, size);
413 call->buffer = buffer;
414
415 ipc_answer(&TASK->kb.box, call);
416}
417
418/** Handle a debug call received on the kernel answerbox.
419 *
420 * This is called by the kbox servicing thread. Verifies that the sender
421 * is indeed the debugger and calls the appropriate processing function.
422 */
423void udebug_call_receive(call_t *call)
424{
425 int debug_method;
426
427 debug_method = IPC_GET_ARG1(call->data);
428
429 if (debug_method != UDEBUG_M_BEGIN) {
430 /*
431 * Verify that the sender is this task's debugger.
432 * Note that this is the only thread that could change
433 * TASK->debugger. Therefore no locking is necessary
434 * and the sender can be safely considered valid until
435 * control exits this function.
436 */
437 if (TASK->udebug.debugger != call->sender) {
438 IPC_SET_RETVAL(call->data, EINVAL);
439 ipc_answer(&TASK->kb.box, call);
440 return;
441 }
442 }
443
444 switch (debug_method) {
445 case UDEBUG_M_BEGIN:
446 udebug_receive_begin(call);
447 break;
448 case UDEBUG_M_END:
449 udebug_receive_end(call);
450 break;
451 case UDEBUG_M_SET_EVMASK:
452 udebug_receive_set_evmask(call);
453 break;
454 case UDEBUG_M_GO:
455 udebug_receive_go(call);
456 break;
457 case UDEBUG_M_STOP:
458 udebug_receive_stop(call);
459 break;
460 case UDEBUG_M_THREAD_READ:
461 udebug_receive_thread_read(call);
462 break;
463 case UDEBUG_M_NAME_READ:
464 udebug_receive_name_read(call);
465 break;
466 case UDEBUG_M_AREAS_READ:
467 udebug_receive_areas_read(call);
468 break;
469 case UDEBUG_M_ARGS_READ:
470 udebug_receive_args_read(call);
471 break;
472 case UDEBUG_M_REGS_READ:
473 udebug_receive_regs_read(call);
474 break;
475 case UDEBUG_M_MEM_READ:
476 udebug_receive_mem_read(call);
477 break;
478 }
479}
480
481/** @}
482 */
Note: See TracBrowser for help on using the repository browser.