Subversion Repositories HelenOS

Rev

Rev 3428 | Rev 3606 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2894 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
 
2801 svoboda 29
/** @addtogroup generic
30
 * @{
31
 */
32
 
33
/**
34
 * @file
3471 svoboda 35
 * @brief   Udebug hooks and data structure management.
3031 svoboda 36
 *
3471 svoboda 37
 * Udebug is an interface that makes userspace debuggers possible.
38
 *
3031 svoboda 39
 * Functions in this file are executed directly in each thread, which
40
 * may or may not be the subject of debugging. The udebug_stoppable_begin/end()
41
 * functions are also executed in the clock interrupt handler. To avoid
42
 * deadlock, functions in this file are protected from the interrupt
43
 * by locking the recursive lock THREAD->udebug.int_lock (just an atomic
44
 * variable). This prevents udebug_stoppable_begin/end() from being
45
 * executed in the interrupt handler (they are skipped).
46
 *
47
 * Functions in udebug_ops.c and udebug_ipc.c execute in different threads,
48
 * so they needn't be protected from the (preemptible) interrupt-initiated
49
 * code.
2801 svoboda 50
 */
51
 
52
#include <synch/waitq.h>
3471 svoboda 53
#include <debug.h>
2813 svoboda 54
#include <udebug/udebug.h>
2870 svoboda 55
#include <errno.h>
2801 svoboda 56
#include <arch.h>
57
 
3026 svoboda 58
static inline void udebug_int_lock(void)
59
{
60
    atomic_inc(&THREAD->udebug.int_lock);
61
}
62
 
63
static inline void udebug_int_unlock(void)
64
{
65
    atomic_dec(&THREAD->udebug.int_lock);
66
}
67
 
3471 svoboda 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
 */
3014 svoboda 73
void udebug_task_init(udebug_task_t *ut)
74
{
3426 svoboda 75
    mutex_initialize(&ut->lock, MUTEX_PASSIVE);
3014 svoboda 76
    ut->dt_state = UDEBUG_TS_INACTIVE;
77
    ut->begin_call = NULL;
78
    ut->not_stoppable_count = 0;
79
    ut->evmask = 0;
80
}
81
 
3471 svoboda 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
 */
3018 svoboda 87
void udebug_thread_initialize(udebug_thread_t *ut)
88
{
3426 svoboda 89
    mutex_initialize(&ut->lock, MUTEX_PASSIVE);
3018 svoboda 90
    waitq_initialize(&ut->go_wq);
3026 svoboda 91
 
92
    /*
93
     * At the beginning the thread is stoppable, so int_lock be set, too.
94
     */
95
    atomic_set(&ut->int_lock, 1);
96
 
3018 svoboda 97
    ut->go_call = NULL;
98
    ut->uspace_state = NULL;
99
    ut->stop = true;
100
    ut->stoppable = true;
101
    ut->debug_active = false;
102
    ut->cur_event = 0; /* none */
103
}
104
 
3471 svoboda 105
/** Wait for a GO message.
106
 *
107
 * When a debugging event occurs in a thread or the thread is stopped,
108
 * this function is called to block the thread until a GO message
109
 * is received.
110
 *
111
 * @param wq    The wait queue used by the thread to wait for GO messages.
112
 */
2917 svoboda 113
static void udebug_wait_for_go(waitq_t *wq)
114
{
115
    int rc;
116
    ipl_t ipl;
117
 
118
    ipl = waitq_sleep_prepare(wq);
119
 
120
    wq->missed_wakeups = 0; /* Enforce blocking. */
121
    rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
122
 
123
    waitq_sleep_finish(wq, rc, ipl);
124
}
125
 
3030 svoboda 126
/** Do a preliminary check that a debugging session is in progress.
127
 *
3471 svoboda 128
 * This only requires the THREAD->udebug.lock mutex (and not TASK->udebug.lock
129
 * mutex). For an undebugged task, this will never block (while there could be
130
 * collisions by different threads on the TASK mutex), thus improving SMP
131
 * perormance for undebugged tasks.
132
 *
133
 * @return  True if the thread was in a debugging session when the function
134
 *      checked, false otherwise.
3030 svoboda 135
 */
136
static bool udebug_thread_precheck(void)
137
{
138
    bool res;
139
 
140
    mutex_lock(&THREAD->udebug.lock);
141
    res = THREAD->udebug.debug_active;
142
    mutex_unlock(&THREAD->udebug.lock);
143
 
144
    return res;
145
}
146
 
