source: mainline/kernel/generic/src/udebug/udebug_ipc.c@ 9233e9d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9233e9d was 63e27ef, checked in by Jiri Svoboda <jiri@…>, 8 years ago

ASSERT → assert

  • 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 <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
53int 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 int rc;
74
75 rc = udebug_begin(call);
76 if (rc < 0) {
77 IPC_SET_RETVAL(call->data, rc);
78 ipc_answer(&TASK->kb.box, call);
79 return;
80 }
81
82 /*
83 * If the initialization of the debugging session has finished,
84 * send a reply.
85 */
86 if (rc != 0) {
87 IPC_SET_RETVAL(call->data, 0);
88 ipc_answer(&TASK->kb.box, call);
89 }
90}
91
92/** Process an END call.
93 *
94 * Terminates the debugging session for the current task.
95 * @param call The call structure.
96 */
97static void udebug_receive_end(call_t *call)
98{
99 int rc;
100
101 rc = udebug_end();
102
103 IPC_SET_RETVAL(call->data, rc);
104 ipc_answer(&TASK->kb.box, call);
105}
106
107/** Process a SET_EVMASK call.
108 *
109 * Sets an event mask for the current debugging session.
110 * @param call The call structure.
111 */
112static void udebug_receive_set_evmask(call_t *call)
113{
114 int rc;
115 udebug_evmask_t mask;
116
117 mask = IPC_GET_ARG2(call->data);
118 rc = udebug_set_evmask(mask);
119
120 IPC_SET_RETVAL(call->data, rc);
121 ipc_answer(&TASK->kb.box, call);
122}
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 int rc;
134
135 t = (thread_t *)IPC_GET_ARG2(call->data);
136
137 rc = udebug_go(t, call);
138 if (rc < 0) {
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 int 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 int 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 < 0) {
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 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
195 same code in process_answer() can be used
196 (no way to distinguish method in answer) */
197 IPC_SET_ARG1(call->data, uspace_addr);
198 IPC_SET_ARG2(call->data, copied);
199 IPC_SET_ARG3(call->data, needed);
200 call->buffer = buffer;
201
202 ipc_answer(&TASK->kb.box, call);
203}
204
205/** Process a NAME_READ call.
206 *
207 * Returns a string containing the name of the task.
208 *
209 * @param call The call structure.
210 */
211static void udebug_receive_name_read(call_t *call)
212{
213 sysarg_t uspace_addr;
214 sysarg_t to_copy;
215 size_t data_size;
216 size_t buf_size;
217 void *data;
218
219 uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
220 buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
221
222 /*
223 * Read task name.
224 */
225 udebug_name_read((char **) &data, &data_size);
226
227 /* Copy MAX(buf_size, data_size) bytes */
228
229 if (buf_size > data_size)
230 to_copy = data_size;
231 else
232 to_copy = buf_size;
233
234 /*
235 * Make use of call->buffer to transfer data to caller's userspace
236 */
237
238 IPC_SET_RETVAL(call->data, 0);
239 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
240 same code in process_answer() can be used
241 (no way to distinguish method in answer) */
242 IPC_SET_ARG1(call->data, uspace_addr);
243 IPC_SET_ARG2(call->data, to_copy);
244
245 IPC_SET_ARG3(call->data, data_size);
246 call->buffer = data;
247
248 ipc_answer(&TASK->kb.box, call);
249}
250
251/** Process an AREAS_READ call.
252 *
253 * Returns a list of address space areas in the current task, as an array
254 * of as_area_info_t structures.
255 *
256 * @param call The call structure.
257 */
258static void udebug_receive_areas_read(call_t *call)
259{
260 sysarg_t uspace_addr;
261 sysarg_t to_copy;
262 size_t data_size;
263 size_t buf_size;
264 void *data;
265
266 uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
267 buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
268
269 /*
270 * Read area list.
271 */
272 as_get_area_info(AS, (as_area_info_t **) &data, &data_size);
273
274 /* Copy MAX(buf_size, data_size) bytes */
275
276 if (buf_size > data_size)
277 to_copy = data_size;
278 else
279 to_copy = buf_size;
280
281 /*
282 * Make use of call->buffer to transfer data to caller's userspace
283 */
284
285 IPC_SET_RETVAL(call->data, 0);
286 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
287 same code in process_answer() can be used
288 (no way to distinguish method in answer) */
289 IPC_SET_ARG1(call->data, uspace_addr);
290 IPC_SET_ARG2(call->data, to_copy);
291
292 IPC_SET_ARG3(call->data, data_size);
293 call->buffer = data;
294
295 ipc_answer(&TASK->kb.box, call);
296}
297
298
299/** Process an ARGS_READ call.
300 *
301 * Reads the argument of a current syscall event (SYSCALL_B or SYSCALL_E).
302 * @param call The call structure.
303 */
304static void udebug_receive_args_read(call_t *call)
305{
306 thread_t *t;
307 sysarg_t uspace_addr;
308 int rc;
309 void *buffer;
310
311 t = (thread_t *)IPC_GET_ARG2(call->data);
312
313 rc = udebug_args_read(t, &buffer);
314 if (rc != EOK) {
315 IPC_SET_RETVAL(call->data, rc);
316 ipc_answer(&TASK->kb.box, call);
317 return;
318 }
319
320 /*
321 * Make use of call->buffer to transfer data to caller's userspace
322 */
323
324 uspace_addr = IPC_GET_ARG3(call->data);
325
326 IPC_SET_RETVAL(call->data, 0);
327 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
328 same code in process_answer() can be used
329 (no way to distinguish method in answer) */
330 IPC_SET_ARG1(call->data, uspace_addr);
331 IPC_SET_ARG2(call->data, 6 * sizeof(sysarg_t));
332 call->buffer = buffer;
333
334 ipc_answer(&TASK->kb.box, call);
335}
336
337/** Receive a REGS_READ call.
338 *
339 * Reads the thread's register state (istate structure).
340 */
341static void udebug_receive_regs_read(call_t *call)
342{
343 thread_t *t;
344 sysarg_t uspace_addr;
345 sysarg_t to_copy;
346 void *buffer = NULL;
347 int rc;
348
349 t = (thread_t *) IPC_GET_ARG2(call->data);
350
351 rc = udebug_regs_read(t, &buffer);
352 if (rc < 0) {
353 IPC_SET_RETVAL(call->data, rc);
354 ipc_answer(&TASK->kb.box, call);
355 return;
356 }
357
358 assert(buffer != NULL);
359
360 /*
361 * Make use of call->buffer to transfer data to caller's userspace
362 */
363
364 uspace_addr = IPC_GET_ARG3(call->data);
365 to_copy = sizeof(istate_t);
366
367 IPC_SET_RETVAL(call->data, 0);
368 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
369 same code in process_answer() can be used
370 (no way to distinguish method in answer) */
371 IPC_SET_ARG1(call->data, uspace_addr);
372 IPC_SET_ARG2(call->data, to_copy);
373
374 call->buffer = buffer;
375
376 ipc_answer(&TASK->kb.box, call);
377}
378
379
380/** Process an MEM_READ call.
381 *
382 * Reads memory of the current (debugged) task.
383 * @param call The call structure.
384 */
385static void udebug_receive_mem_read(call_t *call)
386{
387 sysarg_t uspace_dst;
388 sysarg_t uspace_src;
389 unsigned size;
390 void *buffer = NULL;
391 int rc;
392
393 uspace_dst = IPC_GET_ARG2(call->data);
394 uspace_src = IPC_GET_ARG3(call->data);
395 size = IPC_GET_ARG4(call->data);
396
397 rc = udebug_mem_read(uspace_src, size, &buffer);
398 if (rc < 0) {
399 IPC_SET_RETVAL(call->data, rc);
400 ipc_answer(&TASK->kb.box, call);
401 return;
402 }
403
404 assert(buffer != NULL);
405
406 IPC_SET_RETVAL(call->data, 0);
407 /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
408 same code in process_answer() can be used
409 (no way to distinguish method in answer) */
410 IPC_SET_ARG1(call->data, uspace_dst);
411 IPC_SET_ARG2(call->data, size);
412 call->buffer = buffer;
413
414 ipc_answer(&TASK->kb.box, call);
415}
416
417/** Handle a debug call received on the kernel answerbox.
418 *
419 * This is called by the kbox servicing thread. Verifies that the sender
420 * is indeed the debugger and calls the appropriate processing function.
421 */
422void udebug_call_receive(call_t *call)
423{
424 int debug_method;
425
426 debug_method = IPC_GET_ARG1(call->data);
427
428 if (debug_method != UDEBUG_M_BEGIN) {
429 /*
430 * Verify that the sender is this task's debugger.
431 * Note that this is the only thread that could change
432 * TASK->debugger. Therefore no locking is necessary
433 * and the sender can be safely considered valid until
434 * control exits this function.
435 */
436 if (TASK->udebug.debugger != call->sender) {
437 IPC_SET_RETVAL(call->data, EINVAL);
438 ipc_answer(&TASK->kb.box, call);
439 return;
440 }
441 }
442
443 switch (debug_method) {
444 case UDEBUG_M_BEGIN:
445 udebug_receive_begin(call);
446 break;
447 case UDEBUG_M_END:
448 udebug_receive_end(call);
449 break;
450 case UDEBUG_M_SET_EVMASK:
451 udebug_receive_set_evmask(call);
452 break;
453 case UDEBUG_M_GO:
454 udebug_receive_go(call);
455 break;
456 case UDEBUG_M_STOP:
457 udebug_receive_stop(call);
458 break;
459 case UDEBUG_M_THREAD_READ:
460 udebug_receive_thread_read(call);
461 break;
462 case UDEBUG_M_NAME_READ:
463 udebug_receive_name_read(call);
464 break;
465 case UDEBUG_M_AREAS_READ:
466 udebug_receive_areas_read(call);
467 break;
468 case UDEBUG_M_ARGS_READ:
469 udebug_receive_args_read(call);
470 break;
471 case UDEBUG_M_REGS_READ:
472 udebug_receive_regs_read(call);
473 break;
474 case UDEBUG_M_MEM_READ:
475 udebug_receive_mem_read(call);
476 break;
477 }
478}
479
480/** @}
481 */
Note: See TracBrowser for help on using the repository browser.