Subversion Repositories HelenOS

Rev

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