Subversion Repositories HelenOS

Rev

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

Rev Author Line No. Line
2894 svoboda 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
 
2887 svoboda 29
/** @addtogroup generic
30
 * @{
31
 */
32
 
33
/**
34
 * @file
2894 svoboda 35
 * @brief   Udebug operations.
3471 svoboda 36
 *
37
 * Udebug operations on tasks and threads are implemented here. The
38
 * functions defined here are called from the udebug_ipc module
39
 * when servicing udebug IPC messages.
2887 svoboda 40
 */
41
 
3471 svoboda 42
#include <debug.h>
2887 svoboda 43
#include <proc/task.h>
44
#include <proc/thread.h>
45
#include <arch.h>
46
#include <errno.h>
47
#include <syscall/copy.h>
48
#include <ipc/ipc.h>
49
#include <udebug/udebug.h>
50
#include <udebug/udebug_ops.h>
51
 
52
/**
53
 * Prepare a thread for a debugging operation.
54
 *
3018 svoboda 55
 * Simply put, return thread t with t->udebug.lock held,
2887 svoboda 56
 * but only if it verifies all conditions.
57
 *
58
 * Specifically, verifies that thread t exists, is a userspace thread,
2898 svoboda 59
 * and belongs to the current task (TASK). Verifies, that the thread
60
 * has (or hasn't) go according to having_go (typically false).
3026 svoboda 61
 * It also locks t->udebug.lock, making sure that t->udebug.debug_active
62
 * is true - that the thread is in a valid debugging session.
2887 svoboda 63
 *
3026 svoboda 64
 * With this verified and the t->udebug.lock mutex held, it is ensured
65
 * that the thread cannot leave the debugging session, let alone cease
66
 * to exist.
67
 *
68
 * In this function, holding the TASK->udebug.lock mutex prevents the
69
 * thread from leaving the debugging session, while relaxing from
70
 * the t->lock spinlock to the t->udebug.lock mutex.
71
 *
3471 svoboda 72
 * @param t     Pointer, need not at all be valid.
73
 * @param having_go Required thread state.
74
 *
2887 svoboda 75
 * Returns EOK if all went well, or an error code otherwise.
76
 */
2898 svoboda 77
static int _thread_op_begin(thread_t *t, bool having_go)
2887 svoboda 78
{
79
    task_id_t taskid;
3026 svoboda 80
    ipl_t ipl;
2887 svoboda 81
 
82
    taskid = TASK->taskid;
83
 
3026 svoboda 84
    mutex_lock(&TASK->udebug.lock);
85
 
86
    /* thread_exists() must be called with threads_lock held */
87
    ipl = interrupts_disable();
2887 svoboda 88
    spinlock_lock(&threads_lock);
89
 
90
    if (!thread_exists(t)) {
91
        spinlock_unlock(&threads_lock);
3026 svoboda 92
        interrupts_restore(ipl);
93
        mutex_unlock(&TASK->udebug.lock);
2887 svoboda 94
        return ENOENT;
95
    }
96
 
3026 svoboda 97
    /* t->lock is enough to ensure the thread's existence */
2887 svoboda 98
    spinlock_lock(&t->lock);
3026 svoboda 99
    spinlock_unlock(&threads_lock);
2887 svoboda 100
 
101
    /* Verify that 't' is a userspace thread */
102
    if ((t->flags & THREAD_FLAG_USPACE) == 0) {
103
        /* It's not, deny its existence */
3026 svoboda 104
        spinlock_unlock(&t->lock);
105
        interrupts_restore(ipl);
106
        mutex_unlock(&TASK->udebug.lock);
107
        return ENOENT;
2887 svoboda 108
    }
109
 
3026 svoboda 110
    /* Verify debugging state */
111
    if (t->udebug.debug_active != true) {
2898 svoboda 112
        /* Not in debugging session or undesired GO state */
3026 svoboda 113
        spinlock_unlock(&t->lock);
114
        interrupts_restore(ipl);
115
        mutex_unlock(&TASK->udebug.lock);
116
        return ENOENT;
2887 svoboda 117
    }
118
 
3026 svoboda 119
    /*
120
     * Since the thread has debug_active == true, TASK->udebug.lock
121
     * is enough to ensure its existence and that debug_active remains
122
     * true.
123
     */
2887 svoboda 124
    spinlock_unlock(&t->lock);
3026 svoboda 125
    interrupts_restore(ipl);
2887 svoboda 126
 
3026 svoboda 127
    /* Only mutex TASK->udebug.lock left */
128
 
129
    /* Now verify that the thread belongs to the current task */
130
    if (t->task != TASK) {
131
        /* No such thread belonging this task*/
132
        mutex_unlock(&TASK->udebug.lock);
133
        return ENOENT;
134
    }
2887 svoboda 135
 
3026 svoboda 136
    /*
137
     * Now we need to grab the thread's debug lock for synchronization
138
     * of the threads stoppability/stop state.
139
     */
140
    mutex_lock(&t->udebug.lock);
2887 svoboda 141
 
3026 svoboda 142
    /* The big task mutex is no longer needed */
143
    mutex_unlock(&TASK->udebug.lock);
2887 svoboda 144
 
3026 svoboda 145
    if (!t->udebug.stop != having_go) {
146
        /* Not in debugging session or undesired GO state */
147
        mutex_unlock(&t->udebug.lock);
148
        return EINVAL;
149
    }
2887 svoboda 150
 
3026 svoboda 151
    /* Only t->udebug.lock left */
152
 
153
    return EOK; /* All went well */
2887 svoboda 154
}
155
 
