Subversion Repositories HelenOS

Rev

Rev 2870 | Rev 2886 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2813 svoboda 1
/** @addtogroup generic
2
 * @{
3
 */
4
 
5
/**
6
 * @file
7
 * @brief   Tdebug.
8
 */
9
 
10
#include <console/klog.h>
11
#include <proc/task.h>
12
#include <proc/thread.h>
2815 svoboda 13
#include <arch.h>
2813 svoboda 14
#include <errno.h>
15
#include <ipc/ipc.h>
16
#include <syscall/copy.h>
17
#include <udebug/udebug.h>
18
#include <udebug/udebug_ipc.h>
19
 
2823 svoboda 20
/**
2849 svoboda 21
 * Get a phone's callee task id.
2823 svoboda 22
 *
2849 svoboda 23
 * This will return the id of the task to which the phone
24
 * is connected.
2848 svoboda 25
 *
26
 * Interrupts must be already disabled.
2823 svoboda 27
 */
2849 svoboda 28
static task_id_t get_callee_task_id(phone_t *phone)
2813 svoboda 29
{
2823 svoboda 30
    answerbox_t *box;
31
    task_id_t taskid;
2813 svoboda 32
 
2823 svoboda 33
    spinlock_lock(&phone->lock);
34
    if (phone->state != IPC_PHONE_CONNECTED) {
35
        spinlock_unlock(&phone->lock);
36
        return NULL;
37
    }
2813 svoboda 38
 
2823 svoboda 39
    box = phone->callee;
40
 
41
    spinlock_lock(&box->lock);
2849 svoboda 42
    taskid = box->task->taskid;
2823 svoboda 43
    spinlock_unlock(&box->lock);
44
    spinlock_unlock(&phone->lock);
2813 svoboda 45
 
2849 svoboda 46
    return taskid;
47
}
48
 
49
/**
50
 * Prepare a thread for a debugging operation.
2842 svoboda 51
 *
2849 svoboda 52
 * Simply put, return thread t with t->debug_lock held,
53
 * but only if it verifies all conditions.
2842 svoboda 54
 *
2849 svoboda 55
 * Specifically, verifies that thread t exists, is a userspace thread,
56
 * belongs to the callee of 'phone'. It also locks t->debug_lock,
57
 * making sure that t->debug_active is true - that the thread is
58
 * in a valid debugging session.
59
 *
60
 * Returns EOK if all went well, or an error code otherwise.
61
 * Interrupts must be already disabled when calling this function.
62
 *
63
 * Note: This function sports complicated locking.
2842 svoboda 64
 */
2849 svoboda 65
static int _thread_op_begin(phone_t *phone, thread_t *t)
2841 svoboda 66
{
2849 svoboda 67
    int rc;
68
    task_id_t taskid;
69
    int task_match;
70
    DEADLOCK_PROBE_INIT(p_tasklock);
71
 
72
    taskid = get_callee_task_id(phone);
73
 
74
    /* Need to lock down the thread and than it's owner task */
75
grab_locks:
76
    spinlock_lock(&threads_lock);
77
 
78
    if (!thread_exists(t)) {
79
        spinlock_unlock(&threads_lock);
2841 svoboda 80
        return ENOENT;
81
    }
82
 
2849 svoboda 83
    spinlock_lock(&t->debug_lock);
84
    spinlock_lock(&t->lock);
85
 
86
    if (!spinlock_trylock(&t->task->lock)) {
87
        spinlock_unlock(&t->lock);
88
        spinlock_unlock(&t->debug_lock);
89
        DEADLOCK_PROBE(p_tasklock, DEADLOCK_THRESHOLD);
90
        goto grab_locks;    /* avoid deadlock */
91
    }
92
 
93
    /* Now verify that it's the callee */
94
    task_match = (t->task->taskid == taskid);
95
 
96
    spinlock_unlock(&t->task->lock);
97
 
98
    if (!task_match) {
99
        /* No such thread belonging to callee */
100
        rc = ENOENT;
101
        goto error_exit;
102
    }
103
 
2842 svoboda 104
    /* Verify that 't' is a userspace thread */
2841 svoboda 105
    if ((t->flags & THREAD_FLAG_USPACE) == 0) {
106
        /* It's not, deny its existence */
2849 svoboda 107
        rc = ENOENT;
108
        goto error_exit;
2841 svoboda 109
    }
110
 
111
    if ((t->debug_active != true) || (t->debug_stop != true)) {
112
        /* Not in debugging session or already has GO */
2849 svoboda 113
        rc = ENOENT;
114
        goto error_exit;
2841 svoboda 115
    }
116
 
2849 svoboda 117
    spinlock_unlock(&threads_lock);
118
    spinlock_unlock(&t->lock);
119
 
120
    /* Only t->debug_lock left */
121
 
122
    return EOK; /* All went well */
123
 
124
 
125
    /* Executed when a check on the thread fails */
126
error_exit:
127
    spinlock_unlock(&t->lock);
128
    spinlock_unlock(&t->debug_lock);
129
    spinlock_unlock(&threads_lock);
130
 
131
    /* No locks left here */
132
    return rc;  /* Some errors occured */
2841 svoboda 133
}
134
 
