Subversion Repositories HelenOS

Rev

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

Rev 3016 Rev 3018
Line 46... Line 46...
46
#include <udebug/udebug_ops.h>
46
#include <udebug/udebug_ops.h>
47
 
47
 
48
/**
48
/**
49
 * Prepare a thread for a debugging operation.
49
 * Prepare a thread for a debugging operation.
50
 *
50
 *
51
 * Simply put, return thread t with t->debug_lock held,
51
 * Simply put, return thread t with t->udebug.lock held,
52
 * but only if it verifies all conditions.
52
 * but only if it verifies all conditions.
53
 *
53
 *
54
 * Specifically, verifies that thread t exists, is a userspace thread,
54
 * Specifically, verifies that thread t exists, is a userspace thread,
55
 * and belongs to the current task (TASK). Verifies, that the thread
55
 * and belongs to the current task (TASK). Verifies, that the thread
56
 * has (or hasn't) go according to having_go (typically false).
56
 * has (or hasn't) go according to having_go (typically false).
57
 * It also locks t->debug_lock, making sure that t->debug_active is true
57
 * It also locks t->udebug.lock, making sure that t->udebug.debug_active is true
58
 * - that the thread is in a valid debugging session.
58
 * - that the thread is in a valid debugging session.
59
 *
59
 *
60
 * Returns EOK if all went well, or an error code otherwise.
60
 * Returns EOK if all went well, or an error code otherwise.
61
 * Interrupts must be already disabled when calling this function.
61
 * Interrupts must be already disabled when calling this function.
62
 *
62
 *
Line 75... Line 75...
75
    if (!thread_exists(t)) {
75
    if (!thread_exists(t)) {
76
        spinlock_unlock(&threads_lock);
76
        spinlock_unlock(&threads_lock);
77
        return ENOENT;
77
        return ENOENT;
78
    }
78
    }
79
 
79
 
80
    spinlock_lock(&t->debug_lock);
80
    spinlock_lock(&t->udebug.lock);
81
    spinlock_lock(&t->lock);
81
    spinlock_lock(&t->lock);
82
   
82
   
83
    /* Now verify that it's the current task */
83
    /* Now verify that it's the current task */
84
    if (t->task != TASK) {
84
    if (t->task != TASK) {
85
        /* No such thread belonging to callee */
85
        /* No such thread belonging to callee */
Line 92... Line 92...
92
        /* It's not, deny its existence */
92
        /* It's not, deny its existence */
93
        rc = ENOENT;
93
        rc = ENOENT;
94
        goto error_exit;
94
        goto error_exit;
95
    }
95
    }
96
 
96
 
97
    if ((t->debug_active != true) || (!t->debug_stop != having_go)) {
97
    if ((t->udebug.debug_active != true) || (!t->udebug.stop != having_go)) {
98
        /* Not in debugging session or undesired GO state */
98
        /* Not in debugging session or undesired GO state */
99
        rc = EINVAL;
99
        rc = EINVAL;
100
        goto error_exit;
100
        goto error_exit;
101
    }
101
    }
102
 
102
 
103
    spinlock_unlock(&threads_lock);
103
    spinlock_unlock(&threads_lock);
104
    spinlock_unlock(&t->lock);
104
    spinlock_unlock(&t->lock);
105
 
105
 
106
    /* Only t->debug_lock left */
106
    /* Only t->udebug.lock left */
107
 
107
 
108
    return EOK; /* All went well */
108
    return EOK; /* All went well */
109
 
109
 
110
 
110
 
111
    /* Executed when a check on the thread fails */
111
    /* Executed when a check on the thread fails */
112
error_exit:
112
error_exit:
113
    spinlock_unlock(&t->lock);
113
    spinlock_unlock(&t->lock);
114
    spinlock_unlock(&t->debug_lock);
114
    spinlock_unlock(&t->udebug.lock);
115
    spinlock_unlock(&threads_lock);
115
    spinlock_unlock(&threads_lock);
116
 
116
 
117
    /* No locks left here */
117
    /* No locks left here */
118
    return rc;  /* Some errors occured */
118
    return rc;  /* Some errors occured */
119
}
119
}
120
 
120
 
121
 
121
 
122
static void _thread_op_end(thread_t *t)
122
static void _thread_op_end(thread_t *t)
123
{
123
{
124
    spinlock_unlock(&t->debug_lock);
124
    spinlock_unlock(&t->udebug.lock);
125
}
125
}
126
 
126
 
127
/**
127
/**
128
 * \return 0 (ok, but not done yet), 1 (done) or negative error code.
128
 * \return 0 (ok, but not done yet), 1 (done) or negative error code.
129
 */
129
 */
Line 157... Line 157...
157
        reply = 1; /* immediate reply */
157
        reply = 1; /* immediate reply */
158
    } else {
158
    } else {
159
        reply = 0; /* no reply */
159
        reply = 0; /* no reply */
160
    }
160
    }
161
   
161
   
162
    /* Set debug_active on all of the task's userspace threads */
162
    /* Set udebug.debug_active on all of the task's userspace threads */
