Subversion Repositories HelenOS

Rev

Rev 3424 | Rev 3611 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3424 Rev 3471
Line 31... Line 31...
31
 */
31
 */
32
 
32
 
33
/**
33
/**
34
 * @file
34
 * @file
35
 * @brief   Udebug operations.
35
 * @brief   Udebug operations.
-
 
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.
36
 */
40
 */
37
 
41
 
38
#include <print.h>
42
#include <debug.h>
39
#include <proc/task.h>
43
#include <proc/task.h>
40
#include <proc/thread.h>
44
#include <proc/thread.h>
41
#include <arch.h>
45
#include <arch.h>
42
#include <errno.h>
46
#include <errno.h>
43
#include <syscall/copy.h>
47
#include <syscall/copy.h>
Line 63... Line 67...
63
 *
67
 *
64
 * In this function, holding the TASK->udebug.lock mutex prevents the
68
 * In this function, holding the TASK->udebug.lock mutex prevents the
65
 * thread from leaving the debugging session, while relaxing from
69
 * thread from leaving the debugging session, while relaxing from
66
 * the t->lock spinlock to the t->udebug.lock mutex.
70
 * the t->lock spinlock to the t->udebug.lock mutex.
67
 *
71
 *
-
 
72
 * @param t     Pointer, need not at all be valid.
-
 
73
 * @param having_go Required thread state.
-
 
74
 *
68
 * Returns EOK if all went well, or an error code otherwise.
75
 * Returns EOK if all went well, or an error code otherwise.
69
 */
76
 */
70
static int _thread_op_begin(thread_t *t, bool having_go)
77
static int _thread_op_begin(thread_t *t, bool having_go)
71
{
78
{
72
    task_id_t taskid;
79
    task_id_t taskid;
Line 144... Line 151...
144
    /* Only t->udebug.lock left */
151
    /* Only t->udebug.lock left */
145
 
152
 
146
    return EOK; /* All went well */
153
    return EOK; /* All went well */
147
}
154
}
148
 
155
 
149
 
-
 
-
 
156
/** End debugging operation on a thread. */
150
static void _thread_op_end(thread_t *t)
157
static void _thread_op_end(thread_t *t)
151
{
158
{
152
    mutex_unlock(&t->udebug.lock);
159
    mutex_unlock(&t->udebug.lock);
153
}
160
}
154
 
161
 
-
 
162
/** Begin debugging the current task.
155
/**
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.
156
 * \return 0 (ok, but not done yet), 1 (done) or negative error code.
174
 * @return  0 (OK, but not done yet), 1 (done) or negative error code.
157
 */
175
 */
158
int udebug_begin(call_t *call)
176
int udebug_begin(call_t *call)
159
{
177
{
160
    int reply;
178
    int reply;
161
 
179
 
162
    thread_t *t;
180
    thread_t *t;
163
    link_t *cur;
181
    link_t *cur;
164
 
182
 
165
    printf("udebug_begin()\n");
183
    LOG("udebug_begin()\n");
166
 
184
 
167
    mutex_lock(&TASK->udebug.lock);
185
    mutex_lock(&TASK->udebug.lock);
168
    printf("debugging task %llu\n", TASK->taskid);
186
    LOG("debugging task %llu\n", TASK->taskid);
169
 
187
 
170
    if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
188
    if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
171
        mutex_unlock(&TASK->udebug.lock);
189
        mutex_unlock(&TASK->udebug.lock);
172
        printf("udebug_begin(): busy error\n");
190
        LOG("udebug_begin(): busy error\n");
173
 
191
 
174
        return EBUSY;
192
        return EBUSY;
175
    }
193
    }
176
 
194
 
177
    TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
195
    TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
Line 197... Line 215...
197
        mutex_unlock(&t->udebug.lock);
215
        mutex_unlock(&t->udebug.lock);
198
    }
216
    }
199
 
217
 
200
    mutex_unlock(&TASK->udebug.lock);
218
    mutex_unlock(&TASK->udebug.lock);
201
 
219
 
202
    printf("udebug_begin() done (%s)\n",
220
    LOG("udebug_begin() done (%s)\n",
203
        reply ? "reply" : "stoppability wait");
221
        reply ? "reply" : "stoppability wait");
204
 
222
 
205
    return reply;
223
    return reply;
206
}
224
}
207
 
