Subversion Repositories HelenOS

Rev

Rev 3742 | Details | Compare with Previous | Last modification | View Log | RSS feed

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