Subversion Repositories HelenOS

Rev

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

Rev 2848 Rev 2849
Line 16... Line 16...
16
#include <syscall/copy.h>
16
#include <syscall/copy.h>
17
#include <udebug/udebug.h>
17
#include <udebug/udebug.h>
18
#include <udebug/udebug_ipc.h>
18
#include <udebug/udebug_ipc.h>
19
 
19
 
20
/**
20
/**
21
 * Get and lock a phone's callee task.
21
 * Get a phone's callee task id.
22
 *
22
 *
23
 * This will return a pointer to the task to which the phone
23
 * This will return the id of the task to which the phone
24
 * is connected. It will lock the task, making sure it exists.
24
 * is connected.
25
 *
25
 *
26
 * Interrupts must be already disabled.
26
 * Interrupts must be already disabled.
27
 *
-
 
28
 * (TODO: make sure the udebug-cleanup of the task hasn't
-
 
29
 * started yet)
-
 
30
 */
27
 */
31
static task_t *get_lock_callee_task(phone_t *phone)
28
static task_id_t get_callee_task_id(phone_t *phone)
32
{
29
{
33
    answerbox_t *box;
30
    answerbox_t *box;
34
    task_t *ta;
-
 
35
    task_id_t taskid;
31
    task_id_t taskid;
36
 
32
 
37
    spinlock_lock(&phone->lock);
33
    spinlock_lock(&phone->lock);
38
    if (phone->state != IPC_PHONE_CONNECTED) {
34
    if (phone->state != IPC_PHONE_CONNECTED) {
39
        spinlock_unlock(&phone->lock);
35
        spinlock_unlock(&phone->lock);
Line 41... Line 37...
41
    }
37
    }
42
 
38
 
43
    box = phone->callee;
39
    box = phone->callee;
44
   
40
   
45
    spinlock_lock(&box->lock);
41
    spinlock_lock(&box->lock);
46
    ta = box->task;
-
 
47
    taskid = ta->taskid;
42
    taskid = box->task->taskid;
48
    spinlock_unlock(&box->lock);
43
    spinlock_unlock(&box->lock);
49
    spinlock_unlock(&phone->lock);
44
    spinlock_unlock(&phone->lock);
50
 
45
 
-
 
46
    return taskid;
-
 
47
}
-
 
48
 
-
 
49
/**
51
    /* Locking decoupled using taskid */
50
 * Get and lock a phone's callee task.
-
 
51
 *
-
 
52
 * This will return a pointer to the task to which the phone
-
 
53
 * is connected. It will lock the task, making sure it exists.
-
 
54
 *
-
 
55
 * Interrupts must be already disabled.
-
 
56
 *
-
 
57
 * (TODO: make sure the udebug-cleanup of the task hasn't
-
 
58
 * started yet)
-
 
59
 */
-
 
60
static task_t *get_lock_callee_task(phone_t *phone)
52
   
61
{
-
 
62
    task_t *ta;
-
 
63
    task_id_t taskid;
-
 
64
 
-
 
65
    taskid = get_callee_task_id(phone);
-
 
66
 
53
    spinlock_lock(&tasks_lock);
67
    spinlock_lock(&tasks_lock);
54
    ta = task_find_by_id(taskid);
68
    ta = task_find_by_id(taskid);
55
    if (ta == NULL) {
69
    if (ta == NULL) {
56
        spinlock_unlock(&tasks_lock);
70
        spinlock_unlock(&tasks_lock);
57
        return NULL;
71
        return NULL;
Line 61... Line 75...
61
    spinlock_unlock(&tasks_lock);
75
    spinlock_unlock(&tasks_lock);
62
 
76
 
63
    return ta;
77
    return ta;
64
}
78
}
65
 
79
 
66
/**
80
/**
67
 * Verify that thread t is valid for debugging ops.
81
 * Prepare a thread for a debugging operation.
68
 *
82
 *
69
 * Verifies that t belongs to task ta and that debugging operations
83
 * Simply put, return thread t with t->debug_lock held,
70
 * may be used on it.
84
 * but only if it verifies all conditions.
71
 *
85
 *
-
 
86
 * Specifically, verifies that thread t exists, is a userspace thread,
-
 
87
 * belongs to the callee of 'phone'. It also locks t->debug_lock,
-
 
88
 * making sure that t->debug_active is true - that the thread is
-
 
89
 * in a valid debugging session.
-
 
90
 *
-
 
91
 * Returns EOK if all went well, or an error code otherwise.
72
 * Thread t's lock must already be held and interrupts must be disabled.
92
 * Interrupts must be already disabled when calling this function.
-
 
93
 *
-
 
94
 * Note: This function sports complicated locking.
73
 */
95
 */
74
static int verify_thread(thread_t *t, task_t *ta)
96
static int _thread_op_begin(phone_t *phone, thread_t *t)
75
{
97
{
-
 
98
    int rc;
-
 
99
    task_id_t taskid;
-
 
100
    int task_match;
-
 
101
    DEADLOCK_PROBE_INIT(p_tasklock);
-
 
102
 
-
 
103
    taskid = get_callee_task_id(phone);
-
 
104
 
76
    /* Verify that 't' exists and belongs to task 'ta' */
105
    /* Need to lock down the thread and than it's owner task */
-
 
106
grab_locks:
-
 
107
    spinlock_lock(&threads_lock);
-
 
108
 
77
    if (!thread_exists(t) || (t->task != ta)) {
109
    if (!thread_exists(t)) {
-
 
110
        spinlock_unlock(&threads_lock);
78
        return ENOENT;
111
        return ENOENT;
79
    }
112
    }
80
 
113
 
-
 
114
    spinlock_lock(&t->debug_lock);
-
 
115
    spinlock_lock(&t->lock);
-
 
116
   
-
 
117
    if (!spinlock_trylock(&t->task->lock)) {
-
 
118
        spinlock_unlock(&t->lock);
-
 
119
        spinlock_unlock(&t->debug_lock);
-
 
120
        DEADLOCK_PROBE(p_tasklock, DEADLOCK_THRESHOLD);
-
 
121
        goto grab_locks;    /* avoid deadlock */
-
 
122
    }
-
 
123
 
-
 
124
    /* Now verify that it's the callee */
-
 
125
    task_match = (t->task->taskid == taskid);
-
 
126
 
-
 
127
    spinlock_unlock(&t->task->lock);
-
 
128
 
-
 
129
    if (!task_match) {
-
 
130
        /* No such thread belonging to callee */
-
 
131
        rc = ENOENT;
-
 
132
        goto error_exit;
-
 
133
    }
-
 
134
 
81
    /* Verify that 't' is a userspace thread */
135
    /* Verify that 't' is a userspace thread */
82
    if ((t->flags & THREAD_FLAG_USPACE) == 0) {
136
    if ((t->flags & THREAD_FLAG_USPACE) == 0) {
83
        /* It's not, deny its existence */
137
        /* It's not, deny its existence */
84
        return ENOENT;
138
        rc = ENOENT;
-
 
139
        goto error_exit;
85
    }
140
    }
86
 
141
 
87
    if ((t->debug_active != true) || (t->debug_stop != true)) {
142
    if ((t->debug_active != true) || (t->debug_stop != true)) {
88
        /* Not in debugging session or already has GO */
143
        /* Not in debugging session or already has GO */
89
        return EBUSY;
144
        rc = ENOENT;
-
 
145
        goto error_exit;
90
    }
146
    }
91
 
147
 
-
 
148
    spinlock_unlock(&threads_lock);
-
 
149
    spinlock_unlock(&t->lock);
-
 
150
 
-
 
151
    /* Only t->debug_lock left */
-
 
152
 
-
 
153
    return EOK; /* All went well */
-
 
154
 
-
 
155
 
-
 
156
    /* Executed when a check on the thread fails */
92
    return EOK;
157
error_exit:
-
 
158
    spinlock_unlock(&t->lock);
-
 
159
    spinlock_unlock(&t->debug_lock);
-
 
160
    spinlock_unlock(&threads_lock);
-
 
161
 
-
 
162
    /* No locks left here */
-
 
163
    return rc;  /* Some errors occured */
-
 
164
}
-
 
165
 
-
 
166
static void _thread_op_end(thread_t *t)
-
 
167
{
-
 
168
    spinlock_unlock(&t->debug_lock);
93
}
169
}
94
 
170
 
95
static int udebug_rp_begin(call_t *call, phone_t *phone)
171
static int udebug_rp_begin(call_t *call, phone_t *phone)
96
{
172
{
97
    task_t *ta;
173
    task_t *ta;
Line 227... Line 303...
227
 
303
 
228
 
304
 
229
static int udebug_rp_go(call_t *call, phone_t *phone)
305
static int udebug_rp_go(call_t *call, phone_t *phone)
230
{
306
{
231
    thread_t *t;
307
    thread_t *t;
232
    task_t *ta;
-
 
233
    ipl_t ipl;
308
    ipl_t ipl;
234
    int rc;
309
    int rc;
235
 
310
 
236
    klog_printf("debug_go()");
311
    klog_printf("debug_go()");
237
 
312
 
238
    ipl = interrupts_disable();
313
    t = (thread_t *)IPC_GET_ARG2(call->data);
239
 
314
 
240
    ta = get_lock_callee_task(phone);
-
 
241
    spinlock_unlock(&ta->lock);
-
 
242
    // TODO: don't lock ta
-
 
243
 
-
 
244
    t = (thread_t *) IPC_GET_ARG2(call->data);
-
 
245
 
-
 
246
    spinlock_lock(&threads_lock);
-
 
247
    if (!thread_exists(t)) {
-
 
248
        spinlock_unlock(&threads_lock);
-
 
249
        interrupts_restore(ipl);
315
    ipl = interrupts_disable();
250
        return ENOENT;
-
 
251
    }
-
 
252
 
-
 
253
    spinlock_lock(&t->debug_lock);
-
 
254
 
316
 
255
    /* Verify that thread t may be operated on */
317
    /* On success, this will lock t->debug_lock */
256
    rc = verify_thread(t, ta);
318
    rc = _thread_op_begin(phone, t);
257
    if (rc != EOK) {
319
    if (rc != EOK) {
258
        spinlock_unlock(&t->debug_lock);
-
 
259
        spinlock_unlock(&threads_lock);
-
 
260
        interrupts_restore(ipl);
320
        interrupts_restore(ipl);
261
        return rc;
321
        return rc;
262
    }
322
    }
263
 
323
 
264
    /*
-
 
265
     * Since t->debug_active == true and t->debug_lock is held,
-
 
266
     * we can safely release threads_lock and t will continue
-
 
267
     * to exist (and will stay in debug_active state)
-
 
268
     */
-
 
269
    spinlock_unlock(&threads_lock);
-
 
270
 
-
 
271
    t->debug_go_call = call;
324
    t->debug_go_call = call;
272
    t->debug_stop = false;
325
    t->debug_stop = false;
273
 
326
 
274
    /*
327
    /*
275
     * Neither t's lock nor threads_lock may be held during wakeup
328
     * Neither t's lock nor threads_lock may be held during wakeup
276
     */
329
     */
277
    waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
330
    waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
278
 
331
 
279
    spinlock_unlock(&t->debug_lock);
332
    _thread_op_end(t);
280
    interrupts_restore(ipl);
333
    interrupts_restore(ipl);
281
 
334
 
282
    return 0; /* no backsend */
335
    return 0; /* no backsend */
283
}
336
}
284
 
337
 
285
static int udebug_rp_args_read(call_t *call, phone_t *phone)
338
static int udebug_rp_args_read(call_t *call, phone_t *phone)
286
{
339
{
287
    thread_t *t;
340
    thread_t *t;
288
    task_t *ta;
-
 
289
    void *uspace_buffer;
341
    void *uspace_buffer;
290
    int rc;
342
    int rc;
291
    ipl_t ipl;
343
    ipl_t ipl;
292
    unative_t buffer[6];
344
    unative_t buffer[6];
293
 
345
 
294
    klog_printf("debug_args_read()");
346
    klog_printf("debug_args_read()");
295
 
347
 
296
    ipl = interrupts_disable();
-
 
297
    ta = get_lock_callee_task(phone);
-
 
298
    klog_printf("task %llu", ta->taskid);
-
 
299
    spinlock_unlock(&ta->lock);
-
 
300
 
-
 
301
    t = (thread_t *) IPC_GET_ARG2(call->data);
348
    t = (thread_t *)IPC_GET_ARG2(call->data);
302
 
-
 
303
    spinlock_lock(&threads_lock);
-
 
304
 
-
 
305
    if (!thread_exists(t)) {
-
 
306
        spinlock_unlock(&threads_lock);
-
 
307
        interrupts_restore(ipl);       
-
 
308
        return ENOENT;
-
 
309
    }
-
 
310
 
349
 
311
    spinlock_lock(&t->debug_lock);
350
    ipl = interrupts_disable();
312
 
351
 
313
    /* Verify that thread t may be operated on */
352
    /* On success, this will lock t->debug_lock */
314
    rc = verify_thread(t, ta);
353
    rc = _thread_op_begin(phone, t);
315
    if (rc != EOK) {
354
    if (rc != EOK) {
316
        spinlock_unlock(&t->debug_lock);
-
 
317
        spinlock_unlock(&threads_lock);
-
 
318
        interrupts_restore(ipl);
355
        interrupts_restore(ipl);
319
        return rc;
356
        return rc;
320
    }
357
    }
321
 
358
 
322
    /*
-
 
323
     * We can now safely release threads_lock as debug_active == true
-
 
324
     * and t->debug_lock is held.
-
 
325
     */
-
 
326
    spinlock_unlock(&threads_lock);
-
 
327
 
-
 
328
    //FIXME: additionally we need to verify that we are inside a syscall
359
    //FIXME: additionally we need to verify that we are inside a syscall
329
 
360
 
330
    /* Copy to a local buffer before releasing the lock */
361
    /* Copy to a local buffer before releasing the lock */
331
    memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t));
362
    memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t));
332
 
363
 
333
    spinlock_unlock(&t->debug_lock);
364
    _thread_op_end(t);
334
    interrupts_restore(ipl);
365
    interrupts_restore(ipl);
335
 
366
 
336
    /* Now copy to userspace */
367
    /* Now copy to userspace */
337
 
368
 
338
    uspace_buffer = (void *)IPC_GET_ARG3(call->data);
369
    uspace_buffer = (void *)IPC_GET_ARG3(call->data);
339
 
370
 
340
    rc = copy_to_uspace(uspace_buffer, buffer, 6 * sizeof(unative_t));
371
    rc = copy_to_uspace(uspace_buffer, buffer, 6 * sizeof(unative_t));
341
    if (rc != 0) {
372
    if (rc != 0) {
342
        spinlock_unlock(&ta->lock);
-
 
343
        klog_printf("debug_args_read() - copy failed");
373
        klog_printf("debug_args_read() - copy failed");
344
        return rc;
374
        return rc;
345
    }
375
    }
346
 
376
 
347
    klog_printf("debug_args_read() done");
377
    klog_printf("debug_args_read() done");
Line 349... Line 379...
349
}
379
}
350
 