3471 svoboda 147
/** Start of stoppable section.
148
 *
149
 * A stoppable section is a section of code where if the thread can be stoped. In other words,
150
 * if a STOP operation is issued, the thread is guaranteed not to execute
151
 * any userspace instructions until the thread is resumed.
152
 *
153
 * Having stoppable sections is better than having stopping points, since
154
 * a thread can be stopped even when it is blocked indefinitely in a system
155
 * call (whereas it would not reach any stopping point).
156
 */
2804 svoboda 157
void udebug_stoppable_begin(void)
2801 svoboda 158
{
2804 svoboda 159
    int nsc;
2898 svoboda 160
    call_t *db_call, *go_call;
2804 svoboda 161
 
2902 svoboda 162
    ASSERT(THREAD);
163
    ASSERT(TASK);
164
 
3026 svoboda 165
    udebug_int_lock();
166
 
3030 svoboda 167
    /* Early check for undebugged tasks */
168
    if (!udebug_thread_precheck()) {
169
        udebug_int_unlock();
170
        return;
171
    }
172
 
3016 svoboda 173
    mutex_lock(&TASK->udebug.lock);
2804 svoboda 174
 
3014 svoboda 175
    nsc = --TASK->udebug.not_stoppable_count;
2804 svoboda 176
 
3032 svoboda 177
    /* Lock order OK, THREAD->udebug.lock is after TASK->udebug.lock */
178
    mutex_lock(&THREAD->udebug.lock);
179
    ASSERT(THREAD->udebug.stoppable == false);
180
    THREAD->udebug.stoppable = true;
2804 svoboda 181
 
3014 svoboda 182
    if (TASK->udebug.dt_state == UDEBUG_TS_BEGINNING && nsc == 0) {
2898 svoboda 183
        /*
184
         * This was the last non-stoppable thread. Reply to
185
         * DEBUG_BEGIN call.
186
         */
187
 
3014 svoboda 188
        db_call = TASK->udebug.begin_call;
2902 svoboda 189
        ASSERT(db_call);
190
 
3014 svoboda 191
        TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
192
        TASK->udebug.begin_call = NULL;
2804 svoboda 193
 
194
        IPC_SET_RETVAL(db_call->data, 0);
195
        ipc_answer(&TASK->answerbox, db_call);     
2898 svoboda 196
 
3014 svoboda 197
    } else if (TASK->udebug.dt_state == UDEBUG_TS_ACTIVE) {
2898 svoboda 198
        /*
199
         * Active debugging session
200
         */
201
 
3018 svoboda 202
        if (THREAD->udebug.debug_active && THREAD->udebug.stop) {
2898 svoboda 203
            /*
204
             * Thread was requested to stop - answer go call
205
             */
206
 
207
            /* Make sure nobody takes this call away from us */
3018 svoboda 208
            go_call = THREAD->udebug.go_call;
209
            THREAD->udebug.go_call = NULL;
2902 svoboda 210
            ASSERT(go_call);
2898 svoboda 211
 
212
            IPC_SET_RETVAL(go_call->data, 0);
213
            IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP);
214
 
3018 svoboda 215
            THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
2898 svoboda 216
 
217
                ipc_answer(&TASK->answerbox, go_call);
218
        }
3032 svoboda 219
    }
2898 svoboda 220
 
3032 svoboda 221
    mutex_unlock(&THREAD->udebug.lock);
222
        mutex_unlock(&TASK->udebug.lock);
2804 svoboda 223
}
224
 
3471 svoboda 225
/** End of a stoppable section.
226
 *
227
 * This is the point where the thread will block if it is stopped.
228
 * (As, by definition, a stopped thread must not leave its stoppable section).
229
 */