2849 svoboda 135
static void _thread_op_end(thread_t *t)
136
{
137
    spinlock_unlock(&t->debug_lock);
138
}
139
 
2813 svoboda 140
static int udebug_rp_go(call_t *call, phone_t *phone)
141
{
142
    thread_t *t;
2823 svoboda 143
    ipl_t ipl;
2848 svoboda 144
    int rc;
2813 svoboda 145
 
146
    klog_printf("debug_go()");
2848 svoboda 147
 
2849 svoboda 148
    t = (thread_t *)IPC_GET_ARG2(call->data);
149
 
2848 svoboda 150
    ipl = interrupts_disable();
151
 
2849 svoboda 152
    /* On success, this will lock t->debug_lock */
153
    rc = _thread_op_begin(phone, t);
2848 svoboda 154
    if (rc != EOK) {
155
        interrupts_restore(ipl);
156
        return rc;
157
    }
158
 
2826 svoboda 159
    t->debug_go_call = call;
2825 svoboda 160
    t->debug_stop = false;
2866 svoboda 161
    t->cur_event = 0;   /* none */
2848 svoboda 162
 
163
    /*
164
     * Neither t's lock nor threads_lock may be held during wakeup
165
     */
2813 svoboda 166
    waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
2825 svoboda 167
 
2849 svoboda 168
    _thread_op_end(t);
2823 svoboda 169
    interrupts_restore(ipl);
2813 svoboda 170
 
171
    return 0; /* no backsend */
172
}
173
 
174
static int udebug_rp_args_read(call_t *call, phone_t *phone)
175
{
176
    thread_t *t;
177
    void *uspace_buffer;
178
    int rc;
2823 svoboda 179
    ipl_t ipl;
2827 svoboda 180
    unative_t buffer[6];
2813 svoboda 181
 
182
    klog_printf("debug_args_read()");
183
 
2849 svoboda 184
    t = (thread_t *)IPC_GET_ARG2(call->data);
185
 
2848 svoboda 186
    ipl = interrupts_disable();
2823 svoboda 187
 
2849 svoboda 188
    /* On success, this will lock t->debug_lock */
189
    rc = _thread_op_begin(phone, t);
2841 svoboda 190
    if (rc != EOK) {
2823 svoboda 191
        interrupts_restore(ipl);
2841 svoboda 192
        return rc;
2813 svoboda 193
    }
194
 
2866 svoboda 195
    /* Additionally we need to verify that we are inside a syscall */
196
    if (t->cur_event != UDEBUG_EVENT_SYSCALL) {
197
        _thread_op_end(t);
198
        interrupts_restore(ipl);
199
        return EINVAL;
200
    }
2827 svoboda 201
 
202
    /* Copy to a local buffer before releasing the lock */
203
    memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t));
204
 
2849 svoboda 205
    _thread_op_end(t);
2823 svoboda 206
    interrupts_restore(ipl);
207
 
2827 svoboda 208
    /* Now copy to userspace */
209
 
2813 svoboda 210
    uspace_buffer = (void *)IPC_GET_ARG3(call->data);
211
 
2833 svoboda 212
    rc = copy_to_uspace(uspace_buffer, buffer, 6 * sizeof(unative_t));
2813 svoboda 213
    if (rc != 0) {
214
        klog_printf("debug_args_read() - copy failed");
215
        return rc;
216
    }
217
 
218
    klog_printf("debug_args_read() done");