3471 svoboda 156
/** End debugging operation on a thread. */
2887 svoboda 157
static void _thread_op_end(thread_t *t)
158
{
3026 svoboda 159
    mutex_unlock(&t->udebug.lock);
2887 svoboda 160
}
161
 
3471 svoboda 162
/** Begin debugging the current task.
163
 *
164
 * Initiates a debugging session for the current task (and its threads).
165
 * When the debugging session has started a reply will be sent to the
166
 * UDEBUG_BEGIN call. This may happen immediately in this function if
167
 * all the threads in this task are stoppable at the moment and in this
168
 * case the function returns 1.
169
 *
170
 * Otherwise the function returns 0 and the reply will be sent as soon as
171
 * all the threads become stoppable (i.e. they can be considered stopped).
172
 *
173
 * @param call  The BEGIN call we are servicing.
174
 * @return  0 (OK, but not done yet), 1 (done) or negative error code.
2887 svoboda 175
 */
176
int udebug_begin(call_t *call)
177
{
178
    int reply;
179
 
180
    thread_t *t;
181
    link_t *cur;
182
 
3471 svoboda 183
    LOG("udebug_begin()\n");
2887 svoboda 184
 
3016 svoboda 185
    mutex_lock(&TASK->udebug.lock);
3471 svoboda 186
    LOG("debugging task %llu\n", TASK->taskid);
2887 svoboda 187
 
3014 svoboda 188
    if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
3016 svoboda 189
        mutex_unlock(&TASK->udebug.lock);
3471 svoboda 190
        LOG("udebug_begin(): busy error\n");
2887 svoboda 191
 
192
        return EBUSY;
193
    }
194
 
3014 svoboda 195
    TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
196
    TASK->udebug.begin_call = call;
197
    TASK->udebug.debugger = call->sender;
2887 svoboda 198
 
3014 svoboda 199
    if (TASK->udebug.not_stoppable_count == 0) {
200
        TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
201
        TASK->udebug.begin_call = NULL;
2887 svoboda 202
        reply = 1; /* immediate reply */
203
    } else {
204
        reply = 0; /* no reply */
205
    }
206
 
3018 svoboda 207
    /* Set udebug.debug_active on all of the task's userspace threads */
2887 svoboda 208
 
209
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
210
        t = list_get_instance(cur, thread_t, th_link);
211
 
3026 svoboda 212
        mutex_lock(&t->udebug.lock);
2887 svoboda 213
        if ((t->flags & THREAD_FLAG_USPACE) != 0)