2804 svoboda 230
void udebug_stoppable_end(void)
231
{
3030 svoboda 232
    /* Early check for undebugged tasks */
233
    if (!udebug_thread_precheck()) {
234
        udebug_int_unlock();
235
        return;
236
    }
237
 
2804 svoboda 238
restart:
3016 svoboda 239
    mutex_lock(&TASK->udebug.lock);
3026 svoboda 240
    mutex_lock(&THREAD->udebug.lock);
2898 svoboda 241
 
3018 svoboda 242
    if (THREAD->udebug.debug_active &&
243
        THREAD->udebug.stop == true) {
3014 svoboda 244
        TASK->udebug.begin_call = NULL;
3026 svoboda 245
        mutex_unlock(&THREAD->udebug.lock);
3016 svoboda 246
        mutex_unlock(&TASK->udebug.lock);
2823 svoboda 247
 
3018 svoboda 248
        udebug_wait_for_go(&THREAD->udebug.go_wq);
2917 svoboda 249
 
2804 svoboda 250
        goto restart;
251
        /* must try again - have to lose stoppability atomically */
252
    } else {
3014 svoboda 253
        ++TASK->udebug.not_stoppable_count;
3026 svoboda 254
        ASSERT(THREAD->udebug.stoppable == true);
3018 svoboda 255
        THREAD->udebug.stoppable = false;
2898 svoboda 256
 
3026 svoboda 257
        mutex_unlock(&THREAD->udebug.lock);
3016 svoboda 258
        mutex_unlock(&TASK->udebug.lock);
2801 svoboda 259
    }
3026 svoboda 260
 
261
    udebug_int_unlock();
2801 svoboda 262
}
263
 
3015 svoboda 264
/** Upon being scheduled to run, check if the current thread should stop.
265
 *
266
 * This function is called from clock(). Preemption is enabled.
267
 * interrupts are disabled, but since this is called after
268
 * being scheduled-in, we can enable them, if we're careful enough
3026 svoboda 269
 * not to allow arbitrary recursion or deadlock with the thread context.
3015 svoboda 270
 */
271
void udebug_before_thread_runs(void)
272
{
273
    ipl_t ipl;
274
 
3108 svoboda 275
    return;
3026 svoboda 276
    ASSERT(!PREEMPTION_DISABLED);
277
 
278
    /*
279
     * Prevent agains re-entering, such as when preempted inside this
280
     * function.
281
     */
282
    if (atomic_get(&THREAD->udebug.int_lock) != 0)
3015 svoboda 283
        return;
284
 
3026 svoboda 285
    udebug_int_lock();
286
 
3015 svoboda 287
    ipl = interrupts_enable();
288
 
3016 svoboda 289
    /* Now we're free to do whatever we need (lock mutexes, sleep, etc.) */
3015 svoboda 290
 
291
    /* Check if we're supposed to stop */
292
    udebug_stoppable_begin();
293
    udebug_stoppable_end();
294
 
295
    interrupts_restore(ipl);
3026 svoboda 296
 
297
    udebug_int_unlock();
3015 svoboda 298
}
299
 
3471 svoboda 300
/** Syscall event hook.
301
 *
302
 * Must be called before and after servicing a system call. This generates
303
 * a SYSCALL_B or SYSCALL_E event, depending on the value of @a end_variant.
304
 */
2805 svoboda 305
void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
2901 svoboda 306
    unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc,
307
    bool end_variant)
2801 svoboda 308
{
2805 svoboda 309
    call_t *call;
2901 svoboda 310
    udebug_event_t etype;
2805 svoboda 311
 
2901 svoboda 312
    etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B;
313
 
3026 svoboda 314
    udebug_int_lock();
315
 
3030 svoboda 316
    /* Early check for undebugged tasks */
317
    if (!udebug_thread_precheck()) {
318
        udebug_int_unlock();
319
        return;
320
    }
321
 
3016 svoboda 322
    mutex_lock(&TASK->udebug.lock);
3026 svoboda 323
    mutex_lock(&THREAD->udebug.lock);
3016 svoboda 324
 
2854 svoboda 325
    /* Must only generate events when in debugging session and have go */
3018 svoboda 326
    if (THREAD->udebug.debug_active != true ||
327
        THREAD->udebug.stop == true ||
3014 svoboda 328
        (TASK->udebug.evmask & UDEBUG_EVMASK(etype)) == 0) {
3026 svoboda 329
        mutex_unlock(&THREAD->udebug.lock);
3016 svoboda 330
        mutex_unlock(&TASK->udebug.lock);
2867 svoboda 331
        return;
332
    }
2804 svoboda 333
 
3424 svoboda 334
    //printf("udebug_syscall_event\n");
3018 svoboda 335
    call = THREAD->udebug.go_call;
336
    THREAD->udebug.go_call = NULL;
3016 svoboda 337
 
2867 svoboda 338
    IPC_SET_RETVAL(call->data, 0);
2901 svoboda 339
    IPC_SET_ARG1(call->data, etype);
2867 svoboda 340
    IPC_SET_ARG2(call->data, id);
341
    IPC_SET_ARG3(call->data, rc);
3424 svoboda 342
    //printf("udebug_syscall_event/ipc_answer\n");
2805 svoboda 343
 
3018 svoboda 344
    THREAD->udebug.syscall_args[0] = a1;
345
    THREAD->udebug.syscall_args[1] = a2;
346
    THREAD->udebug.syscall_args[2] = a3;
347
    THREAD->udebug.syscall_args[3] = a4;
348
    THREAD->udebug.syscall_args[4] = a5;
349
    THREAD->udebug.syscall_args[5] = a6;
2866 svoboda 350
 
2867 svoboda 351
    /*
3018 svoboda 352
     * Make sure udebug.stop is true when going to sleep
2867 svoboda 353
     * in case we get woken up by DEBUG_END. (At which
354
     * point it must be back to the initial true value).
355
     */
3018 svoboda 356
    THREAD->udebug.stop = true;
357
    THREAD->udebug.cur_event = etype;
2867 svoboda 358
 
3016 svoboda 359
    ipc_answer(&TASK->answerbox, call);
360
 
3032 svoboda 361
    mutex_unlock(&THREAD->udebug.lock);
3016 svoboda 362
    mutex_unlock(&TASK->udebug.lock);
363
 
3018 svoboda 364
    udebug_wait_for_go(&THREAD->udebug.go_wq);
3026 svoboda 365
 
366
    udebug_int_unlock();
2867 svoboda 367
}
368
 