225
 
-
 
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
 */
208
int udebug_end(void)
231
int udebug_end(void)
209
{
232
{
210
    int rc;
233
    int rc;
211
 
234
 
212
    printf("udebug_end()\n");
235
    LOG("udebug_end()\n");
213
 
236
 
214
    mutex_lock(&TASK->udebug.lock);
237
    mutex_lock(&TASK->udebug.lock);
215
    printf("task %llu\n", TASK->taskid);
238
    LOG("task %" PRIu64 "\n", TASK->taskid);
216
 
239
 
217
    rc = udebug_task_cleanup(TASK);
240
    rc = udebug_task_cleanup(TASK);
218
 
241
 
219
    mutex_unlock(&TASK->udebug.lock);
242
    mutex_unlock(&TASK->udebug.lock);
220
 
243
 
221
    return rc;
244
    return rc;
222
}
245
}
223
 
246
 
-
 
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
 */
224
int udebug_set_evmask(udebug_evmask_t mask)
254
int udebug_set_evmask(udebug_evmask_t mask)
225
{
255
{
226
    printf("udebug_set_mask()\n");
256
    LOG("udebug_set_mask()\n");
227
 
-
 
228
    printf("debugging task %llu\n", TASK->taskid);
-
 
229
 
257
 
230
    mutex_lock(&TASK->udebug.lock);
258
    mutex_lock(&TASK->udebug.lock);
231
 
259
 
232
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
260
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
233
        mutex_unlock(&TASK->udebug.lock);
261
        mutex_unlock(&TASK->udebug.lock);
234
        printf("udebug_set_mask(): not active debuging session\n");
262
        LOG("udebug_set_mask(): not active debuging session\n");
235
 
263
 
236
        return EINVAL;
264
        return EINVAL;
237
    }
265
    }
238
 
266
 
239
    TASK->udebug.evmask = mask;
267
    TASK->udebug.evmask = mask;
Line 241... Line 269...
241
    mutex_unlock(&TASK->udebug.lock);
269
    mutex_unlock(&TASK->udebug.lock);
242
 
270
 
243
    return 0;
271
    return 0;
244
}
272
}
245
 
273
 
-
 
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.
246
 
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
 */
247
int udebug_go(thread_t *t, call_t *call)
283
int udebug_go(thread_t *t, call_t *call)
248
{
284
{
249
    int rc;
285
    int rc;
250
 
286
 
251
//  printf("udebug_go()\n");
-
 
252
 
-
 
253
    /* On success, this will lock t->udebug.lock */
287
    /* On success, this will lock t->udebug.lock */
254
    rc = _thread_op_begin(t, false);
288
    rc = _thread_op_begin(t, false);
255
    if (rc != EOK) {
289
    if (rc != EOK) {
256
        return rc;
290
        return rc;
257
    }
291
    }
Line 268... Line 302...
268
    _thread_op_end(t);
302
    _thread_op_end(t);
269
 
303
 
270
    return 0;
304
    return 0;
271
}
305
}
272
 
306
 
-
 
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
 */
273
int udebug_stop(thread_t *t, call_t *call)
315
int udebug_stop(thread_t *t, call_t *call)
274
{
316
{
275
    int rc;
317
    int rc;
276
 
318
 
277
    printf("udebug_stop()\n");
319
    LOG("udebug_stop()\n");
278
    mutex_lock(&TASK->udebug.lock);
320
    mutex_lock(&TASK->udebug.lock);
279
 
321
 
280
    /*
322
    /*
281
     * On success, this will lock t->udebug.lock. Note that this makes sure
323
     * On success, this will lock t->udebug.lock. Note that this makes sure
282
     * the thread is not stopped.
324
     * the thread is not stopped.
Line 296... Line 338...
296
    }
338
    }
297
 
339
 
298
    /*
340
    /*
299
     * Answer GO call
341
     * Answer GO call
300
     */
342
     */
301
    printf("udebug_stop - answering go call\n");
343
    LOG("udebug_stop - answering go call\n");
302
 
344
 
303
    /* Make sure nobody takes this call away from us */
345
    /* Make sure nobody takes this call away from us */
304
    call = t->udebug.go_call;
346
    call = t->udebug.go_call;
305
    t->udebug.go_call = NULL;
347
    t->udebug.go_call = NULL;
306
 
348
 
307
    IPC_SET_RETVAL(call->data, 0);
349
    IPC_SET_RETVAL(call->data, 0);
308
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
350
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
309
    printf("udebug_stop/ipc_answer\n");
351
    LOG("udebug_stop/ipc_answer\n");
310
 
352
 
311
    THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
353
    THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
312
 
354
 
313
    _thread_op_end(t);
355
    _thread_op_end(t);
314
 
356
 
315
    ipc_answer(&TASK->answerbox, call);
357
    ipc_answer(&TASK->answerbox, call);
316
    mutex_unlock(&TASK->udebug.lock);
358
    mutex_unlock(&TASK->udebug.lock);
317
 
359
 
318
    printf("udebog_stop/done\n");
360
    LOG("udebog_stop/done\n");
319
    return 0;
361
    return 0;
320
}
362
}
321
 