3018 svoboda 214
            t->udebug.debug_active = true;
3026 svoboda 215
        mutex_unlock(&t->udebug.lock);
2887 svoboda 216
    }
217
 
3016 svoboda 218
    mutex_unlock(&TASK->udebug.lock);
2887 svoboda 219
 
3471 svoboda 220
    LOG("udebug_begin() done (%s)\n",
2887 svoboda 221
        reply ? "reply" : "stoppability wait");
222
 
223
    return reply;
224
}
225
 
3471 svoboda 226
/** Finish debugging the current task.
227
 *
228
 * Closes the debugging session for the current task.
229
 * @return Zero on success or negative error code.
230
 */
2887 svoboda 231
int udebug_end(void)
232
{
233
    int rc;
234
 
3471 svoboda 235
    LOG("udebug_end()\n");
2887 svoboda 236
 
3016 svoboda 237
    mutex_lock(&TASK->udebug.lock);
3471 svoboda 238
    LOG("task %" PRIu64 "\n", TASK->taskid);
2887 svoboda 239
 
240
    rc = udebug_task_cleanup(TASK);
241
 
3016 svoboda 242
    mutex_unlock(&TASK->udebug.lock);
2887 svoboda 243
 
3016 svoboda 244
    return rc;
2887 svoboda 245
}
246
 
3471 svoboda 247
/** Set the event mask.
248
 *
249
 * Sets the event mask that determines which events are enabled.
250
 *
251
 * @param mask  Or combination of events that should be enabled.
252
 * @return  Zero on success or negative error code.
253
 */
2899 svoboda 254
int udebug_set_evmask(udebug_evmask_t mask)
255
{
3471 svoboda 256
    LOG("udebug_set_mask()\n");
2899 svoboda 257
 
3016 svoboda 258
    mutex_lock(&TASK->udebug.lock);
2899 svoboda 259
 
3014 svoboda 260
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
3016 svoboda 261
        mutex_unlock(&TASK->udebug.lock);
3471 svoboda 262
        LOG("udebug_set_mask(): not active debuging session\n");
2899 svoboda 263
 
264
        return EINVAL;
265
    }
266
 
3014 svoboda 267
    TASK->udebug.evmask = mask;
2899 svoboda 268
 
3016 svoboda 269
    mutex_unlock(&TASK->udebug.lock);
2899 svoboda 270
 
271
    return 0;
272
}
273
 
3471 svoboda 274
/** Give thread GO.
275
 *
276
 * Upon recieving a go message, the thread is given GO. Having GO
277
 * means the thread is allowed to execute userspace code (until
278
 * a debugging event or STOP occurs, at which point the thread loses GO.
279
 *
280
 * @param t The thread to operate on (unlocked and need not be valid).
281
 * @param call  The GO call that we are servicing.
282
 */
2887 svoboda 283
int udebug_go(thread_t *t, call_t *call)
284
{
285
    int rc;
286
 
3018 svoboda 287
    /* On success, this will lock t->udebug.lock */
2898 svoboda 288
    rc = _thread_op_begin(t, false);
2887 svoboda 289
    if (rc != EOK) {
290
        return rc;
291
    }
292
 
3018 svoboda 293
    t->udebug.go_call = call;
294
    t->udebug.stop = false;
295
    t->udebug.cur_event = 0;    /* none */
2887 svoboda 296
 
297
    /*
298
     * Neither t's lock nor threads_lock may be held during wakeup
299
     */
3018 svoboda 300
    waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
2887 svoboda 301
 
302
    _thread_op_end(t);
303
 
304
    return 0;
305
}
306
 
3471 svoboda 307
/** Stop a thread (i.e. take its GO away)
308
 *
309
 * Generates a STOP event as soon as the thread becomes stoppable (i.e.
310
 * can be considered stopped).
311
 *
312
 * @param t The thread to operate on (unlocked and need not be valid).
313
 * @param call  The GO call that we are servicing.
314
 */