3471 svoboda 369
/** Thread-creation event hook.
370
 *
371
 * Must be called when a new userspace thread is created in the debugged
372
 * task. Generates a THREAD_B event.
373
 *
374
 * @param t Structure of the thread being created. Not locked, as the
375
 *      thread is not executing yet.
376
 */
2903 svoboda 377
void udebug_thread_b_event(struct thread *t)
2867 svoboda 378
{
379
    call_t *call;
380
 
3026 svoboda 381
    udebug_int_lock();
382
 
3016 svoboda 383
    mutex_lock(&TASK->udebug.lock);
3026 svoboda 384
    mutex_lock(&THREAD->udebug.lock);
3016 svoboda 385
 
3471 svoboda 386
    LOG("udebug_thread_b_event\n");
387
    LOG("- check state\n");
2867 svoboda 388
 
389
    /* Must only generate events when in debugging session */
3018 svoboda 390
    if (THREAD->udebug.debug_active != true) {
3471 svoboda 391
        LOG("- debug_active: %s, udebug.stop: %s\n",
3018 svoboda 392
            THREAD->udebug.debug_active ? "yes(+)" : "no(-)",
393
            THREAD->udebug.stop ? "yes(-)" : "no(+)");
3026 svoboda 394
        mutex_unlock(&THREAD->udebug.lock);
3016 svoboda 395
        mutex_unlock(&TASK->udebug.lock);
2867 svoboda 396
        return;
2801 svoboda 397
    }
2867 svoboda 398
 
3471 svoboda 399
    LOG("- trigger event\n");
2867 svoboda 400
 
3018 svoboda 401
    call = THREAD->udebug.go_call;
402
    THREAD->udebug.go_call = NULL;
2867 svoboda 403
    IPC_SET_RETVAL(call->data, 0);
2903 svoboda 404
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_B);
2867 svoboda 405
    IPC_SET_ARG2(call->data, (unative_t)t);
406
 
407
    /*
3018 svoboda 408
     * Make sure udebug.stop is true when going to sleep
2867 svoboda 409
     * in case we get woken up by DEBUG_END. (At which
410
     * point it must be back to the initial true value).
411
     */
3018 svoboda 412
    THREAD->udebug.stop = true;
413
    THREAD->udebug.cur_event = UDEBUG_EVENT_THREAD_B;
2867 svoboda 414
 
3016 svoboda 415
    ipc_answer(&TASK->answerbox, call);
2867 svoboda 416
 
3032 svoboda 417
    mutex_unlock(&THREAD->udebug.lock);
3016 svoboda 418
    mutex_unlock(&TASK->udebug.lock);
419
 
3471 svoboda 420
    LOG("- sleep\n");
3018 svoboda 421
    udebug_wait_for_go(&THREAD->udebug.go_wq);
3026 svoboda 422
 
423
    udebug_int_unlock();
2801 svoboda 424
}
425
 
3471 svoboda 426
/** Thread-termination event hook.
427
 *
428
 * Must be called when the current thread is terminating.
429
 * Generates a THREAD_E event.
430
 */
