Subversion Repositories HelenOS

Rev

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

Rev 3441 Rev 3457
Line 30... Line 30...
30
 * @{
30
 * @{
31
 */
31
 */
32
 
32
 
33
/**
33
/**
34
 * @file
34
 * @file
35
 * @brief   Udebug.
35
 * @brief   Udebug hooks and data structure management.
-
 
36
 *
-
 
37
 * Udebug is an interface that makes userspace debuggers possible.
36
 *
38
 *
37
 * Functions in this file are executed directly in each thread, which
39
 * Functions in this file are executed directly in each thread, which
38
 * may or may not be the subject of debugging. The udebug_stoppable_begin/end()
40
 * may or may not be the subject of debugging. The udebug_stoppable_begin/end()
39
 * functions are also executed in the clock interrupt handler. To avoid
41
 * functions are also executed in the clock interrupt handler. To avoid
40
 * deadlock, functions in this file are protected from the interrupt
42
 * deadlock, functions in this file are protected from the interrupt
Line 61... Line 63...
61
static inline void udebug_int_unlock(void)
63
static inline void udebug_int_unlock(void)
62
{
64
{
63
    atomic_dec(&THREAD->udebug.int_lock);
65
    atomic_dec(&THREAD->udebug.int_lock);
64
}
66
}
65
 
67
 
-
 
68
/** Initialize udebug part of task structure.
-
 
69
 *
-
 
70
 * Called as part of task structure initialization.
-
 
71
 * @param ut    Pointer to the structure to initialize.
-
 
72
 */
66
void udebug_task_init(udebug_task_t *ut)
73
void udebug_task_init(udebug_task_t *ut)
67
{
74
{
68
    mutex_initialize(&ut->lock, MUTEX_PASSIVE);
75
    mutex_initialize(&ut->lock, MUTEX_PASSIVE);
69
    ut->dt_state = UDEBUG_TS_INACTIVE;
76
    ut->dt_state = UDEBUG_TS_INACTIVE;
70
    ut->begin_call = NULL;
77
    ut->begin_call = NULL;
71
    ut->not_stoppable_count = 0;
78
    ut->not_stoppable_count = 0;
72
    ut->evmask = 0;
79
    ut->evmask = 0;
73
}
80
}
74
 
81
 
-
 
82
/** Initialize udebug part of thread structure.
-
 
83
 *
-
 
84
 * Called as part of thread structure initialization.
-
 
85
 * @param ut    Pointer to the structure to initialize.
-
 
86
 */
75
void udebug_thread_initialize(udebug_thread_t *ut)
87
void udebug_thread_initialize(udebug_thread_t *ut)
76
{
88
{
77
    mutex_initialize(&ut->lock, MUTEX_PASSIVE);
89
    mutex_initialize(&ut->lock, MUTEX_PASSIVE);
78
    waitq_initialize(&ut->go_wq);
90
    waitq_initialize(&ut->go_wq);
79
 
91
 
Line 87... Line 99...
87
    ut->stoppable = true;
99
    ut->stoppable = true;
88
    ut->debug_active = false;
100
    ut->debug_active = false;
89
    ut->cur_event = 0; /* none */
101
    ut->cur_event = 0; /* none */
90
}
102
}
91
 
103
 
-
 
104
/** Wait for a GO message.
-
 
105
 *
-
 
106
 * When a debugging event occurs in a thread or the thread is stopped,
-
 
107
 * this function is called to block the thread until a GO message
-
 
108
 * is received.
-
 
109
 *
-
 
110
 * @param wq    The wait queue used by the thread to wait for GO messages.
-
 
111
 */
92
static void udebug_wait_for_go(waitq_t *wq)
112
static void udebug_wait_for_go(waitq_t *wq)
93
{
113
{
94
    int rc;
114
    int rc;
95
    ipl_t ipl;
115
    ipl_t ipl;
96
 
116
 
Line 102... Line 122...
102
    waitq_sleep_finish(wq, rc, ipl);
122
    waitq_sleep_finish(wq, rc, ipl);
103
}
123
}
104
 
124
 
105
/** Do a preliminary check that a debugging session is in progress.
125
/** Do a preliminary check that a debugging session is in progress.
106
 *
126
 *
107
 * This only requires the THREAD->udebug.lock mutex (and not
127
 * This only requires the THREAD->udebug.lock mutex (and not TASK->udebug.lock
108
 * TASK->udebug.lock mutex). For an undebugged task, this will
128
 * mutex). For an undebugged task, this will never block (while there could be
109
 * never block (while there could be collisions by different threads
129
 * collisions by different threads on the TASK mutex), thus improving SMP
110
 * on the TASK mutex), thus improving SMP perormance for undebugged tasks.
130
 * perormance for undebugged tasks.
-
 
131
 *
-
 
132
 * @return  True if the thread was in a debugging session when the function
-
 
133
 *      checked, false otherwise.
111
 */
134
 */
112
static bool udebug_thread_precheck(void)
135
static bool udebug_thread_precheck(void)
113
{
136
{
114
    bool res;
137
    bool res;
115
 
138
 
Line 118... Line 141...
118
    mutex_unlock(&THREAD->udebug.lock);
141
    mutex_unlock(&THREAD->udebug.lock);
119
 
142
 
120
    return res;
143
    return res;
121
}
144
}
122
 
145
 
-
 
146
/** Start of stoppable section.
-
 
147
 *
-
 
148
 * A stoppable section is a section of code where if the thread can be stoped. In other words,
-
 
149
 * if a STOP operation is issued, the thread is guaranteed not to execute
-
 
150
 * any userspace instructions until the thread is resumed.
-
 
151
 *
-
 
152
 * Having stoppable sections is better than having stopping points, since
-
 
153
 * a thread can be stopped even when it is blocked indefinitely in a system
-
 
154
 * call (whereas it would not reach any stopping point).
-
 
155
 */
123
void udebug_stoppable_begin(void)
156
void udebug_stoppable_begin(void)
124
{
157
{
125
    int nsc;
158
    int nsc;
126
    call_t *db_call, *go_call;
159
    call_t *db_call, *go_call;
127
 
160
 
Line 186... Line 219...
186
 
219
 
187
    mutex_unlock(&THREAD->udebug.lock);
220
    mutex_unlock(&THREAD->udebug.lock);
188
        mutex_unlock(&TASK->udebug.lock);
221
        mutex_unlock(&TASK->udebug.lock);
189
}
222
}
190
 
223
 
-
 
224
/** End of a stoppable section.
-
 
225
 *
-
 
226
 * This is the point where the thread will block if it is stopped.
-
 
227
 * (As, by definition, a stopped thread must not leave its stoppable section).
-
 
228
 */
191
void udebug_stoppable_end(void)
229
void udebug_stoppable_end(void)
192
{
230
{
193
    /* Early check for undebugged tasks */
231
    /* Early check for undebugged tasks */
194
    if (!udebug_thread_precheck()) {
232
    if (!udebug_thread_precheck()) {
195
        udebug_int_unlock();
233
        udebug_int_unlock();
Line 256... Line 294...
256
    interrupts_restore(ipl);
294
    interrupts_restore(ipl);
257
 
295
 
258
    udebug_int_unlock();
296
    udebug_int_unlock();
259
}
297
}
260
 
298
 
-
 
299
/** Syscall event hook.
-
 
300
 *
-
 
301
 * Must be called before and after servicing a system call. This generates
-
 
302
 * a SYSCALL_B or SYSCALL_E event, depending on the value of @a end_variant.
-
 
303
 */
261
void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
304
void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
262
    unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc,
305
    unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc,
263
    bool end_variant)
306
    bool end_variant)
264
{
307
{
265
    call_t *call;
308
    call_t *call;
Line 320... Line 363...
320
    udebug_wait_for_go(&THREAD->udebug.go_wq);
363
    udebug_wait_for_go(&THREAD->udebug.go_wq);
321
 
364
 
322
    udebug_int_unlock();
365
    udebug_int_unlock();
323
}
366
}
324
 
367
 
-
 
368
/** Thread-creation event hook.
-
 
369
 *
-
 
370
 * Must be called when a new userspace thread is created in the debugged
-
 
371
 * task. Generates a THREAD_B event.
-
 
372
 *
-
 
373
 * @param t Structure of the thread being created. Not locked, as the
-
 
374
 *      thread is not executing yet.
-
 
375
 */
325
void udebug_thread_b_event(struct thread *t)
376
void udebug_thread_b_event(struct thread *t)
326
{
377
{
327
    call_t *call;
378
    call_t *call;
328
 
379
 
329
    udebug_int_lock();
380
    udebug_int_lock();
Line 369... Line 420...
369
    udebug_wait_for_go(&THREAD->udebug.go_wq);
420
    udebug_wait_for_go(&THREAD->udebug.go_wq);
370
 
421
 
371
    udebug_int_unlock();
422
    udebug_int_unlock();
372
}
423
}
373
 
424
 
-
 
425
/** Thread-termination event hook.
-
 
426
 *
-
 
427
 * Must be called when the current thread is terminating.
-
 
428
 * Generates a THREAD_E event.
-
 
429
 */
374
void udebug_thread_e_event(void)
430
void udebug_thread_e_event(void)
375
{
431
{
376
    call_t *call;
432
    call_t *call;
377
 
433
 
378
    udebug_int_lock();
434
    udebug_int_lock();
Line 415... Line 471...
415
}
471
}
416
 
472
 
417
/**
473
/**
418
 * Terminate task debugging session.
474
 * Terminate task debugging session.
419
 *
475
 *
-
 
476
 * Gracefully terminates the debugging session for a task. If the debugger
-
 
477
 * is still waiting for events on some threads, it will receive a
-
 
478
 * FINISHED event for each of them.
-
 
479
 *
420
 * \param ta->udebug.lock must be already locked.
480
 * @param ta    Task structure. ta->udebug.lock must be already locked.
421
 * \return Zero on success or negative error code.
481
 * @return  Zero on success or negative error code.
422
 */
482
 */
423
int udebug_task_cleanup(struct task *ta)
483
int udebug_task_cleanup(struct task *ta)
424
{
484
{
425
    thread_t *t;
485
    thread_t *t;
426
    link_t *cur;
486
    link_t *cur;