363
 
-
 
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
 */
322
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n)
383
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n)
323
{
384
{
324
    thread_t *t;
385
    thread_t *t;
325
    link_t *cur;
386
    link_t *cur;
326
    unative_t tid;
387
    unative_t tid;
Line 328... Line 389...
328
    ipl_t ipl;
389
    ipl_t ipl;
329
    unative_t *id_buffer;
390
    unative_t *id_buffer;
330
    int flags;
391
    int flags;
331
    size_t max_ids;
392
    size_t max_ids;
332
 
393
 
333
    printf("udebug_thread_read()\n");
394
    LOG("udebug_thread_read()\n");
334
 
395
 
335
    /* Allocate a buffer to hold thread IDs */
396
    /* Allocate a buffer to hold thread IDs */
336
    id_buffer = malloc(buf_size, 0);
397
    id_buffer = malloc(buf_size, 0);
337
 
398
 
338
    mutex_lock(&TASK->udebug.lock);
399
    mutex_lock(&TASK->udebug.lock);
Line 378... Line 439...
378
    *n = copied_ids * sizeof(unative_t);
439
    *n = copied_ids * sizeof(unative_t);
379
 
440
 
380
    return 0;
441
    return 0;
381
}
442
}
382
 
443
 
-
 
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
 */
383
int udebug_args_read(thread_t *t, void **buffer)
456
int udebug_args_read(thread_t *t, void **buffer)
384
{
457
{
385
    int rc;
458
    int rc;
386
    unative_t *arg_buffer;
459
    unative_t *arg_buffer;
387
 
460
 
388
//  printf("udebug_args_read()\n");
-
 
389
 
-
 
390
    /* Prepare a buffer to hold the arguments */
461
    /* Prepare a buffer to hold the arguments */
391
    arg_buffer = malloc(6 * sizeof(unative_t), 0);
462
    arg_buffer = malloc(6 * sizeof(unative_t), 0);
392
 
463
 
393
    /* On success, this will lock t->udebug.lock */
464
    /* On success, this will lock t->udebug.lock */
394
    rc = _thread_op_begin(t, false);
465
    rc = _thread_op_begin(t, false);
Line 468... Line 539...
468
    _thread_op_end(t);
539
    _thread_op_end(t);
469
 
540
 
470
    return 0;
541
    return 0;
471
}
542
}
472
 
543
 
-
 
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.
473
 
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
 */
474
int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer)
554
int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer)
475
{
555
{
476
    void *data_buffer;
556
    void *data_buffer;
477
    int rc;
557
    int rc;
478
 
558
 
Line 484... Line 564...
484
        return EBUSY;
564
        return EBUSY;
485
    }
565
    }
486
 
566
 
487
    data_buffer = malloc(n, 0);
567
    data_buffer = malloc(n, 0);
488
 
568
 
489
//  printf("udebug_mem_read: src=%u, size=%u\n", uspace_addr, n);
-
 
490
 
-
 
491
    /* NOTE: this is not strictly from a syscall... but that shouldn't
569
    /* NOTE: this is not strictly from a syscall... but that shouldn't
492
     * be a problem */
570
     * be a problem */
493
    rc = copy_from_uspace(data_buffer, (void *)uspace_addr, n);
571
    rc = copy_from_uspace(data_buffer, (void *)uspace_addr, n);
494
    mutex_unlock(&TASK->udebug.lock);
572
    mutex_unlock(&TASK->udebug.lock);
495
 
573