163
 
163
 
164
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
164
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
165
        t = list_get_instance(cur, thread_t, th_link);
165
        t = list_get_instance(cur, thread_t, th_link);
166
 
166
 
167
        ipl = interrupts_disable();
167
        ipl = interrupts_disable();
168
        spinlock_lock(&t->debug_lock);
168
        spinlock_lock(&t->udebug.lock);
169
        if ((t->flags & THREAD_FLAG_USPACE) != 0)
169
        if ((t->flags & THREAD_FLAG_USPACE) != 0)
170
            t->debug_active = true;
170
            t->udebug.debug_active = true;
171
        spinlock_unlock(&t->debug_lock);
171
        spinlock_unlock(&t->udebug.lock);
172
        interrupts_restore(ipl);
172
        interrupts_restore(ipl);
173
    }
173
    }
174
 
174
 
175
    mutex_unlock(&TASK->udebug.lock);
175
    mutex_unlock(&TASK->udebug.lock);
176
 
176
 
Line 226... Line 226...
226
 
226
 
227
//  klog_printf("udebug_go()");
227
//  klog_printf("udebug_go()");
228
 
228
 
229
    ipl = interrupts_disable();
229
    ipl = interrupts_disable();
230
 
230
 
231
    /* On success, this will lock t->debug_lock */
231
    /* On success, this will lock t->udebug.lock */
232
    rc = _thread_op_begin(t, false);
232
    rc = _thread_op_begin(t, false);
233
    if (rc != EOK) {
233
    if (rc != EOK) {
234
        interrupts_restore(ipl);
234
        interrupts_restore(ipl);
235
        return rc;
235
        return rc;
236
    }
236
    }
237
 
237
 
238
    t->debug_go_call = call;
238
    t->udebug.go_call = call;
239
    t->debug_stop = false;
239
    t->udebug.stop = false;
240
    t->cur_event = 0;   /* none */
240
    t->udebug.cur_event = 0;    /* none */
241
 
241
 
242
    /*
242
    /*
243
     * Neither t's lock nor threads_lock may be held during wakeup
243
     * Neither t's lock nor threads_lock may be held during wakeup
244
     */
244
     */
245
    waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
245
    waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
246
 
246
 
247
    _thread_op_end(t);
247
    _thread_op_end(t);
248
    interrupts_restore(ipl);
248
    interrupts_restore(ipl);
249
 
249
 
250
    return 0;
250
    return 0;
Line 259... Line 259...
259
    mutex_lock(&TASK->udebug.lock);
259
    mutex_lock(&TASK->udebug.lock);
260
 
260
 
261
    ipl = interrupts_disable();
261
    ipl = interrupts_disable();
262
 
262
 
263
    /*
263
    /*
264
     * On success, this will lock t->debug_lock. Note that this makes sure
264
     * On success, this will lock t->udebug.lock. Note that this makes sure
265
     * the thread is not stopped.
265
     * the thread is not stopped.
266
     */
266
     */
267
    rc = _thread_op_begin(t, true);
267
    rc = _thread_op_begin(t, true);
268
    if (rc != EOK) {
268
    if (rc != EOK) {
269
        interrupts_restore(ipl);
269
        interrupts_restore(ipl);
270
        return rc;
270
        return rc;
271
    }
271
    }
272
 
272
 
273
    /* Take GO away from the thread */
273
    /* Take GO away from the thread */
274
    t->debug_stop = true;
274
    t->udebug.stop = true;
275
 
275
 
276
    if (!t->debug_stoppable) {
276
    if (!t->udebug.stoppable) {
277
        /* Answer will be sent when the thread becomes stoppable */
277
        /* Answer will be sent when the thread becomes stoppable */
278
        _thread_op_end(t);
278
        _thread_op_end(t);
279
        interrupts_restore(ipl);
279
        interrupts_restore(ipl);
280
        return 0;
280
        return 0;
281
    }
281
    }
Line 284... Line 284...
284
     * Answer GO call
284
     * Answer GO call
285
     */
285
     */
286
    klog_printf("udebug_stop - answering go call");
286
    klog_printf("udebug_stop - answering go call");
287
 
287
 
288
    /* Make sure nobody takes this call away from us */
288
    /* Make sure nobody takes this call away from us */
289
    call = t->debug_go_call;
289
    call = t->udebug.go_call;
290
    t->debug_go_call = NULL;
290
    t->udebug.go_call = NULL;
291
 
291
 
292
    IPC_SET_RETVAL(call->data, 0);
292
    IPC_SET_RETVAL(call->data, 0);
293
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
293
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
294
    klog_printf("udebug_stop/ipc_answer");
294
    klog_printf("udebug_stop/ipc_answer");
295
 
295
 
296
    THREAD->cur_event = UDEBUG_EVENT_STOP;
296
    THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
297
 
297
 
298
    _thread_op_end(t);
298
    _thread_op_end(t);
299
    interrupts_restore(ipl);
299
    interrupts_restore(ipl);
300
 
300
 
301
    ipc_answer(&TASK->answerbox, call);