2898 svoboda 315
int udebug_stop(thread_t *t, call_t *call)
316
{
317
    int rc;
2887 svoboda 318
 
3471 svoboda 319
    LOG("udebug_stop()\n");
3016 svoboda 320
    mutex_lock(&TASK->udebug.lock);
2898 svoboda 321
 
322
    /*
3018 svoboda 323
     * On success, this will lock t->udebug.lock. Note that this makes sure
2898 svoboda 324
     * the thread is not stopped.
325
     */
326
    rc = _thread_op_begin(t, true);
327
    if (rc != EOK) {
328
        return rc;
329
    }
330
 
331
    /* Take GO away from the thread */
3018 svoboda 332
    t->udebug.stop = true;
2898 svoboda 333
 
3018 svoboda 334
    if (!t->udebug.stoppable) {
2898 svoboda 335
        /* Answer will be sent when the thread becomes stoppable */
336
        _thread_op_end(t);
337
        return 0;
338
    }
339
 
340
    /*
341
     * Answer GO call
342
     */
3471 svoboda 343
    LOG("udebug_stop - answering go call\n");
2898 svoboda 344
 
345
    /* Make sure nobody takes this call away from us */
3018 svoboda 346
    call = t->udebug.go_call;
347
    t->udebug.go_call = NULL;
2898 svoboda 348
 
349
    IPC_SET_RETVAL(call->data, 0);
350
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
3471 svoboda 351
    LOG("udebug_stop/ipc_answer\n");
2898 svoboda 352
 
3018 svoboda 353
    THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
3016 svoboda 354
 
2898 svoboda 355
    _thread_op_end(t);
356
 
357
    ipc_answer(&TASK->answerbox, call);
3016 svoboda 358
    mutex_unlock(&TASK->udebug.lock);
2898 svoboda 359
 
3471 svoboda 360
    LOG("udebog_stop/done\n");
2898 svoboda 361
    return 0;
362
}
363
 
3471 svoboda 364
/** Read the list of userspace threads in the current task.
365
 *
366
 * The list takes the form of a sequence of thread hashes (i.e. the pointers
367
 * to thread structures). A buffer of size @a buf_size is allocated and
368
 * a pointer to it written to @a buffer. The sequence of hashes is written
369
 * into this buffer.
370
 *
371
 * If the sequence is longer than @a buf_size bytes, only as much hashes
372
 * as can fit are copied. The number of thread hashes copied is stored
373
 * in @a n.
374
 *
375
 * The rationale for having @a buf_size is that this function is only
376
 * used for servicing the THREAD_READ message, which always specifies
377
 * a maximum size for the userspace buffer.
378
 *
379
 * @param buffer    The buffer for storing thread hashes.
380
 * @param buf_size  Buffer size in bytes.
381
 * @param n     The actual number of hashes copied will be stored here.
382
 */
2897 svoboda 383
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n)
2887 svoboda 384
{
385
    thread_t *t;
386
    link_t *cur;
387
    unative_t tid;
2897 svoboda 388
    unsigned copied_ids;
2887 svoboda 389
    ipl_t ipl;
390
    unative_t *id_buffer;
391
    int flags;
2897 svoboda 392
    size_t max_ids;
2887 svoboda 393
 
3471 svoboda 394
    LOG("udebug_thread_read()\n");
2887 svoboda 395
 
2897 svoboda 396
    /* Allocate a buffer to hold thread IDs */
397
    id_buffer = malloc(buf_size, 0);
398
 
3016 svoboda 399
    mutex_lock(&TASK->udebug.lock);
2887 svoboda 400
 
401
    /* Verify task state */
3014 svoboda 402
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
3016 svoboda 403
        mutex_unlock(&TASK->udebug.lock);
2887 svoboda 404
        return EINVAL;
405
    }
406
 
3016 svoboda 407
    ipl = interrupts_disable();
408
    spinlock_lock(&TASK->lock);
2897 svoboda 409
    /* Copy down the thread IDs */
2887 svoboda 410
 
2897 svoboda 411
    max_ids = buf_size / sizeof(unative_t);