219
    return 1; /* actually need becksend with retval 0 */
220
}
221
 
2817 svoboda 222
static int udebug_rp_regs_read(call_t *call, phone_t *phone)
223
{
224
    thread_t *t;
225
    void *uspace_buffer;
226
    unative_t to_copy;
227
    int rc;
228
    istate_t *state;
2824 svoboda 229
    istate_t state_copy;
230
    ipl_t ipl;
2817 svoboda 231
 
232
    klog_printf("debug_regs_read()");
233
 
2849 svoboda 234
    t = (thread_t *) IPC_GET_ARG2(call->data);
2817 svoboda 235
 
2824 svoboda 236
    ipl = interrupts_disable();
237
 
2849 svoboda 238
    /* On success, this will lock t->debug_lock */
239
    rc = _thread_op_begin(phone, t);
2841 svoboda 240
    if (rc != EOK) {
2827 svoboda 241
        interrupts_restore(ipl);
2841 svoboda 242
        return rc;
2817 svoboda 243
    }
244
 
2824 svoboda 245
    state = t->uspace_state;
246
    if (state == NULL) {
2849 svoboda 247
        _thread_op_end(t);
2824 svoboda 248
        interrupts_restore(ipl);
249
        klog_printf("debug_regs_read() - istate not available");
250
        return EBUSY;
251
    }
252
 
253
    /* Copy to a local buffer so that we can release the lock */
254
    memcpy(&state_copy, state, sizeof(state_copy));
2849 svoboda 255
    _thread_op_end(t);
2824 svoboda 256
    interrupts_restore(ipl);
257
 
2817 svoboda 258
    uspace_buffer = (void *)IPC_GET_ARG3(call->data);
259
    to_copy = IPC_GET_ARG4(call->data);
260
    if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
261
 
2824 svoboda 262
    rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy);
2817 svoboda 263
    if (rc != 0) {
264
        klog_printf("debug_regs_read() - copy failed");
265
        return rc;
266
    }
267
 
268
    IPC_SET_ARG1(call->data, to_copy);
269
    IPC_SET_ARG2(call->data, sizeof(istate_t));
270
 
271
    klog_printf("debug_regs_read() done");
272
    return 1; /* actually need becksend with retval 0 */
273
}
274
 
2849 svoboda 275
 
276
 
2817 svoboda 277
static int udebug_rp_regs_write(call_t *call, phone_t *phone)
278
{
279
    thread_t *t;
280
    void *uspace_data;
281
    unative_t to_copy;
282
    int rc;
283
    istate_t *state;
2824 svoboda 284
    istate_t data_copy;
285
    ipl_t ipl;
2817 svoboda 286
 
287
    klog_printf("debug_regs_write()");
288
 
2824 svoboda 289
    /* First copy to a local buffer */
2817 svoboda 290
 
291
    uspace_data = (void *)IPC_GET_ARG3(call->data);
292
    to_copy = IPC_GET_ARG4(call->data);
293
    if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
294
 
2824 svoboda 295
    rc = copy_from_uspace(&data_copy, uspace_data, to_copy);
2817 svoboda 296
    if (rc != 0) {
297
        klog_printf("debug_regs_write() - copy failed");
298
        return rc;
299
    }
300
 
2824 svoboda 301
    /* Now try to change the thread's uspace_state */
302
 
303
    ipl = interrupts_disable();
304
    t = (thread_t *) IPC_GET_ARG2(call->data);
2827 svoboda 305
 
2849 svoboda 306
    /* On success, this will lock t->debug_lock */
307
    rc = _thread_op_begin(phone, t);
2841 svoboda 308
    if (rc != EOK) {
2824 svoboda 309
        interrupts_restore(ipl);
2841 svoboda 310
        return rc;
2824 svoboda 311
    }
312
 
313
    state = t->uspace_state;
314
    if (state == NULL) {
2849 svoboda 315
        _thread_op_end(t);
2824 svoboda 316
        interrupts_restore(ipl);
317
        klog_printf("debug_regs_write() - istate not available");
318
        return EBUSY;
319
    }
320
 
321
    memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state));
322
 
2849 svoboda 323
    _thread_op_end(t);
2824 svoboda 324
    interrupts_restore(ipl);
325
 
326
    /* Set answer values */
327
 
2817 svoboda 328
    IPC_SET_ARG1(call->data, to_copy);