2903 svoboda 431
void udebug_thread_e_event(void)
432
{
433
    call_t *call;
434
 
3026 svoboda 435
    udebug_int_lock();
436
 
3016 svoboda 437
    mutex_lock(&TASK->udebug.lock);
3026 svoboda 438
    mutex_lock(&THREAD->udebug.lock);
3016 svoboda 439
 
3471 svoboda 440
    LOG("udebug_thread_e_event\n");
441
    LOG("- check state\n");
2903 svoboda 442
 
443
    /* Must only generate events when in debugging session */
3018 svoboda 444
    if (THREAD->udebug.debug_active != true) {
3428 svoboda 445
/*      printf("- debug_active: %s, udebug.stop: %s\n",
3018 svoboda 446
            THREAD->udebug.debug_active ? "yes(+)" : "no(-)",
3428 svoboda 447
            THREAD->udebug.stop ? "yes(-)" : "no(+)");*/
3026 svoboda 448
        mutex_unlock(&THREAD->udebug.lock);
3016 svoboda 449
        mutex_unlock(&TASK->udebug.lock);
2903 svoboda 450
        return;
451
    }
452
 
3471 svoboda 453
    LOG("- trigger event\n");
2903 svoboda 454
 
3018 svoboda 455
    call = THREAD->udebug.go_call;
456
    THREAD->udebug.go_call = NULL;
2903 svoboda 457
    IPC_SET_RETVAL(call->data, 0);
458
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_E);
459
 
2908 svoboda 460
    /* Prevent any further debug activity in thread */
3018 svoboda 461
    THREAD->udebug.debug_active = false;
462
    THREAD->udebug.cur_event = 0;       /* none */
463
    THREAD->udebug.stop = true; /* set to initial value */
3016 svoboda 464
 
465
    ipc_answer(&TASK->answerbox, call);
2903 svoboda 466
 
3032 svoboda 467
    mutex_unlock(&THREAD->udebug.lock);
3016 svoboda 468
    mutex_unlock(&TASK->udebug.lock);
2903 svoboda 469
 
3026 svoboda 470
    /* Leave int_lock enabled */
2908 svoboda 471
    /* This event does not sleep - debugging has finished in this thread */
2903 svoboda 472
}
473
 
2921 svoboda 474
static void breakpoint_trap_event(uintptr_t addr, udebug_event_t etype)
2918 svoboda 475
{
476
    call_t *call;
2903 svoboda 477
 
3026 svoboda 478
    udebug_int_lock();
479
 
3016 svoboda 480
    mutex_lock(&TASK->udebug.lock);
3026 svoboda 481
    mutex_lock(&THREAD->udebug.lock);
3016 svoboda 482
 
2918 svoboda 483
    /* Must only generate events when in debugging session and have go */
3018 svoboda 484
    if (THREAD->udebug.debug_active != true ||
3030 svoboda 485
        THREAD->udebug.stop == true) {
3026 svoboda 486
        mutex_unlock(&THREAD->udebug.lock);
3016 svoboda 487
        mutex_unlock(&TASK->udebug.lock);
3030 svoboda 488
        udebug_int_unlock();
2918 svoboda 489
        return;
490
    }
491
 
3030 svoboda 492
    /* Verify that the event is enabled */
493
    if ((TASK->udebug.evmask & UDEBUG_EVMASK(etype)) == 0) {
494
        mutex_unlock(&THREAD->udebug.lock);
495
        mutex_unlock(&TASK->udebug.lock);
496
        udebug_int_unlock();
497
        return;
498
    }
499
 
3424 svoboda 500
    printf("udebug_breakpoint/trap_event\n");
3018 svoboda 501
    call = THREAD->udebug.go_call;
502
    THREAD->udebug.go_call = NULL;
3016 svoboda 503
 
2918 svoboda 504
    IPC_SET_RETVAL(call->data, 0);
505
    IPC_SET_ARG1(call->data, etype);
506
    IPC_SET_ARG2(call->data, addr);
507
 
508
    /*
3018 svoboda 509
     * Make sure udebug.stop is true when going to sleep
2918 svoboda 510
     * in case we get woken up by DEBUG_END. (At which
511
     * point it must be back to the initial true value).
512
     */
3018 svoboda 513
    THREAD->udebug.stop = true;
514
    THREAD->udebug.cur_event = etype;
3026 svoboda 515
 
3424 svoboda 516
    printf("- send answer\n");
3032 svoboda 517
    ipc_answer(&TASK->answerbox, call);
2918 svoboda 518
 
3032 svoboda 519
    mutex_unlock(&THREAD->udebug.lock);
3016 svoboda 520
    mutex_unlock(&TASK->udebug.lock);
2918 svoboda 521
 
3018 svoboda 522
    udebug_wait_for_go(&THREAD->udebug.go_wq);
3026 svoboda 523
 
524
    udebug_int_unlock();
2918 svoboda 525
}
526
 