412
    copied_ids = 0;
413
 
3026 svoboda 414
    /* FIXME: make sure the thread isn't past debug shutdown... */
2887 svoboda 415
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
2897 svoboda 416
        /* Do not write past end of buffer */
417
        if (copied_ids >= max_ids) break;
2887 svoboda 418
 
419
        t = list_get_instance(cur, thread_t, th_link);
420
 
421
        spinlock_lock(&t->lock);
422
        flags = t->flags;
423
        spinlock_unlock(&t->lock);
424
 
425
        /* Not interested in kernel threads */
426
        if ((flags & THREAD_FLAG_USPACE) != 0) {
2897 svoboda 427
            /* Using thread struct pointer as identification hash */
2887 svoboda 428
            tid = (unative_t) t;
429
            id_buffer[copied_ids++] = tid;
430
        }
431
    }
432
 
433
    spinlock_unlock(&TASK->lock);
434
    interrupts_restore(ipl);
435
 
3016 svoboda 436
    mutex_unlock(&TASK->udebug.lock);
437
 
2887 svoboda 438
    *buffer = id_buffer;
439
    *n = copied_ids * sizeof(unative_t);
440
 
441
    return 0;
442
}
443
 
3471 svoboda 444
/** Read the arguments of a system call.
445
 *
446
 * The arguments of the system call being being executed are copied
447
 * to an allocated buffer and a pointer to it is written to @a buffer.
448
 * The size of the buffer is exactly such that it can hold the maximum number
449
 * of system-call arguments.
450
 *
451
 * Unless the thread is currently blocked in a SYSCALL_B or SYSCALL_E event,
452
 * this function will fail with an EINVAL error code.
453
 *
454
 * @param buffer    The buffer for storing thread hashes.
455
 */
2887 svoboda 456
int udebug_args_read(thread_t *t, void **buffer)
457
{
458
    int rc;
459
    unative_t *arg_buffer;
460
 
2896 svoboda 461
    /* Prepare a buffer to hold the arguments */
462
    arg_buffer = malloc(6 * sizeof(unative_t), 0);
463
 
3018 svoboda 464
    /* On success, this will lock t->udebug.lock */
2898 svoboda 465
    rc = _thread_op_begin(t, false);
2887 svoboda 466
    if (rc != EOK) {
467
        return rc;
468
    }
469
 
470
    /* Additionally we need to verify that we are inside a syscall */
3018 svoboda 471
    if (t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B &&
472
        t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E) {
2887 svoboda 473
        _thread_op_end(t);
474
        return EINVAL;
475
    }
476
 
477
    /* Copy to a local buffer before releasing the lock */
3018 svoboda 478
    memcpy(arg_buffer, t->udebug.syscall_args, 6 * sizeof(unative_t));
2887 svoboda 479
 
480
    _thread_op_end(t);
481
 
482
    *buffer = arg_buffer;
483
    return 0;
484
}
485
 
2919 svoboda 486
int udebug_regs_read(thread_t *t, void *buffer)
2887 svoboda 487
{
488
    istate_t *state;
489
    int rc;
490
 
3424 svoboda 491
//  printf("udebug_regs_read()\n");
2887 svoboda 492
 
3018 svoboda 493
    /* On success, this will lock t->udebug.lock */
2898 svoboda 494
    rc = _thread_op_begin(t, false);
2887 svoboda 495
    if (rc != EOK) {
496
        return rc;
497
    }
498
 
3018 svoboda 499
    state = t->udebug.uspace_state;
2887 svoboda 500
    if (state == NULL) {
501
        _thread_op_end(t);
3424 svoboda 502
        printf("udebug_regs_read() - istate not available\n");
2887 svoboda 503
        return EBUSY;
504
    }
505
 
2896 svoboda 506
    /* Copy to the allocated buffer */
2919 svoboda 507
    memcpy(buffer, state, sizeof(istate_t));
2887 svoboda 508
 
509
    _thread_op_end(t);
510
 
511
    return 0;
512
}
513
 