329
    IPC_SET_ARG2(call->data, sizeof(istate_t));
330
 
331
    klog_printf("debug_regs_write() done");
332
    return 1; /* actually need becksend with retval 0 */
333
}
334
 
2885 svoboda 335
static int udebug_rp_mem_write(call_t *call, phone_t *phone)
2813 svoboda 336
{
2885 svoboda 337
    void *uspace_data;
338
    unative_t to_copy;
339
    int rc;
340
    void *buffer;
341
 
342
    klog_printf("udebug_rp_mem_write()");
343
 
344
    uspace_data = (void *)IPC_GET_ARG2(call->data);
345
    to_copy = IPC_GET_ARG4(call->data);
346
 
347
    buffer = malloc(to_copy, 0); // ???
348
 
349
    rc = copy_from_uspace(buffer, uspace_data, to_copy);
350
    if (rc != 0) {
351
        klog_printf(" - copy failed");
352
        return rc;
353
    }
354
 
355
    call->buffer = buffer;
356
 
357
    klog_printf(" - done");
358
    return 1; /* actually need becksend with retval 0 */
359
}
360
 
361
 
362
int udebug_request_preprocess(call_t *call, phone_t *phone)
363
{
364
    int rc;
365
 
366
    switch (IPC_GET_ARG1(call->data)) {
367
    case UDEBUG_M_GO:
368
        rc = udebug_rp_go(call, phone);
369
        return rc;
370
    case UDEBUG_M_ARGS_READ:
371
        rc = udebug_rp_args_read(call, phone);
372
        return rc;
373
    case UDEBUG_M_REGS_READ:
374
        rc = udebug_rp_regs_read(call, phone);
375
        return rc;
376
    case UDEBUG_M_REGS_WRITE:
377
        rc = udebug_rp_regs_write(call, phone);
378
        return rc;
379
    case UDEBUG_M_MEM_WRITE:
380
        rc = udebug_rp_mem_write(call, phone);
381
        return rc;
382
    default:
383
        break;
384
    }
385
 
386
    return 0;
387
}
388
 
389
static void udebug_receive_begin(call_t *call)
390
{
391
    ipl_t ipl;
392
    int reply;
393
 
2813 svoboda 394
    thread_t *t;
395
    link_t *cur;
2885 svoboda 396
 
397
    klog_printf("debug_begin()");
398
 
399
    ipl = interrupts_disable();
400
    klog_printf("debugging task %llu", TASK->taskid);
401
 
402
    spinlock_lock(&TASK->lock);
403
 
404
    if (TASK->dt_state != UDEBUG_TS_INACTIVE) {
405
        spinlock_unlock(&TASK->lock);
406
        interrupts_restore(ipl);
407
        klog_printf("debug_begin(): busy error");
408
 
409
        IPC_SET_RETVAL(call->data, EBUSY);
410
        ipc_answer(&TASK->kernel_box, call);
411
    }
412
 
413
    TASK->dt_state = UDEBUG_TS_BEGINNING;
414
    TASK->debug_begin_call = call;
415
    TASK->debugger = call->sender;
416
 
417
    if (TASK->not_stoppable_count == 0) {
418
        TASK->dt_state = UDEBUG_TS_ACTIVE;
419
        TASK->debug_begin_call = NULL;
420
        reply = 1; /* immediate reply */
421
    } else {
422
        reply = 0; /* no reply */
423
    }
424
 
425
    /* Set debug_active on all of the task's userspace threads */
426
 
427
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
428
        t = list_get_instance(cur, thread_t, th_link);
429
 
430
        spinlock_lock(&t->debug_lock);
431
        if ((t->flags & THREAD_FLAG_USPACE) != 0)
432
            t->debug_active = true;
433
        spinlock_unlock(&t->debug_lock);
434
    }
435
 
436
    spinlock_unlock(&TASK->lock);
437
    interrupts_restore(ipl);
438
 
439
    klog_printf("debug_begin() done (%s)",
440
        reply ? "reply" : "stoppability wait");
441
 
442
    if (reply) ipc_answer(&TASK->kernel_box, call);
443
}
444
 