380
 
351
static int udebug_rp_regs_read(call_t *call, phone_t *phone)
381
static int udebug_rp_regs_read(call_t *call, phone_t *phone)
352
{
382
{
353
    thread_t *t;
383
    thread_t *t;
354
    task_t *ta;
-
 
355
    void *uspace_buffer;
384
    void *uspace_buffer;
356
    unative_t to_copy;
385
    unative_t to_copy;
357
    int rc;
386
    int rc;
358
    istate_t *state;
387
    istate_t *state;
359
    istate_t state_copy;
388
    istate_t state_copy;
360
    ipl_t ipl;
389
    ipl_t ipl;
361
 
390
 
362
    klog_printf("debug_regs_read()");
391
    klog_printf("debug_regs_read()");
363
 
392
 
364
    ta = get_lock_callee_task(phone);
-
 
365
    spinlock_unlock(&ta->lock);
-
 
366
    //FIXME: don't lock ta
-
 
367
 
-
 
368
    ipl = interrupts_disable();
-
 
369
    spinlock_lock(&threads_lock);
-
 
370
 
-
 
371
    t = (thread_t *) IPC_GET_ARG2(call->data);
393
    t = (thread_t *) IPC_GET_ARG2(call->data);
372
 
394
 
373
    if (!thread_exists(t)) {
-
 
374
        spinlock_unlock(&threads_lock);
-
 
375
        interrupts_restore(ipl);       
395
    ipl = interrupts_disable();
376
        return ENOENT;
-
 
377
    }
-
 
378
 
-
 
379
    spinlock_lock(&t->debug_lock);
-
 
380
 
396
 
381
    /* Verify that thread t may be operated on */
397
    /* On success, this will lock t->debug_lock */
382
    rc = verify_thread(t, ta);
398
    rc = _thread_op_begin(phone, t);
383
    if (rc != EOK) {
399
    if (rc != EOK) {
384
        spinlock_unlock(&t->debug_lock);
-
 
385
        spinlock_unlock(&threads_lock);
-
 
386
        interrupts_restore(ipl);
400
        interrupts_restore(ipl);
387
        return rc;
401
        return rc;
388
    }
402
    }
389
 
403
 
390
    /*
-
 
391
     * We can now safely release threads_lock as debug_active == true
-
 
392
     * and t->debug_lock is held.
-
 
393
     */
-
 
394
    spinlock_unlock(&threads_lock);
-
 
395
 
-
 
396
    state = t->uspace_state;
404
    state = t->uspace_state;
397
    if (state == NULL) {
405
    if (state == NULL) {
398
        spinlock_unlock(&threads_lock);
406
        _thread_op_end(t);
399
        interrupts_restore(ipl);
407
        interrupts_restore(ipl);
400
        klog_printf("debug_regs_read() - istate not available");
408
        klog_printf("debug_regs_read() - istate not available");
401
        return EBUSY;
409
        return EBUSY;
402
    }
410
    }
403
 
411
 
404
    /* Copy to a local buffer so that we can release the lock */
412
    /* Copy to a local buffer so that we can release the lock */
405
    memcpy(&state_copy, state, sizeof(state_copy));
413
    memcpy(&state_copy, state, sizeof(state_copy));
406
    spinlock_unlock(&t->debug_lock);
414
    _thread_op_end(t);
407
    interrupts_restore(ipl);
415
    interrupts_restore(ipl);
408
 
416
 
409
    uspace_buffer = (void *)IPC_GET_ARG3(call->data);
417
    uspace_buffer = (void *)IPC_GET_ARG3(call->data);
410
    to_copy = IPC_GET_ARG4(call->data);
418
    to_copy = IPC_GET_ARG4(call->data);
411
    if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
419
    if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
Line 421... Line 429...
421
 
429
 
422
    klog_printf("debug_regs_read() done");
430
    klog_printf("debug_regs_read() done");
423
    return 1; /* actually need becksend with retval 0 */
431
    return 1; /* actually need becksend with retval 0 */
424
}
432
}
425
 