514
int udebug_regs_write(thread_t *t, void *buffer)
515
{
516
    int rc;
517
    istate_t *state;
518
 
3424 svoboda 519
    printf("udebug_regs_write()\n");
2887 svoboda 520
 
521
    /* Try to change the thread's uspace_state */
522
 
3018 svoboda 523
    /* On success, this will lock t->udebug.lock */
2898 svoboda 524
    rc = _thread_op_begin(t, false);
2887 svoboda 525
    if (rc != EOK) {
3424 svoboda 526
        printf("error locking thread\n");
2887 svoboda 527
        return rc;
528
    }
529
 
3018 svoboda 530
    state = t->udebug.uspace_state;
2887 svoboda 531
    if (state == NULL) {
532
        _thread_op_end(t);
3424 svoboda 533
        printf("udebug_regs_write() - istate not available\n");
2887 svoboda 534
        return EBUSY;
535
    }
536
 
3018 svoboda 537
    memcpy(t->udebug.uspace_state, buffer, sizeof(istate_t));
2887 svoboda 538
 
539
    _thread_op_end(t);
540
 
541
    return 0;
542
}
543
 
3471 svoboda 544
/** Read the memory of the debugged task.
545
 *
546
 * Reads @a n bytes from the address space of the debugged task, starting
547
 * from @a uspace_addr. The bytes are copied into an allocated buffer
548
 * and a pointer to it is written into @a buffer.
549
 *
550
 * @param uspace_addr   Address from where to start reading.
551
 * @param n     Number of bytes to read.
552
 * @param buffer    For storing a pointer to the allocated buffer.
553
 */
2887 svoboda 554
int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer)
555
{
556
    void *data_buffer;
557
    int rc;
558
 
3016 svoboda 559
    /* Verify task state */
560
    mutex_lock(&TASK->udebug.lock);
2887 svoboda 561
 
3016 svoboda 562
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
563
        mutex_unlock(&TASK->udebug.lock);
564
        return EBUSY;
565
    }
566
 
2896 svoboda 567
    data_buffer = malloc(n, 0);
568
 
2887 svoboda 569
    /* NOTE: this is not strictly from a syscall... but that shouldn't
570
     * be a problem */
571
    rc = copy_from_uspace(data_buffer, (void *)uspace_addr, n);
3016 svoboda 572
    mutex_unlock(&TASK->udebug.lock);
2887 svoboda 573
 
3016 svoboda 574
    if (rc != 0) return rc;
575
 
2887 svoboda 576
    *buffer = data_buffer;
577
    return 0;
578
}
579
 
580
int udebug_mem_write(unative_t uspace_addr, void *data, size_t n)
581
{
582
    int rc;
583
 
3424 svoboda 584
    printf("udebug_mem_write()\n");
2887 svoboda 585
 
3127 svoboda 586
    /* n must be positive */
587
    if (n < 1)
588
        return EINVAL;
589
 
2887 svoboda 590
    /* Verify task state */
3016 svoboda 591
    mutex_lock(&TASK->udebug.lock);
2887 svoboda 592
 
3016 svoboda 593
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
594
        mutex_unlock(&TASK->udebug.lock);
2887 svoboda 595
        return EBUSY;
3016 svoboda 596
    }
2887 svoboda 597
 
3424 svoboda 598
    printf("dst=%u, size=%u\n", uspace_addr, n);
2887 svoboda 599
 
600
    /* NOTE: this is not strictly from a syscall... but that shouldn't
601
     * be a problem */
3013 svoboda 602
//  rc = copy_to_uspace((void *)uspace_addr, data, n);
603
//  if (rc) return rc;
2887 svoboda 604
 
3013 svoboda 605
    rc = as_debug_write(uspace_addr, data, n);
3127 svoboda 606
 
3424 svoboda 607
    printf("rc=%d\n", rc);
3013 svoboda 608
 
3016 svoboda 609
    mutex_unlock(&TASK->udebug.lock);
610
 
3013 svoboda 611
    return rc;
2887 svoboda 612
}
613
 
614
/** @}
615
 */