445
static void udebug_receive_end(call_t *call)
446
{
447
    ipl_t ipl;
448
    int rc;
449
 
450
    klog_printf("udebug_receive_end()");
451
 
452
    ipl = interrupts_disable();
453
    spinlock_lock(&TASK->lock);
454
 
455
    rc = udebug_task_cleanup(TASK);
456
 
457
    klog_printf("task %llu", TASK->taskid);
458
 
459
    spinlock_unlock(&TASK->lock);
460
    interrupts_restore(ipl);
461
 
462
    if (rc < 0) {
463
        IPC_SET_RETVAL(call->data, EINVAL);
464
        ipc_answer(&TASK->kernel_box, call);
465
        return;
466
    }
467
 
468
    IPC_SET_RETVAL(call->data, 0);
469
    ipc_answer(&TASK->kernel_box, call);
470
}
471
 
472
static void udebug_receive_thread_read(call_t *call)
473
{
474
    thread_t *t;
475
    link_t *cur;
476
    unative_t uspace_addr;
2813 svoboda 477
    unative_t to_copy;
2824 svoboda 478
    unsigned total_bytes;
2813 svoboda 479
    unsigned buf_size;
480
    unative_t tid;
2824 svoboda 481
    unsigned num_threads, copied_ids;
482
    ipl_t ipl;
483
    unative_t *buffer;
484
    int flags;
2813 svoboda 485
 
486
    klog_printf("debug_thread_read()");
487
 
2824 svoboda 488
    ipl = interrupts_disable();
2885 svoboda 489
    spinlock_lock(&TASK->lock);
2813 svoboda 490
 
2827 svoboda 491
    /* Verify task state */
2885 svoboda 492
    if (TASK->dt_state != UDEBUG_TS_ACTIVE) {
493
        spinlock_unlock(&TASK->lock);
2827 svoboda 494
        interrupts_restore(ipl);
2885 svoboda 495
 
496
        IPC_SET_RETVAL(call->data, EINVAL);
497
        ipc_answer(&TASK->kernel_box, call);
498
        return;
2827 svoboda 499
    }
500
 
2824 svoboda 501
    /* Count the threads first */
502
 
503
    num_threads = 0;
2885 svoboda 504
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
2824 svoboda 505
        /* Count all threads, to be on the safe side */
506
        ++num_threads;
507
    }
508
 
509
    /* Allocate a buffer and copy down the threads' ids */
510
    buffer = malloc(num_threads * sizeof(unative_t), 0); // ???
511
 
512
    copied_ids = 0;
2885 svoboda 513
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
2813 svoboda 514
        t = list_get_instance(cur, thread_t, th_link);
515
 
2824 svoboda 516
        spinlock_lock(&t->lock);
517
        flags = t->flags;
518
        spinlock_unlock(&t->lock);
519
 
2813 svoboda 520
        /* Not interested in kernel threads */
2824 svoboda 521
        if ((flags & THREAD_FLAG_USPACE) != 0) {
522
            /* Using thread struct pointer for identification */
523
            tid = (unative_t) t;
524
            buffer[copied_ids++] = tid;
525
        }
526
    }
2813 svoboda 527
 
2885 svoboda 528
    spinlock_unlock(&TASK->lock);
2824 svoboda 529
    interrupts_restore(ipl);
2813 svoboda 530
 
2885 svoboda 531
    /*
532
     * Prepare data and send it back through call->buffer
533
     */
2813 svoboda 534
 
2885 svoboda 535
    uspace_addr = IPC_GET_ARG2(call->data);
2824 svoboda 536
    buf_size = IPC_GET_ARG3(call->data);
2813 svoboda 537
 
2824 svoboda 538
    total_bytes = copied_ids * sizeof(unative_t);
539
 
540
    if (buf_size > total_bytes)
541
        to_copy = total_bytes;
542
    else
543
        to_copy = buf_size;
544
 
2885 svoboda 545
    IPC_SET_RETVAL(call->data, 0);
546
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
547
       same code in process_answer() can be used
548
       (no way to distinguish method in answer) */
549
    IPC_SET_ARG1(call->data, uspace_addr);
550
    IPC_SET_ARG2(call->data, to_copy);
2824 svoboda 551
 
2885 svoboda 552
    IPC_SET_ARG3(call->data, total_bytes);
553
    call->buffer = (void *)buffer;
2813 svoboda 554
 
2885 svoboda 555
    ipc_answer(&TASK->kernel_box, call);
2813 svoboda 556
}
557
 
