Ignore:
File:
1 edited

Legend:

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

    r1d432f9 r0d21b53  
    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)
     
    7270        waitq_initialize(&ut->go_wq);
    7371        condvar_initialize(&ut->active_cv);
    74        
     72
    7573        ut->go_call = NULL;
    7674        ut->uspace_state = NULL;
     
    7876        ut->stoppable = true;
    7977        ut->active = false;
    80         ut->cur_event = 0;  /* None */
     78        ut->cur_event = 0; /* none */
    8179}
    8280
     
    8785 * is received.
    8886 *
    89  * @param wq The wait queue used by the thread to wait for GO messages.
    90  *
     87 * @param wq    The wait queue used by the thread to wait for GO messages.
    9188 */
    9289static void udebug_wait_for_go(waitq_t *wq)
    9390{
    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        
     91        int rc;
     92        ipl_t ipl;
     93
     94        ipl = waitq_sleep_prepare(wq);
     95
     96        wq->missed_wakeups = 0; /* Enforce blocking. */
     97        rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
     98
    9999        waitq_sleep_finish(wq, rc, ipl);
    100100}
     
    102102/** Start of stoppable section.
    103103 *
    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.
     104 * A stoppable section is a section of code where if the thread can be stoped. In other words,
     105 * if a STOP operation is issued, the thread is guaranteed not to execute
     106 * any userspace instructions until the thread is resumed.
    108107 *
    109108 * Having stoppable sections is better than having stopping points, since
    110109 * a thread can be stopped even when it is blocked indefinitely in a system
    111110 * call (whereas it would not reach any stopping point).
    112  *
    113111 */
    114112void udebug_stoppable_begin(void)
    115113{
     114        int nsc;
     115        call_t *db_call, *go_call;
     116
    116117        ASSERT(THREAD);
    117118        ASSERT(TASK);
    118        
     119
    119120        mutex_lock(&TASK->udebug.lock);
    120        
    121         int nsc = --TASK->udebug.not_stoppable_count;
    122        
     121
     122        nsc = --TASK->udebug.not_stoppable_count;
     123
    123124        /* Lock order OK, THREAD->udebug.lock is after TASK->udebug.lock */
    124125        mutex_lock(&THREAD->udebug.lock);
    125126        ASSERT(THREAD->udebug.stoppable == false);
    126127        THREAD->udebug.stoppable = true;
    127        
    128         if ((TASK->udebug.dt_state == UDEBUG_TS_BEGINNING) && (nsc == 0)) {
     128
     129        if (TASK->udebug.dt_state == UDEBUG_TS_BEGINNING && nsc == 0) {
    129130                /*
    130131                 * This was the last non-stoppable thread. Reply to
    131132                 * DEBUG_BEGIN call.
    132                  *
    133133                 */
    134                
    135                 call_t *db_call = TASK->udebug.begin_call;
     134
     135                db_call = TASK->udebug.begin_call;
    136136                ASSERT(db_call);
    137                
     137
    138138                TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
    139139                TASK->udebug.begin_call = NULL;
    140                
     140
    141141                IPC_SET_RETVAL(db_call->data, 0);
    142                 ipc_answer(&TASK->answerbox, db_call);
     142                ipc_answer(&TASK->answerbox, db_call);         
     143
    143144        } else if (TASK->udebug.dt_state == UDEBUG_TS_ACTIVE) {
    144145                /*
    145146                 * Active debugging session
    146147                 */
    147                
     148
    148149                if (THREAD->udebug.active == true &&
    149150                    THREAD->udebug.go == false) {
    150151                        /*
    151152                         * Thread was requested to stop - answer go call
    152                          *
    153153                         */
    154                        
     154
    155155                        /* Make sure nobody takes this call away from us */
    156                         call_t *go_call = THREAD->udebug.go_call;
     156                        go_call = THREAD->udebug.go_call;
    157157                        THREAD->udebug.go_call = NULL;
    158158                        ASSERT(go_call);
    159                        
     159
    160160                        IPC_SET_RETVAL(go_call->data, 0);
    161161                        IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP);
    162                        
     162
    163163                        THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
    164                         ipc_answer(&TASK->answerbox, go_call);
     164
     165                        ipc_answer(&TASK->answerbox, go_call);
    165166                }
    166167        }
    167        
     168
    168169        mutex_unlock(&THREAD->udebug.lock);
    169170        mutex_unlock(&TASK->udebug.lock);
     
    173174 *
    174175 * 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  *
     176 * (As, by definition, a stopped thread must not leave its stoppable section).
    178177 */
    179178void udebug_stoppable_end(void)
     
    182181        mutex_lock(&TASK->udebug.lock);
    183182        mutex_lock(&THREAD->udebug.lock);
    184        
    185         if ((THREAD->udebug.active) && (THREAD->udebug.go == false)) {
     183
     184        if (THREAD->udebug.active && THREAD->udebug.go == false) {
    186185                mutex_unlock(&THREAD->udebug.lock);
    187186                mutex_unlock(&TASK->udebug.lock);
    188                
     187
    189188                udebug_wait_for_go(&THREAD->udebug.go_wq);
    190                
     189
    191190                goto restart;
    192191                /* Must try again - have to lose stoppability atomically. */
     
    195194                ASSERT(THREAD->udebug.stoppable == true);
    196195                THREAD->udebug.stoppable = false;
    197                
     196
    198197                mutex_unlock(&THREAD->udebug.lock);
    199198                mutex_unlock(&TASK->udebug.lock);
     
    204203 *
    205204 * This function is called from clock().
    206  *
    207205 */
    208206void udebug_before_thread_runs(void)
     
    217215 * Must be called before and after servicing a system call. This generates
    218216 * a SYSCALL_B or SYSCALL_E event, depending on the value of @a end_variant.
    219  *
    220217 */
    221218void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
     
    223220    bool end_variant)
    224221{
    225         udebug_event_t etype =
    226             end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B;
    227        
     222        call_t *call;
     223        udebug_event_t etype;
     224
     225        etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B;
     226
    228227        mutex_lock(&TASK->udebug.lock);
    229228        mutex_lock(&THREAD->udebug.lock);
    230        
     229
    231230        /* Must only generate events when in debugging session and is go. */
    232231        if (THREAD->udebug.active != true || THREAD->udebug.go == false ||
     
    236235                return;
    237236        }
    238        
     237
    239238        /* Fill in the GO response. */
    240         call_t *call = THREAD->udebug.go_call;
     239        call = THREAD->udebug.go_call;
    241240        THREAD->udebug.go_call = NULL;
    242        
     241
    243242        IPC_SET_RETVAL(call->data, 0);
    244243        IPC_SET_ARG1(call->data, etype);
    245244        IPC_SET_ARG2(call->data, id);
    246245        IPC_SET_ARG3(call->data, rc);
    247        
     246
    248247        THREAD->udebug.syscall_args[0] = a1;
    249248        THREAD->udebug.syscall_args[1] = a2;
     
    252251        THREAD->udebug.syscall_args[4] = a5;
    253252        THREAD->udebug.syscall_args[5] = a6;
    254        
     253
    255254        /*
    256255         * Make sure udebug.go is false when going to sleep
    257256         * in case we get woken up by DEBUG_END. (At which
    258257         * point it must be back to the initial true value).
    259          *
    260258         */
    261259        THREAD->udebug.go = false;
    262260        THREAD->udebug.cur_event = etype;
    263        
     261
    264262        ipc_answer(&TASK->answerbox, call);
    265        
     263
    266264        mutex_unlock(&THREAD->udebug.lock);
    267265        mutex_unlock(&TASK->udebug.lock);
    268        
     266
    269267        udebug_wait_for_go(&THREAD->udebug.go_wq);
    270268}
     
    282280 * and get a THREAD_B event for them.
    283281 *
    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 {
     282 * @param t     Structure of the thread being created. Not locked, as the
     283 *              thread is not executing yet.
     284 * @param ta    Task to which the thread should be attached.
     285 */
     286void udebug_thread_b_event_attach(struct thread *t, struct task *ta)
     287{
     288        call_t *call;
     289
    291290        mutex_lock(&TASK->udebug.lock);
    292291        mutex_lock(&THREAD->udebug.lock);
    293        
    294         thread_attach(thread, task);
    295        
     292
     293        thread_attach(t, ta);
     294
    296295        LOG("Check state");
    297        
     296
    298297        /* Must only generate events when in debugging session */
    299298        if (THREAD->udebug.active != true) {
    300299                LOG("udebug.active: %s, udebug.go: %s",
    301                     THREAD->udebug.active ? "Yes(+)" : "No",
    302                     THREAD->udebug.go ? "Yes(-)" : "No");
    303                
     300                        THREAD->udebug.active ? "Yes(+)" : "No",
     301                        THREAD->udebug.go ? "Yes(-)" : "No");
    304302                mutex_unlock(&THREAD->udebug.lock);
    305303                mutex_unlock(&TASK->udebug.lock);
    306304                return;
    307305        }
    308        
     306
    309307        LOG("Trigger event");
    310        
    311         call_t *call = THREAD->udebug.go_call;
    312        
     308        call = THREAD->udebug.go_call;
    313309        THREAD->udebug.go_call = NULL;
    314310        IPC_SET_RETVAL(call->data, 0);
    315311        IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_B);
    316         IPC_SET_ARG2(call->data, (unative_t) thread);
    317        
     312        IPC_SET_ARG2(call->data, (unative_t)t);
     313
    318314        /*
    319315         * Make sure udebug.go is false when going to sleep
    320316         * in case we get woken up by DEBUG_END. (At which
    321317         * point it must be back to the initial true value).
    322          *
    323318         */
    324319        THREAD->udebug.go = false;
    325320        THREAD->udebug.cur_event = UDEBUG_EVENT_THREAD_B;
    326        
     321
    327322        ipc_answer(&TASK->answerbox, call);
    328        
     323
    329324        mutex_unlock(&THREAD->udebug.lock);
    330325        mutex_unlock(&TASK->udebug.lock);
    331        
     326
    332327        LOG("Wait for Go");
    333328        udebug_wait_for_go(&THREAD->udebug.go_wq);
     
    338333 * Must be called when the current thread is terminating.
    339334 * Generates a THREAD_E event.
    340  *
    341335 */
    342336void udebug_thread_e_event(void)
    343337{
     338        call_t *call;
     339
    344340        mutex_lock(&TASK->udebug.lock);
    345341        mutex_lock(&THREAD->udebug.lock);
    346        
     342
    347343        LOG("Check state");
    348        
     344
    349345        /* Must only generate events when in debugging session. */
    350346        if (THREAD->udebug.active != true) {
    351347                LOG("udebug.active: %s, udebug.go: %s",
    352                     THREAD->udebug.active ? "Yes" : "No",
    353                     THREAD->udebug.go ? "Yes" : "No");
    354                
     348                        THREAD->udebug.active ? "Yes" : "No",
     349                        THREAD->udebug.go ? "Yes" : "No");
    355350                mutex_unlock(&THREAD->udebug.lock);
    356351                mutex_unlock(&TASK->udebug.lock);
    357352                return;
    358353        }
    359        
     354
    360355        LOG("Trigger event");
    361        
    362         call_t *call = THREAD->udebug.go_call;
    363        
     356        call = THREAD->udebug.go_call;
    364357        THREAD->udebug.go_call = NULL;
    365358        IPC_SET_RETVAL(call->data, 0);
    366359        IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_E);
    367        
     360
    368361        /* Prevent any further debug activity in thread. */
    369362        THREAD->udebug.active = false;
    370         THREAD->udebug.cur_event = 0;   /* None */
    371         THREAD->udebug.go = false;      /* Set to initial value */
    372        
     363        THREAD->udebug.cur_event = 0;           /* none */
     364        THREAD->udebug.go = false;      /* set to initial value */
     365
    373366        ipc_answer(&TASK->answerbox, call);
    374        
     367
    375368        mutex_unlock(&THREAD->udebug.lock);
    376369        mutex_unlock(&TASK->udebug.lock);
    377        
    378         /*
     370
     371        /* 
    379372         * This event does not sleep - debugging has finished
    380373         * in this thread.
    381          *
    382374         */
    383375}
    384376
    385 /** Terminate task debugging session.
    386  *
    387  * Gracefully terminate the debugging session for a task. If the debugger
     377/**
     378 * Terminate task debugging session.
     379 *
     380 * Gracefully terminates the debugging session for a task. If the debugger
    388381 * is still waiting for events on some threads, it will receive a
    389382 * FINISHED event for each of them.
    390383 *
    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)) {
     384 * @param ta    Task structure. ta->udebug.lock must be already locked.
     385 * @return      Zero on success or negative error code.
     386 */
     387int udebug_task_cleanup(struct task *ta)
     388{
     389        thread_t *t;
     390        link_t *cur;
     391        int flags;
     392        ipl_t ipl;
     393
     394        if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING &&
     395            ta->udebug.dt_state != UDEBUG_TS_ACTIVE) {
    402396                return EINVAL;
    403397        }
    404        
    405         LOG("Task %" PRIu64, task->taskid);
    406        
     398
     399        LOG("Task %" PRIu64, ta->taskid);
     400
    407401        /* 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                
     402        for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
     403                t = list_get_instance(cur, thread_t, th_link);
     404
     405                mutex_lock(&t->udebug.lock);
     406
     407                ipl = interrupts_disable();
     408                spinlock_lock(&t->lock);
     409
     410                flags = t->flags;
     411
     412                spinlock_unlock(&t->lock);
     413                interrupts_restore(ipl);
     414
    415415                /* Only process userspace threads. */
    416416                if ((flags & THREAD_FLAG_USPACE) != 0) {
    417417                        /* Prevent any further debug activity in thread. */
    418                         thread->udebug.active = false;
    419                         thread->udebug.cur_event = 0;   /* None */
    420                        
     418                        t->udebug.active = false;
     419                        t->udebug.cur_event = 0;        /* none */
     420
    421421                        /* Is the thread still go? */
    422                         if (thread->udebug.go == true) {
     422                        if (t->udebug.go == true) {
    423423                                /*
    424                                  * Yes, so clear go. As active == false,
     424                                * Yes, so clear go. As active == false,
    425425                                 * this doesn't affect anything.
    426                                  (
    427426                                 */
    428                                 thread->udebug.go = false;
    429                                
     427                                t->udebug.go = false;   
     428
    430429                                /* Answer GO call */
    431430                                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,
     431                                IPC_SET_RETVAL(t->udebug.go_call->data, 0);
     432                                IPC_SET_ARG1(t->udebug.go_call->data,
    435433                                    UDEBUG_EVENT_FINISHED);
    436                                
    437                                 ipc_answer(&task->answerbox, thread->udebug.go_call);
    438                                 thread->udebug.go_call = NULL;
     434
     435                                ipc_answer(&ta->answerbox, t->udebug.go_call);
     436                                t->udebug.go_call = NULL;
    439437                        } else {
    440438                                /*
    441439                                 * Debug_stop is already at initial value.
    442440                                 * Yet this means the thread needs waking up.
    443                                  *
    444441                                 */
    445                                
     442
    446443                                /*
    447                                  * thread's lock must not be held when calling
     444                                 * t's lock must not be held when calling
    448445                                 * waitq_wakeup.
    449                                  *
    450446                                 */
    451                                 waitq_wakeup(&thread->udebug.go_wq, WAKEUP_FIRST);
     447                                waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
    452448                        }
    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        
     449                        mutex_unlock(&t->udebug.lock);
     450                        condvar_broadcast(&t->udebug.active_cv);
     451                } else {
     452                        mutex_unlock(&t->udebug.lock);
     453                }
     454        }
     455
     456        ta->udebug.dt_state = UDEBUG_TS_INACTIVE;
     457        ta->udebug.debugger = NULL;
     458
    463459        return 0;
    464460}
     
    470466 * a chance to examine the faulting thead/task. When the debugging session
    471467 * is over, this function returns (so that thread/task cleanup can continue).
    472  *
    473468 */
    474469void udebug_thread_fault(void)
    475470{
    476471        udebug_stoppable_begin();
    477        
     472
    478473        /* Wait until a debugger attends to us. */
    479474        mutex_lock(&THREAD->udebug.lock);
     
    481476                condvar_wait(&THREAD->udebug.active_cv, &THREAD->udebug.lock);
    482477        mutex_unlock(&THREAD->udebug.lock);
    483        
     478
    484479        /* Make sure the debugging session is over before proceeding. */
    485480        mutex_lock(&THREAD->udebug.lock);
     
    487482                condvar_wait(&THREAD->udebug.active_cv, &THREAD->udebug.lock);
    488483        mutex_unlock(&THREAD->udebug.lock);
    489        
     484
    490485        udebug_stoppable_end();
    491486}
Note: See TracChangeset for help on using the changeset viewer.