Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/udebug/udebug.c

    r96b02eb9 r9441458  
    3333/**
    3434 * @file
    35  * @brief Udebug hooks and data structure management.
     35 * @brief       Udebug hooks and data structure management.
    3636 *
    3737 * Udebug is an interface that makes userspace debuggers possible.
    3838 */
    39 
     39 
    4040#include <synch/waitq.h>
    4141#include <debug.h>
     
    4545#include <arch.h>
    4646
     47
    4748/** Initialize udebug part of task structure.
    4849 *
    4950 * Called as part of task structure initialization.
    50  * @param ut Pointer to the structure to initialize.
    51  *
     51 * @param ut    Pointer to the structure to initialize.
    5252 */
    5353void udebug_task_init(udebug_task_t *ut)
     
    6363 *
    6464 * Called as part of thread structure initialization.
    65  *
    66  * @param ut Pointer to the structure to initialize.
    67  *
     65 * @param ut    Pointer to the structure to initialize.
    6866 */
    6967void udebug_thread_initialize(udebug_thread_t *ut)
     
    7169        mutex_initialize(&ut->lock, MUTEX_PASSIVE);
    7270        waitq_initialize(&ut->go_wq);
    73         condvar_initialize(&ut->active_cv);
    74        
     71
    7572        ut->go_call = NULL;
    7673        ut->uspace_state = NULL;
     
    7875        ut->stoppable = true;
    7976        ut->active = false;
    80         ut->cur_event = 0;  /* None */
     77        ut->cur_event = 0; /* none */
    8178}
    8279
     
    8784 * is received.
    8885 *
    89  * @param wq The wait queue used by the thread to wait for GO messages.
    90  *
     86 * @param wq    The wait queue used by the thread to wait for GO messages.
    9187 */
    9288static void udebug_wait_for_go(waitq_t *wq)
    9389{
    94         ipl_t ipl = waitq_sleep_prepare(wq);
    95        
    96         wq->missed_wakeups = 0;  /* Enforce blocking. */
    97         int rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
    98        
     90        int rc;
     91        ipl_t ipl;
     92
     93        ipl = waitq_sleep_prepare(wq);
     94
     95        wq->missed_wakeups = 0; /* Enforce blocking. */
     96        rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
     97
    9998        waitq_sleep_finish(wq, rc, ipl);
    10099}
     
    102101/** Start of stoppable section.
    103102 *
    104  * A stoppable section is a section of code where if the thread can
    105  * be stoped. In other words, if a STOP operation is issued, the thread
    106  * is guaranteed not to execute any userspace instructions until the
    107  * thread is resumed.
     103 * A stoppable section is a section of code where if the thread can be stoped. In other words,
     104 * if a STOP operation is issued, the thread is guaranteed not to execute
     105 * any userspace instructions until the thread is resumed.
    108106 *
    109107 * Having stoppable sections is better than having stopping points, since
    110108 * a thread can be stopped even when it is blocked indefinitely in a system
    111109 * call (whereas it would not reach any stopping point).
    112  *
    113110 */
    114111void udebug_stoppable_begin(void)
    115112{
     113        int nsc;
     114        call_t *db_call, *go_call;
     115
    116116        ASSERT(THREAD);
    117117        ASSERT(TASK);
    118        
     118
    119119        mutex_lock(&TASK->udebug.lock);
    120        
    121         int nsc = --TASK->udebug.not_stoppable_count;
    122        
     120
     121        nsc = --TASK->udebug.not_stoppable_count;
     122
    123123        /* Lock order OK, THREAD->udebug.lock is after TASK->udebug.lock */
    124124        mutex_lock(&THREAD->udebug.lock);
    125125        ASSERT(THREAD->udebug.stoppable == false);
    126126        THREAD->udebug.stoppable = true;
    127        
    128         if ((TASK->udebug.dt_state == UDEBUG_TS_BEGINNING) && (nsc == 0)) {
     127
     128        if (TASK->udebug.dt_state == UDEBUG_TS_BEGINNING && nsc == 0) {
    129129                /*
    130130                 * This was the last non-stoppable thread. Reply to
    131131                 * DEBUG_BEGIN call.
    132                  *
    133132                 */
    134                
    135                 call_t *db_call = TASK->udebug.begin_call;
     133
     134                db_call = TASK->udebug.begin_call;
    136135                ASSERT(db_call);
    137                
     136
    138137                TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
    139138                TASK->udebug.begin_call = NULL;
    140                
     139
    141140                IPC_SET_RETVAL(db_call->data, 0);
    142                 ipc_answer(&TASK->answerbox, db_call);
     141                ipc_answer(&TASK->answerbox, db_call);         
     142
    143143        } else if (TASK->udebug.dt_state == UDEBUG_TS_ACTIVE) {
    144144                /*
    145145                 * Active debugging session
    146146                 */
    147                
     147
    148148                if (THREAD->udebug.active == true &&
    149149                    THREAD->udebug.go == false) {
    150150                        /*
    151151                         * Thread was requested to stop - answer go call
    152                          *
    153152                         */
    154                        
     153
    155154                        /* Make sure nobody takes this call away from us */
    156                         call_t *go_call = THREAD->udebug.go_call;
     155                        go_call = THREAD->udebug.go_call;
    157156                        THREAD->udebug.go_call = NULL;
    158157                        ASSERT(go_call);
    159                        
     158
    160159                        IPC_SET_RETVAL(go_call->data, 0);
    161160                        IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP);
    162                        
     161
    163162                        THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
    164                         ipc_answer(&TASK->answerbox, go_call);
     163
     164                        ipc_answer(&TASK->answerbox, go_call);
    165165                }
    166166        }
    167        
     167
    168168        mutex_unlock(&THREAD->udebug.lock);
    169169        mutex_unlock(&TASK->udebug.lock);
     
    173173 *
    174174 * This is the point where the thread will block if it is stopped.
    175  * (As, by definition, a stopped thread must not leave its stoppable
    176  * section).
    177  *
     175 * (As, by definition, a stopped thread must not leave its stoppable section).
    178176 */
    179177void udebug_stoppable_end(void)
     
    182180        mutex_lock(&TASK->udebug.lock);
    183181        mutex_lock(&THREAD->udebug.lock);
    184        
    185         if ((THREAD->udebug.active) && (THREAD->udebug.go == false)) {
     182
     183        if (THREAD->udebug.active && THREAD->udebug.go == false) {
    186184                mutex_unlock(&THREAD->udebug.lock);
    187185                mutex_unlock(&TASK->udebug.lock);
    188                
     186
    189187                udebug_wait_for_go(&THREAD->udebug.go_wq);
    190                
     188
    191189                goto restart;
    192190                /* Must try again - have to lose stoppability atomically. */
     
    195193                ASSERT(THREAD->udebug.stoppable == true);
    196194                THREAD->udebug.stoppable = false;
    197                
     195
    198196                mutex_unlock(&THREAD->udebug.lock);
    199197                mutex_unlock(&TASK->udebug.lock);
     
    204202 *
    205203 * This function is called from clock().
    206  *
    207204 */
    208205void udebug_before_thread_runs(void)
     
    217214 * Must be called before and after servicing a system call. This generates
    218215 * a SYSCALL_B or SYSCALL_E event, depending on the value of @a end_variant.
    219  *
    220  */
    221 void udebug_syscall_event(sysarg_t a1, sysarg_t a2, sysarg_t a3,
    222     sysarg_t a4, sysarg_t a5, sysarg_t a6, sysarg_t id, sysarg_t rc,
     216 */
     217void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
     218    unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc,
    223219    bool end_variant)
    224220{
    225         udebug_event_t etype =
    226             end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B;
    227        
     221        call_t *call;
     222        udebug_event_t etype;
     223
     224        etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B;
     225
    228226        mutex_lock(&TASK->udebug.lock);
    229227        mutex_lock(&THREAD->udebug.lock);
    230        
     228
    231229        /* Must only generate events when in debugging session and is go. */
    232230        if (THREAD->udebug.active != true || THREAD->udebug.go == false ||
     
    236234                return;
    237235        }
    238        
     236
    239237        /* Fill in the GO response. */
    240         call_t *call = THREAD->udebug.go_call;
     238        call = THREAD->udebug.go_call;
    241239        THREAD->udebug.go_call = NULL;
    242        
     240
    243241        IPC_SET_RETVAL(call->data, 0);
    244242        IPC_SET_ARG1(call->data, etype);
    245243        IPC_SET_ARG2(call->data, id);
    246244        IPC_SET_ARG3(call->data, rc);
    247        
     245
    248246        THREAD->udebug.syscall_args[0] = a1;
    249247        THREAD->udebug.syscall_args[1] = a2;
     
    252250        THREAD->udebug.syscall_args[4] = a5;
    253251        THREAD->udebug.syscall_args[5] = a6;
    254        
     252
    255253        /*
    256254         * Make sure udebug.go is false when going to sleep
    257255         * in case we get woken up by DEBUG_END. (At which
    258256         * point it must be back to the initial true value).
    259          *
    260257         */
    261258        THREAD->udebug.go = false;
    262259        THREAD->udebug.cur_event = etype;
    263        
     260
    264261        ipc_answer(&TASK->answerbox, call);
    265        
     262
    266263        mutex_unlock(&THREAD->udebug.lock);
    267264        mutex_unlock(&TASK->udebug.lock);
    268        
     265
    269266        udebug_wait_for_go(&THREAD->udebug.go_wq);
    270267}
     
    282279 * and get a THREAD_B event for them.
    283280 *
    284  * @param thread Structure of the thread being created. Not locked, as the
    285  *               thread is not executing yet.
    286  * @param task   Task to which the thread should be attached.
    287  *
    288  */
    289 void udebug_thread_b_event_attach(struct thread *thread, struct task *task)
    290 {
     281 * @param t     Structure of the thread being created. Not locked, as the
     282 *              thread is not executing yet.
     283 * @param ta    Task to which the thread should be attached.
     284 */
     285void udebug_thread_b_event_attach(struct thread *t, struct task *ta)
     286{
     287        call_t *call;
     288
    291289        mutex_lock(&TASK->udebug.lock);
    292290        mutex_lock(&THREAD->udebug.lock);
    293        
    294         thread_attach(thread, task);
    295        
     291
     292        thread_attach(t, ta);
     293
    296294        LOG("Check state");
    297        
     295
    298296        /* Must only generate events when in debugging session */
    299297        if (THREAD->udebug.active != true) {
    300298                LOG("udebug.active: %s, udebug.go: %s",
    301                     THREAD->udebug.active ? "Yes(+)" : "No",
    302                     THREAD->udebug.go ? "Yes(-)" : "No");
    303                
     299                        THREAD->udebug.active ? "Yes(+)" : "No",
     300                        THREAD->udebug.go ? "Yes(-)" : "No");
    304301                mutex_unlock(&THREAD->udebug.lock);
    305302                mutex_unlock(&TASK->udebug.lock);
    306303                return;
    307304        }
    308        
     305
    309306        LOG("Trigger event");
    310        
    311         call_t *call = THREAD->udebug.go_call;
    312        
     307        call = THREAD->udebug.go_call;
    313308        THREAD->udebug.go_call = NULL;
    314309        IPC_SET_RETVAL(call->data, 0);
    315310        IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_B);
    316         IPC_SET_ARG2(call->data, (sysarg_t) thread);
    317        
     311        IPC_SET_ARG2(call->data, (unative_t)t);
     312
    318313        /*
    319314         * Make sure udebug.go is false when going to sleep
    320315         * in case we get woken up by DEBUG_END. (At which
    321316         * point it must be back to the initial true value).
    322          *
    323317         */
    324318        THREAD->udebug.go = false;
    325319        THREAD->udebug.cur_event = UDEBUG_EVENT_THREAD_B;
    326        
     320
    327321        ipc_answer(&TASK->answerbox, call);
    328        
     322
    329323        mutex_unlock(&THREAD->udebug.lock);
    330324        mutex_unlock(&TASK->udebug.lock);
    331        
     325
    332326        LOG("Wait for Go");
    333327        udebug_wait_for_go(&THREAD->udebug.go_wq);
     
    338332 * Must be called when the current thread is terminating.
    339333 * Generates a THREAD_E event.
    340  *
    341334 */
    342335void udebug_thread_e_event(void)
    343336{
     337        call_t *call;
     338
    344339        mutex_lock(&TASK->udebug.lock);
    345340        mutex_lock(&THREAD->udebug.lock);
    346        
     341
    347342        LOG("Check state");
    348        
     343
    349344        /* Must only generate events when in debugging session. */
    350345        if (THREAD->udebug.active != true) {
    351346                LOG("udebug.active: %s, udebug.go: %s",
    352                     THREAD->udebug.active ? "Yes" : "No",
    353                     THREAD->udebug.go ? "Yes" : "No");
    354                
     347                        THREAD->udebug.active ? "Yes" : "No",
     348                        THREAD->udebug.go ? "Yes" : "No");
    355349                mutex_unlock(&THREAD->udebug.lock);
    356350                mutex_unlock(&TASK->udebug.lock);
    357351                return;
    358352        }
    359        
     353
    360354        LOG("Trigger event");
    361        
    362         call_t *call = THREAD->udebug.go_call;
    363        
     355        call = THREAD->udebug.go_call;
    364356        THREAD->udebug.go_call = NULL;
    365357        IPC_SET_RETVAL(call->data, 0);
    366358        IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_E);
    367        
     359
    368360        /* Prevent any further debug activity in thread. */
    369361        THREAD->udebug.active = false;
    370         THREAD->udebug.cur_event = 0;   /* None */
    371         THREAD->udebug.go = false;      /* Set to initial value */
    372        
     362        THREAD->udebug.cur_event = 0;           /* none */
     363        THREAD->udebug.go = false;      /* set to initial value */
     364
    373365        ipc_answer(&TASK->answerbox, call);
    374        
     366
    375367        mutex_unlock(&THREAD->udebug.lock);
    376368        mutex_unlock(&TASK->udebug.lock);
    377        
    378         /*
     369
     370        /* 
    379371         * This event does not sleep - debugging has finished
    380372         * in this thread.
    381          *
    382373         */
    383374}
    384375
    385 /** Terminate task debugging session.
    386  *
    387  * Gracefully terminate the debugging session for a task. If the debugger
     376/**
     377 * Terminate task debugging session.
     378 *
     379 * Gracefully terminates the debugging session for a task. If the debugger
    388380 * is still waiting for events on some threads, it will receive a
    389381 * FINISHED event for each of them.
    390382 *
    391  * @param task Task structure. task->udebug.lock must be already locked.
    392  *
    393  * @return Zero on success or negative error code.
    394  *
    395  */
    396 int udebug_task_cleanup(struct task *task)
    397 {
    398         ASSERT(mutex_locked(&task->udebug.lock));
    399 
    400         if ((task->udebug.dt_state != UDEBUG_TS_BEGINNING) &&
    401             (task->udebug.dt_state != UDEBUG_TS_ACTIVE)) {
     383 * @param ta    Task structure. ta->udebug.lock must be already locked.
     384 * @return      Zero on success or negative error code.
     385 */
     386int udebug_task_cleanup(struct task *ta)
     387{
     388        thread_t *t;
     389        link_t *cur;
     390        int flags;
     391        ipl_t ipl;
     392
     393        if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING &&
     394            ta->udebug.dt_state != UDEBUG_TS_ACTIVE) {
    402395                return EINVAL;
    403396        }
    404        
    405         LOG("Task %" PRIu64, task->taskid);
    406        
     397
     398        LOG("Task %" PRIu64, ta->taskid);
     399
    407400        /* Finish debugging of all userspace threads */
    408         link_t *cur;
    409         for (cur = task->th_head.next; cur != &task->th_head; cur = cur->next) {
    410                 thread_t *thread = list_get_instance(cur, thread_t, th_link);
    411                
    412                 mutex_lock(&thread->udebug.lock);
    413                 unsigned int flags = thread->flags;
    414                
     401        for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
     402                t = list_get_instance(cur, thread_t, th_link);
     403
     404                mutex_lock(&t->udebug.lock);
     405
     406                ipl = interrupts_disable();
     407                spinlock_lock(&t->lock);
     408
     409                flags = t->flags;
     410
     411                spinlock_unlock(&t->lock);
     412                interrupts_restore(ipl);
     413
    415414                /* Only process userspace threads. */
    416415                if ((flags & THREAD_FLAG_USPACE) != 0) {
    417416                        /* Prevent any further debug activity in thread. */
    418                         thread->udebug.active = false;
    419                         thread->udebug.cur_event = 0;   /* None */
    420                        
     417                        t->udebug.active = false;
     418                        t->udebug.cur_event = 0;        /* none */
     419
    421420                        /* Is the thread still go? */
    422                         if (thread->udebug.go == true) {
     421                        if (t->udebug.go == true) {
    423422                                /*
    424                                  * Yes, so clear go. As active == false,
     423                                * Yes, so clear go. As active == false,
    425424                                 * this doesn't affect anything.
    426                                  (
    427425                                 */
    428                                 thread->udebug.go = false;
    429                                
     426                                t->udebug.go = false;   
     427
    430428                                /* Answer GO call */
    431429                                LOG("Answer GO call with EVENT_FINISHED.");
    432                                
    433                                 IPC_SET_RETVAL(thread->udebug.go_call->data, 0);
    434                                 IPC_SET_ARG1(thread->udebug.go_call->data,
     430                                IPC_SET_RETVAL(t->udebug.go_call->data, 0);
     431                                IPC_SET_ARG1(t->udebug.go_call->data,
    435432                                    UDEBUG_EVENT_FINISHED);
    436                                
    437                                 ipc_answer(&task->answerbox, thread->udebug.go_call);
    438                                 thread->udebug.go_call = NULL;
     433
     434                                ipc_answer(&ta->answerbox, t->udebug.go_call);
     435                                t->udebug.go_call = NULL;
    439436                        } else {
    440437                                /*
    441438                                 * Debug_stop is already at initial value.
    442439                                 * Yet this means the thread needs waking up.
    443                                  *
    444440                                 */
    445                                
     441
    446442                                /*
    447                                  * thread's lock must not be held when calling
     443                                 * t's lock must not be held when calling
    448444                                 * waitq_wakeup.
    449                                  *
    450445                                 */
    451                                 waitq_wakeup(&thread->udebug.go_wq, WAKEUP_FIRST);
     446                                waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
    452447                        }
    453                        
    454                         mutex_unlock(&thread->udebug.lock);
    455                         condvar_broadcast(&thread->udebug.active_cv);
    456                 } else
    457                         mutex_unlock(&thread->udebug.lock);
    458         }
    459        
    460         task->udebug.dt_state = UDEBUG_TS_INACTIVE;
    461         task->udebug.debugger = NULL;
    462        
     448                }
     449                mutex_unlock(&t->udebug.lock);
     450        }
     451
     452        ta->udebug.dt_state = UDEBUG_TS_INACTIVE;
     453        ta->udebug.debugger = NULL;
     454
    463455        return 0;
    464456}
    465457
    466 /** Wait for debugger to handle a fault in this thread.
    467  *
    468  * When a thread faults and someone is subscribed to the FAULT kernel event,
    469  * this function is called to wait for a debugging session to give userspace
    470  * a chance to examine the faulting thead/task. When the debugging session
    471  * is over, this function returns (so that thread/task cleanup can continue).
    472  *
    473  */
    474 void udebug_thread_fault(void)
    475 {
    476         udebug_stoppable_begin();
    477        
    478         /* Wait until a debugger attends to us. */
    479         mutex_lock(&THREAD->udebug.lock);
    480         while (!THREAD->udebug.active)
    481                 condvar_wait(&THREAD->udebug.active_cv, &THREAD->udebug.lock);
    482         mutex_unlock(&THREAD->udebug.lock);
    483        
    484         /* Make sure the debugging session is over before proceeding. */
    485         mutex_lock(&THREAD->udebug.lock);
    486         while (THREAD->udebug.active)
    487                 condvar_wait(&THREAD->udebug.active_cv, &THREAD->udebug.lock);
    488         mutex_unlock(&THREAD->udebug.lock);
    489        
    490         udebug_stoppable_end();
    491 }
    492458
    493459/** @}
Note: See TracChangeset for help on using the changeset viewer.