Rev 3448 | Rev 3674 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3448 | Rev 3474 | ||
---|---|---|---|
Line 31... | Line 31... | ||
31 | */ |
31 | */ |
32 | 32 | ||
33 | /** |
33 | /** |
34 | * @file |
34 | * @file |
35 | * @brief Udebug operations. |
35 | * @brief Udebug operations. |
- | 36 | * |
|
- | 37 | * Udebug operations on tasks and threads are implemented here. The |
|
- | 38 | * functions defined here are called from the udebug_ipc module |
|
- | 39 | * when servicing udebug IPC messages. |
|
36 | */ |
40 | */ |
37 | 41 | ||
38 | #include <debug.h> |
42 | #include <debug.h> |
39 | #include <proc/task.h> |
43 | #include <proc/task.h> |
40 | #include <proc/thread.h> |
44 | #include <proc/thread.h> |
Line 63... | Line 67... | ||
63 | * |
67 | * |
64 | * In this function, holding the TASK->udebug.lock mutex prevents the |
68 | * In this function, holding the TASK->udebug.lock mutex prevents the |
65 | * thread from leaving the debugging session, while relaxing from |
69 | * thread from leaving the debugging session, while relaxing from |
66 | * the t->lock spinlock to the t->udebug.lock mutex. |
70 | * the t->lock spinlock to the t->udebug.lock mutex. |
67 | * |
71 | * |
- | 72 | * @param t Pointer, need not at all be valid. |
|
- | 73 | * @param having_go Required thread state. |
|
- | 74 | * |
|
68 | * Returns EOK if all went well, or an error code otherwise. |
75 | * Returns EOK if all went well, or an error code otherwise. |
69 | */ |
76 | */ |
70 | static int _thread_op_begin(thread_t *t, bool having_go) |
77 | static int _thread_op_begin(thread_t *t, bool having_go) |
71 | { |
78 | { |
72 | task_id_t taskid; |
79 | task_id_t taskid; |
Line 144... | Line 151... | ||
144 | /* Only t->udebug.lock left */ |
151 | /* Only t->udebug.lock left */ |
145 | 152 | ||
146 | return EOK; /* All went well */ |
153 | return EOK; /* All went well */ |
147 | } |
154 | } |
148 | 155 | ||
149 | - | ||
- | 156 | /** End debugging operation on a thread. */ |
|
150 | static void _thread_op_end(thread_t *t) |
157 | static void _thread_op_end(thread_t *t) |
151 | { |
158 | { |
152 | mutex_unlock(&t->udebug.lock); |
159 | mutex_unlock(&t->udebug.lock); |
153 | } |
160 | } |
154 | 161 | ||
- | 162 | /** Begin debugging the current task. |
|
155 | /** |
163 | * |
- | 164 | * Initiates a debugging session for the current task (and its threads). |
|
- | 165 | * When the debugging session has started a reply will be sent to the |
|
- | 166 | * UDEBUG_BEGIN call. This may happen immediately in this function if |
|
- | 167 | * all the threads in this task are stoppable at the moment and in this |
|
- | 168 | * case the function returns 1. |
|
- | 169 | * |
|
- | 170 | * Otherwise the function returns 0 and the reply will be sent as soon as |
|
- | 171 | * all the threads become stoppable (i.e. they can be considered stopped). |
|
- | 172 | * |
|
- | 173 | * @param call The BEGIN call we are servicing. |
|
156 | * \return 0 (ok, but not done yet), 1 (done) or negative error code. |
174 | * @return 0 (OK, but not done yet), 1 (done) or negative error code. |
157 | */ |
175 | */ |
158 | int udebug_begin(call_t *call) |
176 | int udebug_begin(call_t *call) |
159 | { |
177 | { |
160 | int reply; |
178 | int reply; |
161 | 179 | ||
Line 203... | Line 221... | ||
203 | reply ? "reply" : "stoppability wait"); |
221 | reply ? "reply" : "stoppability wait"); |
204 | 222 | ||
205 | return reply; |
223 | return reply; |
206 | } |
224 | } |
207 | 225 | ||
- | 226 | /** Finish debugging the current task. |
|
- | 227 | * |
|
- | 228 | * Closes the debugging session for the current task. |
|
- | 229 | * @return Zero on success or negative error code. |
|
- | 230 | */ |
|
208 | int udebug_end(void) |
231 | int udebug_end(void) |
209 | { |
232 | { |
210 | int rc; |
233 | int rc; |
211 | 234 | ||
212 | LOG("udebug_end()\n"); |
235 | LOG("udebug_end()\n"); |
Line 219... | Line 242... | ||
219 | mutex_unlock(&TASK->udebug.lock); |
242 | mutex_unlock(&TASK->udebug.lock); |
220 | 243 | ||
221 | return rc; |
244 | return rc; |
222 | } |
245 | } |
223 | 246 | ||
- | 247 | /** Set the event mask. |
|
- | 248 | * |
|
- | 249 | * Sets the event mask that determines which events are enabled. |
|
- | 250 | * |
|
- | 251 | * @param mask Or combination of events that should be enabled. |
|
- | 252 | * @return Zero on success or negative error code. |
|
- | 253 | */ |
|
224 | int udebug_set_evmask(udebug_evmask_t mask) |
254 | int udebug_set_evmask(udebug_evmask_t mask) |
225 | { |
255 | { |
226 | LOG("udebug_set_mask()\n"); |
256 | LOG("udebug_set_mask()\n"); |
227 | 257 | ||
228 | mutex_lock(&TASK->udebug.lock); |
258 | mutex_lock(&TASK->udebug.lock); |
Line 239... | Line 269... | ||
239 | mutex_unlock(&TASK->udebug.lock); |
269 | mutex_unlock(&TASK->udebug.lock); |
240 | 270 | ||
241 | return 0; |
271 | return 0; |
242 | } |
272 | } |
243 | 273 | ||
- | 274 | /** Give thread GO. |
|
- | 275 | * |
|
- | 276 | * Upon recieving a go message, the thread is given GO. Having GO |
|
- | 277 | * means the thread is allowed to execute userspace code (until |
|
- | 278 | * a debugging event or STOP occurs, at which point the thread loses GO. |
|
244 | 279 | * |
|
- | 280 | * @param t The thread to operate on (unlocked and need not be valid). |
|
- | 281 | * @param call The GO call that we are servicing. |
|
- | 282 | */ |
|
245 | int udebug_go(thread_t *t, call_t *call) |
283 | int udebug_go(thread_t *t, call_t *call) |
246 | { |
284 | { |
247 | int rc; |
285 | int rc; |
248 | 286 | ||
249 | /* On success, this will lock t->udebug.lock */ |
287 | /* On success, this will lock t->udebug.lock */ |
Line 264... | Line 302... | ||
264 | _thread_op_end(t); |
302 | _thread_op_end(t); |
265 | 303 | ||
266 | return 0; |
304 | return 0; |
267 | } |
305 | } |
268 | 306 | ||
- | 307 | /** Stop a thread (i.e. take its GO away) |
|
- | 308 | * |
|
- | 309 | * Generates a STOP event as soon as the thread becomes stoppable (i.e. |
|
- | 310 | * can be considered stopped). |
|
- | 311 | * |
|
- | 312 | * @param t The thread to operate on (unlocked and need not be valid). |
|
- | 313 | * @param call The GO call that we are servicing. |
|
- | 314 | */ |
|
269 | int udebug_stop(thread_t *t, call_t *call) |
315 | int udebug_stop(thread_t *t, call_t *call) |
270 | { |
316 | { |
271 | int rc; |
317 | int rc; |
272 | 318 | ||
273 | LOG("udebug_stop()\n"); |
319 | LOG("udebug_stop()\n"); |
Line 313... | Line 359... | ||
313 | 359 | ||
314 | LOG("udebog_stop/done\n"); |
360 | LOG("udebog_stop/done\n"); |
315 | return 0; |
361 | return 0; |
316 | } |
362 | } |
317 | 363 | ||
- | 364 | /** Read the list of userspace threads in the current task. |
|
- | 365 | * |
|
- | 366 | * The list takes the form of a sequence of thread hashes (i.e. the pointers |
|
- | 367 | * to thread structures). A buffer of size @a buf_size is allocated and |
|
- | 368 | * a pointer to it written to @a buffer. The sequence of hashes is written |
|
- | 369 | * into this buffer. |
|
- | 370 | * |
|
- | 371 | * If the sequence is longer than @a buf_size bytes, only as much hashes |
|
- | 372 | * as can fit are copied. The number of thread hashes copied is stored |
|
- | 373 | * in @a n. |
|
- | 374 | * |
|
- | 375 | * The rationale for having @a buf_size is that this function is only |
|
- | 376 | * used for servicing the THREAD_READ message, which always specifies |
|
- | 377 | * a maximum size for the userspace buffer. |
|
- | 378 | * |
|
- | 379 | * @param buffer The buffer for storing thread hashes. |
|
- | 380 | * @param buf_size Buffer size in bytes. |
|
- | 381 | * @param n The actual number of hashes copied will be stored here. |
|
- | 382 | */ |
|
318 | int udebug_thread_read(void **buffer, size_t buf_size, size_t *n) |
383 | int udebug_thread_read(void **buffer, size_t buf_size, size_t *n) |
319 | { |
384 | { |
320 | thread_t *t; |
385 | thread_t *t; |
321 | link_t *cur; |
386 | link_t *cur; |
322 | unative_t tid; |
387 | unative_t tid; |
Line 374... | Line 439... | ||
374 | *n = copied_ids * sizeof(unative_t); |
439 | *n = copied_ids * sizeof(unative_t); |
375 | 440 | ||
376 | return 0; |
441 | return 0; |
377 | } |
442 | } |
378 | 443 | ||
- | 444 | /** Read the arguments of a system call. |
|
- | 445 | * |
|
- | 446 | * The arguments of the system call being being executed are copied |
|
- | 447 | * to an allocated buffer and a pointer to it is written to @a buffer. |
|
- | 448 | * The size of the buffer is exactly such that it can hold the maximum number |
|
- | 449 | * of system-call arguments. |
|
- | 450 | * |
|
- | 451 | * Unless the thread is currently blocked in a SYSCALL_B or SYSCALL_E event, |
|
- | 452 | * this function will fail with an EINVAL error code. |
|
- | 453 | * |
|
- | 454 | * @param buffer The buffer for storing thread hashes. |
|
- | 455 | */ |
|
379 | int udebug_args_read(thread_t *t, void **buffer) |
456 | int udebug_args_read(thread_t *t, void **buffer) |
380 | { |
457 | { |
381 | int rc; |
458 | int rc; |
382 | unative_t *arg_buffer; |
459 | unative_t *arg_buffer; |
383 | 460 | ||
Line 404... | Line 481... | ||
404 | 481 | ||
405 | *buffer = arg_buffer; |
482 | *buffer = arg_buffer; |
406 | return 0; |
483 | return 0; |
407 | } |
484 | } |
408 | 485 | ||
- | 486 | /** Read the memory of the debugged task. |
|
- | 487 | * |
|
- | 488 | * Reads @a n bytes from the address space of the debugged task, starting |
|
- | 489 | * from @a uspace_addr. The bytes are copied into an allocated buffer |
|
- | 490 | * and a pointer to it is written into @a buffer. |
|
- | 491 | * |
|
- | 492 | * @param uspace_addr Address from where to start reading. |
|
- | 493 | * @param n Number of bytes to read. |
|
- | 494 | * @param buffer For storing a pointer to the allocated buffer. |
|
- | 495 | */ |
|
409 | int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer) |
496 | int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer) |
410 | { |
497 | { |
411 | void *data_buffer; |
498 | void *data_buffer; |
412 | int rc; |
499 | int rc; |
413 | 500 |