301
    ipc_answer(&TASK->answerbox, call);
Line 376... Line 376...
376
    /* Prepare a buffer to hold the arguments */
376
    /* Prepare a buffer to hold the arguments */
377
    arg_buffer = malloc(6 * sizeof(unative_t), 0);
377
    arg_buffer = malloc(6 * sizeof(unative_t), 0);
378
 
378
 
379
    ipl = interrupts_disable();
379
    ipl = interrupts_disable();
380
 
380
 
381
    /* On success, this will lock t->debug_lock */
381
    /* On success, this will lock t->udebug.lock */
382
    rc = _thread_op_begin(t, false);
382
    rc = _thread_op_begin(t, false);
383
    if (rc != EOK) {
383
    if (rc != EOK) {
384
        interrupts_restore(ipl);
384
        interrupts_restore(ipl);
385
        return rc;
385
        return rc;
386
    }
386
    }
387
 
387
 
388
    /* Additionally we need to verify that we are inside a syscall */
388
    /* Additionally we need to verify that we are inside a syscall */
389
    if (t->cur_event != UDEBUG_EVENT_SYSCALL_B &&
389
    if (t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B &&
390
        t->cur_event != UDEBUG_EVENT_SYSCALL_E) {
390
        t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E) {
391
        _thread_op_end(t);
391
        _thread_op_end(t);
392
        interrupts_restore(ipl);
392
        interrupts_restore(ipl);
393
 
393
 
394
        return EINVAL;
394
        return EINVAL;
395
    }
395
    }
396
 
396
 
397
    /* Copy to a local buffer before releasing the lock */
397
    /* Copy to a local buffer before releasing the lock */
398
    memcpy(arg_buffer, t->syscall_args, 6 * sizeof(unative_t));
398
    memcpy(arg_buffer, t->udebug.syscall_args, 6 * sizeof(unative_t));
399
 
399
 
400
    _thread_op_end(t);
400
    _thread_op_end(t);
401
    interrupts_restore(ipl);
401
    interrupts_restore(ipl);
402
 
402
 
403
    *buffer = arg_buffer;
403
    *buffer = arg_buffer;
Line 412... Line 412...
412
 
412
 
413
    klog_printf("udebug_regs_read()");
413
    klog_printf("udebug_regs_read()");
414
 
414
 
415
    ipl = interrupts_disable();
415
    ipl = interrupts_disable();
416
 
416
 
417
    /* On success, this will lock t->debug_lock */
417
    /* On success, this will lock t->udebug.lock */
418
    rc = _thread_op_begin(t, false);
418
    rc = _thread_op_begin(t, false);
419
    if (rc != EOK) {
419
    if (rc != EOK) {
420
        interrupts_restore(ipl);
420
        interrupts_restore(ipl);
421
        return rc;
421
        return rc;
422
    }
422
    }
423
 
423
 
424
    state = t->uspace_state;
424
    state = t->udebug.uspace_state;
425
    if (state == NULL) {
425
    if (state == NULL) {
426
        _thread_op_end(t);
426
        _thread_op_end(t);
427
        interrupts_restore(ipl);
427
        interrupts_restore(ipl);
428
        klog_printf("udebug_regs_read() - istate not available");
428
        klog_printf("udebug_regs_read() - istate not available");
429
        return EBUSY;
429
        return EBUSY;
Line 448... Line 448...
448
 
448
 
449
    /* Try to change the thread's uspace_state */
449
    /* Try to change the thread's uspace_state */
450
 
450
 
451
    ipl = interrupts_disable();
451
    ipl = interrupts_disable();
452
 
452
 
453
    /* On success, this will lock t->debug_lock */
453
    /* On success, this will lock t->udebug.lock */
454
    rc = _thread_op_begin(t, false);
454
    rc = _thread_op_begin(t, false);
455
    if (rc != EOK) {
455
    if (rc != EOK) {
456
        klog_printf("error locking thread");
456
        klog_printf("error locking thread");
457
        interrupts_restore(ipl);
457
        interrupts_restore(ipl);
458
        return rc;
458
        return rc;
459
    }
459
    }
460
 
460
 
461
    state = t->uspace_state;
461
    state = t->udebug.uspace_state;
462
    if (state == NULL) {
462
    if (state == NULL) {
463
        _thread_op_end(t);
463
        _thread_op_end(t);
464
        interrupts_restore(ipl);
464
        interrupts_restore(ipl);
465
        klog_printf("udebug_regs_write() - istate not available");
465
        klog_printf("udebug_regs_write() - istate not available");
466
 
466
 
467
        return EBUSY;
467
        return EBUSY;
468
    }
468
    }
469
 
469
 
470
    memcpy(t->uspace_state, buffer, sizeof(istate_t));
470
    memcpy(t->udebug.uspace_state, buffer, sizeof(istate_t));
471
 
471
 
472
    _thread_op_end(t);
472
    _thread_op_end(t);
473
    interrupts_restore(ipl);
473
    interrupts_restore(ipl);
474
 
474
 
475
    return 0;
475
    return 0;