2818 svoboda 558
 
2815 svoboda 559
static void udebug_receive_mem_read(call_t *call)
560
{
561
    unative_t uspace_dst;
562
    void *uspace_ptr;
563
    unsigned size;
564
    void *buffer;
565
    int rc;
2813 svoboda 566
 
2815 svoboda 567
    klog_printf("debug_mem_read()");
568
    uspace_dst = IPC_GET_ARG2(call->data);
569
    uspace_ptr = (void *)IPC_GET_ARG3(call->data);
570
    size = IPC_GET_ARG4(call->data);
571
 
572
    buffer = malloc(size, 0); // ???
573
    klog_printf("debug_mem_read: src=%u, size=%u", uspace_ptr, size);
574
 
575
    /* NOTE: this is not strictly from a syscall... but that shouldn't
576
     * be a problem */
577
    rc = copy_from_uspace(buffer, uspace_ptr, size);
578
    if (rc) {
579
        IPC_SET_RETVAL(call->data, rc);
580
        return;
581
    }
582
 
583
    klog_printf("first word: %u", *((unative_t *)buffer));
584
 
585
    IPC_SET_RETVAL(call->data, 0);
586
    /* Hack: ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
587
       same code in process_answer() can be used
588
       (no way to distinguish method in answer) */
589
    IPC_SET_ARG1(call->data, uspace_dst);
590
    IPC_SET_ARG2(call->data, size);
591
    call->buffer = buffer;
592
 
593
    ipc_answer(&TASK->kernel_box, call);
594
}
595
 
2818 svoboda 596
static void udebug_receive_mem_write(call_t *call)
597
{
598
    void *uspace_dst;
599
    unsigned size;
600
    void *buffer;
601
    int rc;
2827 svoboda 602
    udebug_task_state_t dts;
2818 svoboda 603
 
604
    klog_printf("udebug_receive_mem_write()");
2827 svoboda 605
 
606
    /* Verify task state */
607
    spinlock_lock(&TASK->lock);
608
    dts = TASK->dt_state;
609
    spinlock_unlock(&TASK->lock);
610
 
611
    if (dts != UDEBUG_TS_ACTIVE) {
612
        IPC_SET_RETVAL(call->data, EBUSY);
613
        ipc_answer(&TASK->kernel_box, call);
614
        return;
615
    }
616
 
2818 svoboda 617
    uspace_dst = (void *)IPC_GET_ARG3(call->data);
618
    size = IPC_GET_ARG4(call->data);
619
 
620
    buffer = call->buffer;
621
    klog_printf("dst=%u, size=%u", uspace_dst, size);
622
 
623
    /* NOTE: this is not strictly from a syscall... but that shouldn't
624
     * be a problem */
625
    rc = copy_to_uspace(uspace_dst, buffer, size);
626
    if (rc) {
627
        IPC_SET_RETVAL(call->data, rc);
2827 svoboda 628
        ipc_answer(&TASK->kernel_box, call);
2818 svoboda 629
        return;
630
    }
631
 
632
    IPC_SET_RETVAL(call->data, 0);
633
 
634
    free(call->buffer);
635
    call->buffer = NULL;
636
 
637
    ipc_answer(&TASK->kernel_box, call);
638
}
639
 
640
 
2815 svoboda 641
/**
642
 * Handle a debug call received on the kernel answerbox.
643
 *
644
 * This is called by the kbox servicing thread.
645
 */
646
void udebug_call_receive(call_t *call)
647
{
648
    int debug_method;
649
 
650
    debug_method = IPC_GET_ARG1(call->data);
651
 
652
    switch (debug_method) {
2885 svoboda 653
    case UDEBUG_M_BEGIN:
654
        udebug_receive_begin(call);
655
        break;
656
    case UDEBUG_M_END:
657
        udebug_receive_end(call);
658
        break;
659
    case UDEBUG_M_THREAD_READ:
660
        udebug_receive_thread_read(call);
661
        break;
2815 svoboda 662
    case UDEBUG_M_MEM_READ:
663
        udebug_receive_mem_read(call);
664
        break;
2818 svoboda 665
    case UDEBUG_M_MEM_WRITE:
666
        udebug_receive_mem_write(call);
667
        break;
2815 svoboda 668
    }
669
}
670
 
2813 svoboda 671
/** @}
672
 */