source: mainline/kernel/generic/src/udebug/udebug_ipc.c@ 5a5269d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5a5269d was 5a5269d, checked in by GitHub <noreply@…>, 6 years ago

Change type of uspace pointers in kernel from pointer type to numeric (#170)

From kernel's perspective, userspace addresses are not valid pointers,
and can only be used in calls to copy_to/from_uspace().
Therefore, we change the type of those arguments and variables to
uspace_addr_t which is an alias for sysarg_t.

This allows the compiler to catch accidental direct accesses to
userspace addresses.

Additionally, to avoid losing the type information in code,
a macro uspace_ptr(type) is used that translates to uspace_addr_t.
I makes no functional difference, but allows keeping the type information
in code in case we implement some sort of static checking for it in the future.

However, ccheck doesn't like that, so instead of using uspace_ptr(char),
we use uspace_ptr_char which is defined as
#define uspace_ptr_char uspace_ptr(char).

  • Property mode set to 100644
File size: 11.5 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 uspace_addr_t uspace_dst;
401 uspace_addr_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.