433
 
-
 
434
 
-
 
435
 
426
static int udebug_rp_regs_write(call_t *call, phone_t *phone)
436
static int udebug_rp_regs_write(call_t *call, phone_t *phone)
427
{
437
{
428
    thread_t *t;
438
    thread_t *t;
429
    task_t *ta;
-
 
430
    void *uspace_data;
439
    void *uspace_data;
431
    unative_t to_copy;
440
    unative_t to_copy;
432
    int rc;
441
    int rc;
433
    istate_t *state;
442
    istate_t *state;
434
    istate_t data_copy;
443
    istate_t data_copy;
Line 446... Line 455...
446
    if (rc != 0) {
455
    if (rc != 0) {
447
        klog_printf("debug_regs_write() - copy failed");
456
        klog_printf("debug_regs_write() - copy failed");
448
        return rc;
457
        return rc;
449
    }
458
    }
450
 
459
 
451
    ta = get_lock_callee_task(phone);
-
 
452
    spinlock_unlock(&ta->lock);
-
 
453
    //FIXME: don't lock ta
-
 
454
 
-
 
455
    /* Now try to change the thread's uspace_state */
460
    /* Now try to change the thread's uspace_state */
456
 
461
 
457
    ipl = interrupts_disable();
462
    ipl = interrupts_disable();
458
    spinlock_lock(&threads_lock);
-
 
459
 
-
 
460
    t = (thread_t *) IPC_GET_ARG2(call->data);
463
    t = (thread_t *) IPC_GET_ARG2(call->data);
461
 
464
 
462
    if (!thread_exists(t)) {
-
 
463
        spinlock_unlock(&threads_lock);
-
 
464
        interrupts_restore(ipl);       
-
 
465
        return ENOENT;
-
 
466
    }
-
 
467
 
-
 
468
    spinlock_lock(&t->debug_lock);
465
    /* On success, this will lock t->debug_lock */
469
 
-
 
470
    /* Verify that thread t may be operated on */
-
 
471
    rc = verify_thread(t, ta);
466
    rc = _thread_op_begin(phone, t);
472
    if (rc != EOK) {
467
    if (rc != EOK) {
473
        spinlock_unlock(&t->debug_lock);
-
 
474
        spinlock_unlock(&threads_lock);
-
 
475
        interrupts_restore(ipl);
468
        interrupts_restore(ipl);
476
        return rc;
469
        return rc;
477
    }
470
    }
478
 
471
 
479
    state = t->uspace_state;
472
    state = t->uspace_state;
480
    if (state == NULL) {
473
    if (state == NULL) {
481
        spinlock_unlock(&t->debug_lock);
474
        _thread_op_end(t);
482
        interrupts_restore(ipl);
475
        interrupts_restore(ipl);
483
        klog_printf("debug_regs_write() - istate not available");
476
        klog_printf("debug_regs_write() - istate not available");
484
        return EBUSY;
477
        return EBUSY;
485
    }
478
    }
486
 
479
 
487
    memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state));
480
    memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state));
488
 
481
 
489
    spinlock_unlock(&t->debug_lock);
482
    _thread_op_end(t);
490
    interrupts_restore(ipl);
483
    interrupts_restore(ipl);
491
 
484
 
492
    /* Set answer values */
485
    /* Set answer values */
493
 
486
 
494
    IPC_SET_ARG1(call->data, to_copy);
487
    IPC_SET_ARG1(call->data, to_copy);