2921 svoboda 527
void udebug_breakpoint_event(uintptr_t addr)
528
{
529
    breakpoint_trap_event(addr, UDEBUG_EVENT_BREAKPOINT);
530
}
2918 svoboda 531
 
2921 svoboda 532
void udebug_trap_event(uintptr_t addr)
533
{
534
    breakpoint_trap_event(addr, UDEBUG_EVENT_TRAP);
535
}
536
 
2870 svoboda 537
/**
538
 * Terminate task debugging session.
539
 *
3471 svoboda 540
 * Gracefully terminates the debugging session for a task. If the debugger
541
 * is still waiting for events on some threads, it will receive a
542
 * FINISHED event for each of them.
543
 *
544
 * @param ta    Task structure. ta->udebug.lock must be already locked.
545
 * @return  Zero on success or negative error code.
2870 svoboda 546
 */
547
int udebug_task_cleanup(struct task *ta)
548
{
549
    thread_t *t;
550
    link_t *cur;
551
    int flags;
3016 svoboda 552
    ipl_t ipl;
2867 svoboda 553
 
3471 svoboda 554
    LOG("udebug_task_cleanup()\n");
555
    LOG("task %" PRIu64 "\n", ta->taskid);
2870 svoboda 556
 
3026 svoboda 557
    udebug_int_lock();
558
 
3032 svoboda 559
    if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING &&
3014 svoboda 560
        ta->udebug.dt_state != UDEBUG_TS_ACTIVE) {
3471 svoboda 561
        LOG("udebug_task_cleanup(): task not being debugged\n");
2870 svoboda 562
        return EINVAL;
563
    }
564
 
565
    /* Finish debugging of all userspace threads */
566
    for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
567
        t = list_get_instance(cur, thread_t, th_link);
568
 
3026 svoboda 569
        mutex_lock(&t->udebug.lock);
570
 
3016 svoboda 571
        ipl = interrupts_disable();
2870 svoboda 572
        spinlock_lock(&t->lock);
573
 
574
        flags = t->flags;
575
 
576
        spinlock_unlock(&t->lock);
3026 svoboda 577
        interrupts_restore(ipl);
2870 svoboda 578
 
579
        /* Only process userspace threads */
580
        if ((flags & THREAD_FLAG_USPACE) != 0) {
581
            /* Prevent any further debug activity in thread */
3018 svoboda 582
            t->udebug.debug_active = false;
583
            t->udebug.cur_event = 0;    /* none */
2870 svoboda 584
 
585
            /* Still has go? */
3018 svoboda 586
            if (t->udebug.stop == false) {
2870 svoboda 587
                /*
588
                * Yes, so clear go. As debug_active == false,
589
                 * this doesn't affect anything.
590
                 */
3018 svoboda 591
                t->udebug.stop = true; 
2870 svoboda 592
 
593
                /* Answer GO call */
3471 svoboda 594
                LOG("answer GO call with EVENT_FINISHED\n");
3018 svoboda 595
                IPC_SET_RETVAL(t->udebug.go_call->data, 0);
3471 svoboda 596
                IPC_SET_ARG1(t->udebug.go_call->data,
597
                    UDEBUG_EVENT_FINISHED);
3026 svoboda 598
 
3018 svoboda 599
                ipc_answer(&ta->answerbox, t->udebug.go_call);
600
                t->udebug.go_call = NULL;
2870 svoboda 601
            } else {
602
                /*
603
                 * Debug_stop is already at initial value.
604
                 * Yet this means the thread needs waking up.
605
                 */
606
 
607
                /*
608
                 * t's lock must not be held when calling
609
                 * waitq_wakeup.
610
                 */
3018 svoboda 611
                waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
2870 svoboda 612
            }
613
        }
3026 svoboda 614
        mutex_unlock(&t->udebug.lock);
2870 svoboda 615
    }
616
 
3014 svoboda 617
    ta->udebug.dt_state = UDEBUG_TS_INACTIVE;
618
    ta->udebug.debugger = NULL;
2870 svoboda 619
 
3026 svoboda 620
    udebug_int_unlock();
621
 
2870 svoboda 622
    return 0;
623
}
624
 
625
 
2801 svoboda 626
/** @}
627
 */