Ignore:
File:
1 edited

Legend:

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

    rae5aa90 r96b02eb9  
    3333/**
    3434 * @file
    35  * @brief       Udebug operations.
     35 * @brief Udebug operations.
    3636 *
    3737 * Udebug operations on tasks and threads are implemented here. The
     
    3939 * when servicing udebug IPC messages.
    4040 */
    41  
     41
    4242#include <debug.h>
    4343#include <proc/task.h>
     
    4646#include <errno.h>
    4747#include <print.h>
     48#include <str.h>
    4849#include <syscall/copy.h>
    4950#include <ipc/ipc.h>
    5051#include <udebug/udebug.h>
    5152#include <udebug/udebug_ops.h>
    52 
    53 /**
    54  * Prepare a thread for a debugging operation.
     53#include <memstr.h>
     54
     55/** Prepare a thread for a debugging operation.
    5556 *
    5657 * Simply put, return thread t with t->udebug.lock held,
     
    7172 * the t->lock spinlock to the t->udebug.lock mutex.
    7273 *
    73  * @param t             Pointer, need not at all be valid.
    74  * @param being_go      Required thread state.
     74 * @param thread   Pointer, need not at all be valid.
     75 * @param being_go Required thread state.
    7576 *
    7677 * Returns EOK if all went well, or an error code otherwise.
    77  */
    78 static int _thread_op_begin(thread_t *t, bool being_go)
    79 {
    80         task_id_t taskid;
    81         ipl_t ipl;
    82 
    83         taskid = TASK->taskid;
    84 
    85         mutex_lock(&TASK->udebug.lock);
    86 
     78 *
     79 */
     80static int _thread_op_begin(thread_t *thread, bool being_go)
     81{
     82        mutex_lock(&TASK->udebug.lock);
     83       
    8784        /* thread_exists() must be called with threads_lock held */
    88         ipl = interrupts_disable();
    89         spinlock_lock(&threads_lock);
    90 
    91         if (!thread_exists(t)) {
    92                 spinlock_unlock(&threads_lock);
    93                 interrupts_restore(ipl);
     85        irq_spinlock_lock(&threads_lock, true);
     86       
     87        if (!thread_exists(thread)) {
     88                irq_spinlock_unlock(&threads_lock, true);
    9489                mutex_unlock(&TASK->udebug.lock);
    9590                return ENOENT;
    9691        }
    97 
    98         /* t->lock is enough to ensure the thread's existence */
    99         spinlock_lock(&t->lock);
    100         spinlock_unlock(&threads_lock);
    101 
    102         /* Verify that 't' is a userspace thread. */
    103         if ((t->flags & THREAD_FLAG_USPACE) == 0) {
     92       
     93        /* thread->lock is enough to ensure the thread's existence */
     94        irq_spinlock_exchange(&threads_lock, &thread->lock);
     95       
     96        /* Verify that 'thread' is a userspace thread. */
     97        if ((thread->flags & THREAD_FLAG_USPACE) == 0) {
    10498                /* It's not, deny its existence */
    105                 spinlock_unlock(&t->lock);
    106                 interrupts_restore(ipl);
     99                irq_spinlock_unlock(&thread->lock, true);
    107100                mutex_unlock(&TASK->udebug.lock);
    108101                return ENOENT;
    109102        }
    110 
     103       
    111104        /* Verify debugging state. */
    112         if (t->udebug.active != true) {
     105        if (thread->udebug.active != true) {
    113106                /* Not in debugging session or undesired GO state */
    114                 spinlock_unlock(&t->lock);
    115                 interrupts_restore(ipl);
     107                irq_spinlock_unlock(&thread->lock, true);
    116108                mutex_unlock(&TASK->udebug.lock);
    117109                return ENOENT;
    118110        }
    119 
     111       
    120112        /*
    121113         * Since the thread has active == true, TASK->udebug.lock
    122114         * is enough to ensure its existence and that active remains
    123115         * true.
     116         *
    124117         */
    125         spinlock_unlock(&t->lock);
    126         interrupts_restore(ipl);
    127 
     118        irq_spinlock_unlock(&thread->lock, true);
     119       
    128120        /* Only mutex TASK->udebug.lock left. */
    129121       
    130122        /* Now verify that the thread belongs to the current task. */
    131         if (t->task != TASK) {
     123        if (thread->task != TASK) {
    132124                /* No such thread belonging this task*/
    133125                mutex_unlock(&TASK->udebug.lock);
    134126                return ENOENT;
    135127        }
    136 
     128       
    137129        /*
    138130         * Now we need to grab the thread's debug lock for synchronization
    139131         * of the threads stoppability/stop state.
     132         *
    140133         */
    141         mutex_lock(&t->udebug.lock);
    142 
     134        mutex_lock(&thread->udebug.lock);
     135       
    143136        /* The big task mutex is no longer needed. */
    144137        mutex_unlock(&TASK->udebug.lock);
    145 
    146         if (t->udebug.go != being_go) {
     138       
     139        if (thread->udebug.go != being_go) {
    147140                /* Not in debugging session or undesired GO state. */
    148                 mutex_unlock(&t->udebug.lock);
     141                mutex_unlock(&thread->udebug.lock);
    149142                return EINVAL;
    150143        }
    151 
    152         /* Only t->udebug.lock left. */
    153 
    154         return EOK;     /* All went well. */
     144       
     145        /* Only thread->udebug.lock left. */
     146       
     147        return EOK;  /* All went well. */
    155148}
    156149
    157150/** End debugging operation on a thread. */
    158 static void _thread_op_end(thread_t *t)
    159 {
    160         mutex_unlock(&t->udebug.lock);
     151static void _thread_op_end(thread_t *thread)
     152{
     153        mutex_unlock(&thread->udebug.lock);
    161154}
    162155
     
    172165 * all the threads become stoppable (i.e. they can be considered stopped).
    173166 *
    174  * @param call  The BEGIN call we are servicing.
    175  * @return      0 (OK, but not done yet), 1 (done) or negative error code.
     167 * @param call The BEGIN call we are servicing.
     168 *
     169 * @return 0 (OK, but not done yet), 1 (done) or negative error code.
     170 *
    176171 */
    177172int udebug_begin(call_t *call)
    178173{
    179         int reply;
    180 
    181         thread_t *t;
    182         link_t *cur;
    183 
    184         LOG("Debugging task %llu", TASK->taskid);
    185         mutex_lock(&TASK->udebug.lock);
    186 
     174        LOG("Debugging task %" PRIu64, TASK->taskid);
     175       
     176        mutex_lock(&TASK->udebug.lock);
     177       
    187178        if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
    188179                mutex_unlock(&TASK->udebug.lock);
    189180                return EBUSY;
    190181        }
    191 
     182       
    192183        TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
    193184        TASK->udebug.begin_call = call;
    194185        TASK->udebug.debugger = call->sender;
    195 
     186       
     187        int reply;
     188       
    196189        if (TASK->udebug.not_stoppable_count == 0) {
    197190                TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
    198191                TASK->udebug.begin_call = NULL;
    199                 reply = 1; /* immediate reply */
    200         } else {
    201                 reply = 0; /* no reply */
    202         }
     192                reply = 1;  /* immediate reply */
     193        } else
     194                reply = 0;  /* no reply */
    203195       
    204196        /* Set udebug.active on all of the task's userspace threads. */
    205 
     197       
     198        link_t *cur;
    206199        for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
    207                 t = list_get_instance(cur, thread_t, th_link);
    208 
    209                 mutex_lock(&t->udebug.lock);
    210                 if ((t->flags & THREAD_FLAG_USPACE) != 0)
    211                         t->udebug.active = true;
    212                 mutex_unlock(&t->udebug.lock);
    213         }
    214 
     200                thread_t *thread = list_get_instance(cur, thread_t, th_link);
     201               
     202                mutex_lock(&thread->udebug.lock);
     203                if ((thread->flags & THREAD_FLAG_USPACE) != 0) {
     204                        thread->udebug.active = true;
     205                        mutex_unlock(&thread->udebug.lock);
     206                        condvar_broadcast(&thread->udebug.active_cv);
     207                } else
     208                        mutex_unlock(&thread->udebug.lock);
     209        }
     210       
    215211        mutex_unlock(&TASK->udebug.lock);
    216212        return reply;
     
    220216 *
    221217 * Closes the debugging session for the current task.
     218 *
    222219 * @return Zero on success or negative error code.
     220 *
    223221 */
    224222int udebug_end(void)
    225223{
    226         int rc;
    227 
    228224        LOG("Task %" PRIu64, TASK->taskid);
    229 
    230         mutex_lock(&TASK->udebug.lock);
    231         rc = udebug_task_cleanup(TASK);
    232         mutex_unlock(&TASK->udebug.lock);
    233 
     225       
     226        mutex_lock(&TASK->udebug.lock);
     227        int rc = udebug_task_cleanup(TASK);
     228        mutex_unlock(&TASK->udebug.lock);
     229       
    234230        return rc;
    235231}
     
    239235 * Sets the event mask that determines which events are enabled.
    240236 *
    241  * @param mask  Or combination of events that should be enabled.
    242  * @return      Zero on success or negative error code.
     237 * @param mask Or combination of events that should be enabled.
     238 *
     239 * @return Zero on success or negative error code.
     240 *
    243241 */
    244242int udebug_set_evmask(udebug_evmask_t mask)
    245243{
    246244        LOG("mask = 0x%x", mask);
    247 
    248         mutex_lock(&TASK->udebug.lock);
    249 
     245       
     246        mutex_lock(&TASK->udebug.lock);
     247       
    250248        if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
    251249                mutex_unlock(&TASK->udebug.lock);
    252250                return EINVAL;
    253251        }
    254 
     252       
    255253        TASK->udebug.evmask = mask;
    256254        mutex_unlock(&TASK->udebug.lock);
    257 
     255       
    258256        return 0;
    259257}
     
    265263 * a debugging event or STOP occurs, at which point the thread loses GO.
    266264 *
    267  * @param t     The thread to operate on (unlocked and need not be valid).
    268  * @param call  The GO call that we are servicing.
    269  */
    270 int udebug_go(thread_t *t, call_t *call)
    271 {
    272         int rc;
    273 
    274         /* On success, this will lock t->udebug.lock. */
    275         rc = _thread_op_begin(t, false);
    276         if (rc != EOK) {
     265 * @param thread The thread to operate on (unlocked and need not be valid).
     266 * @param call   The GO call that we are servicing.
     267 *
     268 */
     269int udebug_go(thread_t *thread, call_t *call)
     270{
     271        /* On success, this will lock thread->udebug.lock. */
     272        int rc = _thread_op_begin(thread, false);
     273        if (rc != EOK)
    277274                return rc;
    278         }
    279 
    280         t->udebug.go_call = call;
    281         t->udebug.go = true;
    282         t->udebug.cur_event = 0;        /* none */
    283 
     275       
     276        thread->udebug.go_call = call;
     277        thread->udebug.go = true;
     278        thread->udebug.cur_event = 0;  /* none */
     279       
    284280        /*
    285          * Neither t's lock nor threads_lock may be held during wakeup.
     281         * Neither thread's lock nor threads_lock may be held during wakeup.
     282         *
    286283         */
    287         waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
    288 
    289         _thread_op_end(t);
    290 
     284        waitq_wakeup(&thread->udebug.go_wq, WAKEUP_FIRST);
     285       
     286        _thread_op_end(thread);
     287       
    291288        return 0;
    292289}
     
    297294 * can be considered stopped).
    298295 *
    299  * @param t     The thread to operate on (unlocked and need not be valid).
    300  * @param call  The GO call that we are servicing.
    301  */
    302 int udebug_stop(thread_t *t, call_t *call)
    303 {
    304         int rc;
    305 
     296 * @param thread The thread to operate on (unlocked and need not be valid).
     297 * @param call   The GO call that we are servicing.
     298 *
     299 */
     300int udebug_stop(thread_t *thread, call_t *call)
     301{
    306302        LOG("udebug_stop()");
    307 
     303       
    308304        /*
    309          * On success, this will lock t->udebug.lock. Note that this makes sure
    310          * the thread is not stopped.
     305         * On success, this will lock thread->udebug.lock. Note that this
     306         * makes sure the thread is not stopped.
     307         *
    311308         */
    312         rc = _thread_op_begin(t, true);
    313         if (rc != EOK) {
     309        int rc = _thread_op_begin(thread, true);
     310        if (rc != EOK)
    314311                return rc;
    315         }
    316 
     312       
    317313        /* Take GO away from the thread. */
    318         t->udebug.go = false;
    319 
    320         if (t->udebug.stoppable != true) {
     314        thread->udebug.go = false;
     315       
     316        if (thread->udebug.stoppable != true) {
    321317                /* Answer will be sent when the thread becomes stoppable. */
    322                 _thread_op_end(t);
     318                _thread_op_end(thread);
    323319                return 0;
    324320        }
    325 
     321       
    326322        /*
    327323         * Answer GO call.
     324         *
    328325         */
    329 
     326       
    330327        /* Make sure nobody takes this call away from us. */
    331         call = t->udebug.go_call;
    332         t->udebug.go_call = NULL;
    333 
     328        call = thread->udebug.go_call;
     329        thread->udebug.go_call = NULL;
     330       
    334331        IPC_SET_RETVAL(call->data, 0);
    335332        IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
    336 
     333       
    337334        THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
    338 
    339         _thread_op_end(t);
    340 
     335       
     336        _thread_op_end(thread);
     337       
    341338        mutex_lock(&TASK->udebug.lock);
    342339        ipc_answer(&TASK->answerbox, call);
    343340        mutex_unlock(&TASK->udebug.lock);
    344 
     341       
    345342        return 0;
    346343}
     
    354351 *
    355352 * If the sequence is longer than @a buf_size bytes, only as much hashes
    356  * as can fit are copied. The number of thread hashes copied is stored
    357  * in @a n.
     353 * as can fit are copied. The number of bytes copied is stored in @a stored.
     354 * The total number of thread bytes that could have been saved had there been
     355 * enough space is stored in @a needed.
    358356 *
    359357 * The rationale for having @a buf_size is that this function is only
     
    361359 * a maximum size for the userspace buffer.
    362360 *
    363  * @param buffer        The buffer for storing thread hashes.
    364  * @param buf_size      Buffer size in bytes.
    365  * @param n             The actual number of hashes copied will be stored here.
    366  */
    367 int udebug_thread_read(void **buffer, size_t buf_size, size_t *n)
    368 {
    369         thread_t *t;
    370         link_t *cur;
    371         unative_t tid;
    372         unsigned copied_ids;
    373         ipl_t ipl;
    374         unative_t *id_buffer;
    375         int flags;
    376         size_t max_ids;
    377 
     361 * @param buffer   The buffer for storing thread hashes.
     362 * @param buf_size Buffer size in bytes.
     363 * @param stored   The actual number of bytes copied will be stored here.
     364 * @param needed   Total number of hashes that could have been saved.
     365 *
     366 */
     367int udebug_thread_read(void **buffer, size_t buf_size, size_t *stored,
     368    size_t *needed)
     369{
    378370        LOG("udebug_thread_read()");
    379 
     371       
    380372        /* Allocate a buffer to hold thread IDs */
    381         id_buffer = malloc(buf_size, 0);
    382 
    383         mutex_lock(&TASK->udebug.lock);
    384 
     373        sysarg_t *id_buffer = malloc(buf_size + 1, 0);
     374       
     375        mutex_lock(&TASK->udebug.lock);
     376       
    385377        /* Verify task state */
    386378        if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
     
    388380                return EINVAL;
    389381        }
    390 
    391         ipl = interrupts_disable();
    392         spinlock_lock(&TASK->lock);
     382       
     383        irq_spinlock_lock(&TASK->lock, true);
     384       
    393385        /* Copy down the thread IDs */
    394 
    395         max_ids = buf_size / sizeof(unative_t);
    396         copied_ids = 0;
    397 
     386       
     387        size_t max_ids = buf_size / sizeof(sysarg_t);
     388        size_t copied_ids = 0;
     389        size_t extra_ids = 0;
     390       
    398391        /* FIXME: make sure the thread isn't past debug shutdown... */
     392        link_t *cur;
    399393        for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
    400                 /* Do not write past end of buffer */
    401                 if (copied_ids >= max_ids) break;
    402 
    403                 t = list_get_instance(cur, thread_t, th_link);
    404 
    405                 spinlock_lock(&t->lock);
    406                 flags = t->flags;
    407                 spinlock_unlock(&t->lock);
    408 
     394                thread_t *thread = list_get_instance(cur, thread_t, th_link);
     395               
     396                irq_spinlock_lock(&thread->lock, false);
     397                int flags = thread->flags;
     398                irq_spinlock_unlock(&thread->lock, false);
     399               
    409400                /* Not interested in kernel threads. */
    410                 if ((flags & THREAD_FLAG_USPACE) != 0) {
     401                if ((flags & THREAD_FLAG_USPACE) == 0)
     402                        continue;
     403               
     404                if (copied_ids < max_ids) {
    411405                        /* Using thread struct pointer as identification hash */
    412                         tid = (unative_t) t;
    413                         id_buffer[copied_ids++] = tid;
    414                 }
    415         }
    416 
    417         spinlock_unlock(&TASK->lock);
    418         interrupts_restore(ipl);
    419 
    420         mutex_unlock(&TASK->udebug.lock);
    421 
     406                        id_buffer[copied_ids++] = (sysarg_t) thread;
     407                } else
     408                        extra_ids++;
     409        }
     410       
     411        irq_spinlock_unlock(&TASK->lock, true);
     412       
     413        mutex_unlock(&TASK->udebug.lock);
     414       
    422415        *buffer = id_buffer;
    423         *n = copied_ids * sizeof(unative_t);
    424 
     416        *stored = copied_ids * sizeof(sysarg_t);
     417        *needed = (copied_ids + extra_ids) * sizeof(sysarg_t);
     418       
     419        return 0;
     420}
     421
     422/** Read task name.
     423 *
     424 * Returns task name as non-terminated string in a newly allocated buffer.
     425 * Also returns the size of the data.
     426 *
     427 * @param data      Place to store pointer to newly allocated block.
     428 * @param data_size Place to store size of the data.
     429 *
     430 * @return EOK.
     431 *
     432 */
     433int udebug_name_read(char **data, size_t *data_size)
     434{
     435        size_t name_size = str_size(TASK->name) + 1;
     436       
     437        *data = malloc(name_size, 0);
     438        *data_size = name_size;
     439       
     440        memcpy(*data, TASK->name, name_size);
     441       
    425442        return 0;
    426443}
     
    436453 * this function will fail with an EINVAL error code.
    437454 *
    438  * @param buffer        The buffer for storing thread hashes.
    439  */
    440 int udebug_args_read(thread_t *t, void **buffer)
    441 {
    442         int rc;
    443         unative_t *arg_buffer;
    444 
     455 * @param thread Thread where call arguments are to be read.
     456 * @param buffer Place to store pointer to new buffer.
     457 *
     458 * @return EOK on success, ENOENT if @a t is invalid, EINVAL
     459 *         if thread state is not valid for this operation.
     460 *
     461 */
     462int udebug_args_read(thread_t *thread, void **buffer)
     463{
    445464        /* Prepare a buffer to hold the arguments. */
    446         arg_buffer = malloc(6 * sizeof(unative_t), 0);
    447 
     465        sysarg_t *arg_buffer = malloc(6 * sizeof(sysarg_t), 0);
     466       
    448467        /* On success, this will lock t->udebug.lock. */
    449         rc = _thread_op_begin(t, false);
    450         if (rc != EOK) {
     468        int rc = _thread_op_begin(thread, false);
     469        if (rc != EOK)
    451470                return rc;
    452         }
    453 
     471       
    454472        /* Additionally we need to verify that we are inside a syscall. */
    455         if (t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B &&
    456             t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E) {
    457                 _thread_op_end(t);
     473        if ((thread->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B) &&
     474            (thread->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E)) {
     475                _thread_op_end(thread);
    458476                return EINVAL;
    459477        }
    460 
     478       
    461479        /* Copy to a local buffer before releasing the lock. */
    462         memcpy(arg_buffer, t->udebug.syscall_args, 6 * sizeof(unative_t));
    463 
    464         _thread_op_end(t);
    465 
     480        memcpy(arg_buffer, thread->udebug.syscall_args, 6 * sizeof(sysarg_t));
     481       
     482        _thread_op_end(thread);
     483       
    466484        *buffer = arg_buffer;
     485        return 0;
     486}
     487
     488/** Read the register state of the thread.
     489 *
     490 * The contents of the thread's istate structure are copied to a newly
     491 * allocated buffer and a pointer to it is written to @a buffer. The size of
     492 * the buffer will be sizeof(istate_t).
     493 *
     494 * Currently register state cannot be read if the thread is inside a system
     495 * call (as opposed to an exception). This is an implementation limit.
     496 *
     497 * @param thread Thread whose state is to be read.
     498 * @param buffer Place to store pointer to new buffer.
     499 *
     500 * @return EOK on success, ENOENT if @a t is invalid, EINVAL
     501 *         if thread is not in valid state, EBUSY if istate
     502 *         is not available.
     503 *
     504 */
     505int udebug_regs_read(thread_t *thread, void **buffer)
     506{
     507        /* Prepare a buffer to hold the data. */
     508        istate_t *state_buf = malloc(sizeof(istate_t), 0);
     509       
     510        /* On success, this will lock t->udebug.lock */
     511        int rc = _thread_op_begin(thread, false);
     512        if (rc != EOK)
     513                return rc;
     514       
     515        istate_t *state = thread->udebug.uspace_state;
     516        if (state == NULL) {
     517                _thread_op_end(thread);
     518                return EBUSY;
     519        }
     520       
     521        /* Copy to the allocated buffer */
     522        memcpy(state_buf, state, sizeof(istate_t));
     523       
     524        _thread_op_end(thread);
     525       
     526        *buffer = (void *) state_buf;
    467527        return 0;
    468528}
     
    474534 * and a pointer to it is written into @a buffer.
    475535 *
    476  * @param uspace_addr   Address from where to start reading.
    477  * @param n             Number of bytes to read.
    478  * @param buffer        For storing a pointer to the allocated buffer.
    479  */
    480 int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer)
    481 {
    482         void *data_buffer;
    483         int rc;
    484 
     536 * @param uspace_addr Address from where to start reading.
     537 * @param n           Number of bytes to read.
     538 * @param buffer      For storing a pointer to the allocated buffer.
     539 *
     540 */
     541int udebug_mem_read(sysarg_t uspace_addr, size_t n, void **buffer)
     542{
    485543        /* Verify task state */
    486544        mutex_lock(&TASK->udebug.lock);
    487 
     545       
    488546        if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
    489547                mutex_unlock(&TASK->udebug.lock);
    490548                return EBUSY;
    491549        }
    492 
    493         data_buffer = malloc(n, 0);
    494 
    495         /* NOTE: this is not strictly from a syscall... but that shouldn't
    496          * be a problem */
    497         rc = copy_from_uspace(data_buffer, (void *)uspace_addr, n);
    498         mutex_unlock(&TASK->udebug.lock);
    499 
    500         if (rc != 0) return rc;
    501 
     550       
     551        void *data_buffer = malloc(n, 0);
     552       
     553        /*
     554         * NOTE: this is not strictly from a syscall... but that shouldn't
     555         * be a problem
     556         *
     557         */
     558        int rc = copy_from_uspace(data_buffer, (void *) uspace_addr, n);
     559        mutex_unlock(&TASK->udebug.lock);
     560       
     561        if (rc != 0)
     562                return rc;
     563       
    502564        *buffer = data_buffer;
    503565        return 0;
Note: See TracChangeset for help on using the changeset viewer.