source: mainline/kernel/generic/src/udebug/udebug_ops.c@ eed4139

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eed4139 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 15.7 KB
Line 
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
29/** @addtogroup generic
30 * @{
31 */
32
33/**
34 * @file
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.
40 */
41
42#include <debug.h>
43#include <proc/task.h>
44#include <proc/thread.h>
45#include <arch.h>
46#include <errno.h>
47#include <print.h>
48#include <stdbool.h>
49#include <str.h>
50#include <syscall/copy.h>
51#include <ipc/ipc.h>
52#include <udebug/udebug.h>
53#include <udebug/udebug_ops.h>
54#include <mem.h>
55
56/** Prepare a thread for a debugging operation.
57 *
58 * Simply put, return thread t with t->udebug.lock held,
59 * but only if it verifies all conditions.
60 *
61 * Specifically, verifies that thread t exists, is a userspace thread,
62 * and belongs to the current task (TASK). Verifies, that the thread
63 * is (or is not) go according to being_go (typically false).
64 * It also locks t->udebug.lock, making sure that t->udebug.active
65 * is true - that the thread is in a valid debugging session.
66 *
67 * With this verified and the t->udebug.lock mutex held, it is ensured
68 * that the thread cannot leave the debugging session, let alone cease
69 * to exist.
70 *
71 * In this function, holding the TASK->udebug.lock mutex prevents the
72 * thread from leaving the debugging session, while relaxing from
73 * the t->lock spinlock to the t->udebug.lock mutex.
74 *
75 * @param thread Pointer, need not at all be valid.
76 * @param being_go Required thread state.
77 *
78 * Returns EOK if all went well, or an error code otherwise.
79 *
80 */
81static errno_t _thread_op_begin(thread_t *thread, bool being_go)
82{
83 mutex_lock(&TASK->udebug.lock);
84
85 /* thread_exists() must be called with threads_lock held */
86 irq_spinlock_lock(&threads_lock, true);
87
88 if (!thread_exists(thread)) {
89 irq_spinlock_unlock(&threads_lock, true);
90 mutex_unlock(&TASK->udebug.lock);
91 return ENOENT;
92 }
93
94 /* thread->lock is enough to ensure the thread's existence */
95 irq_spinlock_exchange(&threads_lock, &thread->lock);
96
97 /* Verify that 'thread' is a userspace thread. */
98 if (!thread->uspace) {
99 /* It's not, deny its existence */
100 irq_spinlock_unlock(&thread->lock, true);
101 mutex_unlock(&TASK->udebug.lock);
102 return ENOENT;
103 }
104
105 /* Verify debugging state. */
106 if (thread->udebug.active != true) {
107 /* Not in debugging session or undesired GO state */
108 irq_spinlock_unlock(&thread->lock, true);
109 mutex_unlock(&TASK->udebug.lock);
110 return ENOENT;
111 }
112
113 /*
114 * Since the thread has active == true, TASK->udebug.lock
115 * is enough to ensure its existence and that active remains
116 * true.
117 *
118 */
119 irq_spinlock_unlock(&thread->lock, true);
120
121 /* Only mutex TASK->udebug.lock left. */
122
123 /* Now verify that the thread belongs to the current task. */
124 if (thread->task != TASK) {
125 /* No such thread belonging this task*/
126 mutex_unlock(&TASK->udebug.lock);
127 return ENOENT;
128 }
129
130 /*
131 * Now we need to grab the thread's debug lock for synchronization
132 * of the threads stoppability/stop state.
133 *
134 */
135 mutex_lock(&thread->udebug.lock);
136
137 /* The big task mutex is no longer needed. */
138 mutex_unlock(&TASK->udebug.lock);
139
140 if (thread->udebug.go != being_go) {
141 /* Not in debugging session or undesired GO state. */
142 mutex_unlock(&thread->udebug.lock);
143 return EINVAL;
144 }
145
146 /* Only thread->udebug.lock left. */
147
148 return EOK; /* All went well. */
149}
150
151/** End debugging operation on a thread. */
152static void _thread_op_end(thread_t *thread)
153{
154 mutex_unlock(&thread->udebug.lock);
155}
156
157/** Begin debugging the current task.
158 *
159 * Initiates a debugging session for the current task (and its threads).
160 * When the debugging session has started a reply should be sent to the
161 * UDEBUG_BEGIN call. This may happen immediately in this function if
162 * all the threads in this task are stoppable at the moment and in this
163 * case the function sets @a *active to @c true.
164 *
165 * Otherwise the function sets @a *active to false and the resonse should
166 * be sent as soon as all the threads become stoppable (i.e. they can be
167 * considered stopped).
168 *
169 * @param call The BEGIN call we are servicing.
170 * @param active Place to store @c true iff we went directly to active state,
171 * @c false if we only went to beginning state
172 *
173 * @return EOK on success, EBUSY if the task is already has an active
174 * debugging session.
175 */
176errno_t udebug_begin(call_t *call, bool *active)
177{
178 LOG("Debugging task %" PRIu64, TASK->taskid);
179
180 mutex_lock(&TASK->udebug.lock);
181
182 if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
183 mutex_unlock(&TASK->udebug.lock);
184 return EBUSY;
185 }
186
187 TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
188 TASK->udebug.begin_call = call;
189 TASK->udebug.debugger = call->sender;
190
191 if (TASK->udebug.not_stoppable_count == 0) {
192 TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
193 TASK->udebug.begin_call = NULL;
194 *active = true; /* directly to active state */
195 } else
196 *active = false; /* only in beginning state */
197
198 /* Set udebug.active on all of the task's userspace threads. */
199
200 list_foreach(TASK->threads, th_link, thread_t, thread) {
201 mutex_lock(&thread->udebug.lock);
202 if (thread->uspace) {
203 thread->udebug.active = true;
204 mutex_unlock(&thread->udebug.lock);
205 condvar_broadcast(&thread->udebug.active_cv);
206 } else
207 mutex_unlock(&thread->udebug.lock);
208 }
209
210 mutex_unlock(&TASK->udebug.lock);
211 return EOK;
212}
213
214/** Finish debugging the current task.
215 *
216 * Closes the debugging session for the current task.
217 *
218 * @return Zero on success or an error code.
219 *
220 */
221errno_t udebug_end(void)
222{
223 LOG("Task %" PRIu64, TASK->taskid);
224
225 mutex_lock(&TASK->udebug.lock);
226 errno_t rc = udebug_task_cleanup(TASK);
227 mutex_unlock(&TASK->udebug.lock);
228
229 return rc;
230}
231
232/** Set the event mask.
233 *
234 * Sets the event mask that determines which events are enabled.
235 *
236 * @param mask Or combination of events that should be enabled.
237 *
238 * @return Zero on success or an error code.
239 *
240 */
241errno_t udebug_set_evmask(udebug_evmask_t mask)
242{
243 LOG("mask = 0x%x", mask);
244
245 mutex_lock(&TASK->udebug.lock);
246
247 if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
248 mutex_unlock(&TASK->udebug.lock);
249 return EINVAL;
250 }
251
252 TASK->udebug.evmask = mask;
253 mutex_unlock(&TASK->udebug.lock);
254
255 return EOK;
256}
257
258/** Give thread GO.
259 *
260 * Upon recieving a go message, the thread is given GO. Being GO
261 * means the thread is allowed to execute userspace code (until
262 * a debugging event or STOP occurs, at which point the thread loses GO.
263 *
264 * @param thread The thread to operate on (unlocked and need not be valid).
265 * @param call The GO call that we are servicing.
266 *
267 */
268errno_t udebug_go(thread_t *thread, call_t *call)
269{
270 /* On success, this will lock thread->udebug.lock. */
271 errno_t rc = _thread_op_begin(thread, false);
272 if (rc != EOK)
273 return rc;
274
275 thread->udebug.go_call = call;
276 thread->udebug.go = true;
277 thread->udebug.cur_event = 0; /* none */
278
279 /*
280 * Neither thread's lock nor threads_lock may be held during wakeup.
281 *
282 */
283 waitq_wakeup(&thread->udebug.go_wq, WAKEUP_FIRST);
284
285 _thread_op_end(thread);
286
287 return EOK;
288}
289
290/** Stop a thread (i.e. take its GO away)
291 *
292 * Generates a STOP event as soon as the thread becomes stoppable (i.e.
293 * can be considered stopped).
294 *
295 * @param thread The thread to operate on (unlocked and need not be valid).
296 * @param call The GO call that we are servicing.
297 *
298 */
299errno_t udebug_stop(thread_t *thread, call_t *call)
300{
301 LOG("udebug_stop()");
302
303 /*
304 * On success, this will lock thread->udebug.lock. Note that this
305 * makes sure the thread is not stopped.
306 *
307 */
308 errno_t rc = _thread_op_begin(thread, true);
309 if (rc != EOK)
310 return rc;
311
312 /* Take GO away from the thread. */
313 thread->udebug.go = false;
314
315 if (thread->udebug.stoppable != true) {
316 /* Answer will be sent when the thread becomes stoppable. */
317 _thread_op_end(thread);
318 return EOK;
319 }
320
321 /*
322 * Answer GO call.
323 *
324 */
325
326 /* Make sure nobody takes this call away from us. */
327 call = thread->udebug.go_call;
328 thread->udebug.go_call = NULL;
329
330 IPC_SET_RETVAL(call->data, 0);
331 IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
332
333 THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
334
335 _thread_op_end(thread);
336
337 mutex_lock(&TASK->udebug.lock);
338 ipc_answer(&TASK->answerbox, call);
339 mutex_unlock(&TASK->udebug.lock);
340
341 return EOK;
342}
343
344/** Read the list of userspace threads in the current task.
345 *
346 * The list takes the form of a sequence of thread hashes (i.e. the pointers
347 * to thread structures). A buffer of size @a buf_size is allocated and
348 * a pointer to it written to @a buffer. The sequence of hashes is written
349 * into this buffer.
350 *
351 * If the sequence is longer than @a buf_size bytes, only as much hashes
352 * as can fit are copied. The number of bytes copied is stored in @a stored.
353 * The total number of thread bytes that could have been saved had there been
354 * enough space is stored in @a needed.
355 *
356 * The rationale for having @a buf_size is that this function is only
357 * used for servicing the THREAD_READ message, which always specifies
358 * a maximum size for the userspace buffer.
359 *
360 * @param buffer The buffer for storing thread hashes.
361 * @param buf_size Buffer size in bytes.
362 * @param stored The actual number of bytes copied will be stored here.
363 * @param needed Total number of hashes that could have been saved.
364 *
365 */
366errno_t udebug_thread_read(void **buffer, size_t buf_size, size_t *stored,
367 size_t *needed)
368{
369 LOG("udebug_thread_read()");
370
371 /* Allocate a buffer to hold thread IDs */
372 sysarg_t *id_buffer = malloc(buf_size + 1, 0);
373
374 mutex_lock(&TASK->udebug.lock);
375
376 /* Verify task state */
377 if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
378 mutex_unlock(&TASK->udebug.lock);
379 free(id_buffer);
380 return EINVAL;
381 }
382
383 irq_spinlock_lock(&TASK->lock, true);
384
385 /* Copy down the thread IDs */
386
387 size_t max_ids = buf_size / sizeof(sysarg_t);
388 size_t copied_ids = 0;
389 size_t extra_ids = 0;
390
391 /* FIXME: make sure the thread isn't past debug shutdown... */
392 list_foreach(TASK->threads, th_link, thread_t, thread) {
393 irq_spinlock_lock(&thread->lock, false);
394 bool uspace = thread->uspace;
395 irq_spinlock_unlock(&thread->lock, false);
396
397 /* Not interested in kernel threads. */
398 if (!uspace)
399 continue;
400
401 if (copied_ids < max_ids) {
402 /* Using thread struct pointer as identification hash */
403 id_buffer[copied_ids++] = (sysarg_t) thread;
404 } else
405 extra_ids++;
406 }
407
408 irq_spinlock_unlock(&TASK->lock, true);
409
410 mutex_unlock(&TASK->udebug.lock);
411
412 *buffer = id_buffer;
413 *stored = copied_ids * sizeof(sysarg_t);
414 *needed = (copied_ids + extra_ids) * sizeof(sysarg_t);
415
416 return EOK;
417}
418
419/** Read task name.
420 *
421 * Returns task name as non-terminated string in a newly allocated buffer.
422 * Also returns the size of the data.
423 *
424 * @param data Place to store pointer to newly allocated block.
425 * @param data_size Place to store size of the data.
426 *
427 * @return EOK.
428 *
429 */
430errno_t udebug_name_read(char **data, size_t *data_size)
431{
432 size_t name_size = str_size(TASK->name) + 1;
433
434 *data = malloc(name_size, 0);
435 *data_size = name_size;
436
437 memcpy(*data, TASK->name, name_size);
438
439 return EOK;
440}
441
442/** Read the arguments of a system call.
443 *
444 * The arguments of the system call being being executed are copied
445 * to an allocated buffer and a pointer to it is written to @a buffer.
446 * The size of the buffer is exactly such that it can hold the maximum number
447 * of system-call arguments.
448 *
449 * Unless the thread is currently blocked in a SYSCALL_B or SYSCALL_E event,
450 * this function will fail with an EINVAL error code.
451 *
452 * @param thread Thread where call arguments are to be read.
453 * @param buffer Place to store pointer to new buffer.
454 *
455 * @return EOK on success, ENOENT if @a t is invalid, EINVAL
456 * if thread state is not valid for this operation.
457 *
458 */
459errno_t udebug_args_read(thread_t *thread, void **buffer)
460{
461 /* On success, this will lock t->udebug.lock. */
462 errno_t rc = _thread_op_begin(thread, false);
463 if (rc != EOK)
464 return rc;
465
466 /* Additionally we need to verify that we are inside a syscall. */
467 if ((thread->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B) &&
468 (thread->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E)) {
469 _thread_op_end(thread);
470 return EINVAL;
471 }
472
473 /* Prepare a buffer to hold the arguments. */
474 sysarg_t *arg_buffer = malloc(6 * sizeof(sysarg_t), 0);
475
476 /* Copy to a local buffer before releasing the lock. */
477 memcpy(arg_buffer, thread->udebug.syscall_args, 6 * sizeof(sysarg_t));
478
479 _thread_op_end(thread);
480
481 *buffer = arg_buffer;
482 return EOK;
483}
484
485/** Read the register state of the thread.
486 *
487 * The contents of the thread's istate structure are copied to a newly
488 * allocated buffer and a pointer to it is written to @a buffer. The size of
489 * the buffer will be sizeof(istate_t).
490 *
491 * Currently register state cannot be read if the thread is inside a system
492 * call (as opposed to an exception). This is an implementation limit.
493 *
494 * @param thread Thread whose state is to be read.
495 * @param buffer Place to store pointer to new buffer.
496 *
497 * @return EOK on success, ENOENT if @a t is invalid, EINVAL
498 * if thread is not in valid state, EBUSY if istate
499 * is not available.
500 *
501 */
502errno_t udebug_regs_read(thread_t *thread, void **buffer)
503{
504 /* On success, this will lock t->udebug.lock */
505 errno_t rc = _thread_op_begin(thread, false);
506 if (rc != EOK)
507 return rc;
508
509 istate_t *state = thread->udebug.uspace_state;
510 if (state == NULL) {
511 _thread_op_end(thread);
512 return EBUSY;
513 }
514
515 /* Prepare a buffer to hold the data. */
516 istate_t *state_buf = malloc(sizeof(istate_t), 0);
517
518 /* Copy to the allocated buffer */
519 memcpy(state_buf, state, sizeof(istate_t));
520
521 _thread_op_end(thread);
522
523 *buffer = (void *) state_buf;
524 return EOK;
525}
526
527/** Read the memory of the debugged task.
528 *
529 * Reads @a n bytes from the address space of the debugged task, starting
530 * from @a uspace_addr. The bytes are copied into an allocated buffer
531 * and a pointer to it is written into @a buffer.
532 *
533 * @param uspace_addr Address from where to start reading.
534 * @param n Number of bytes to read.
535 * @param buffer For storing a pointer to the allocated buffer.
536 *
537 */
538errno_t udebug_mem_read(sysarg_t uspace_addr, size_t n, void **buffer)
539{
540 /* Verify task state */
541 mutex_lock(&TASK->udebug.lock);
542
543 if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
544 mutex_unlock(&TASK->udebug.lock);
545 return EBUSY;
546 }
547
548 void *data_buffer = malloc(n, 0);
549
550 /*
551 * NOTE: this is not strictly from a syscall... but that shouldn't
552 * be a problem
553 *
554 */
555 errno_t rc = copy_from_uspace(data_buffer, (void *) uspace_addr, n);
556 mutex_unlock(&TASK->udebug.lock);
557
558 if (rc != EOK)
559 return rc;
560
561 *buffer = data_buffer;
562 return EOK;
563}
564
565/** @}
566 */
Note: See TracBrowser for help on using the repository browser.