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
RevLine 
[9a1b20c]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
[da1bafb]35 * @brief Udebug operations.
[7dc62af]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.
[9a1b20c]40 */
[da1bafb]41
[0108984a]42#include <debug.h>
[9a1b20c]43#include <proc/task.h>
44#include <proc/thread.h>
45#include <arch.h>
46#include <errno.h>
[1902113]47#include <print.h>
[b2a1fd92]48#include <stdbool.h>
[19f857a]49#include <str.h>
[9a1b20c]50#include <syscall/copy.h>
51#include <ipc/ipc.h>
52#include <udebug/udebug.h>
53#include <udebug/udebug_ops.h>
[44a7ee5]54#include <mem.h>
[9a1b20c]55
[da1bafb]56/** Prepare a thread for a debugging operation.
[9a1b20c]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
[1378b2b]63 * is (or is not) go according to being_go (typically false).
[8af9950]64 * It also locks t->udebug.lock, making sure that t->udebug.active
[9a1b20c]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 *
[da1bafb]75 * @param thread Pointer, need not at all be valid.
76 * @param being_go Required thread state.
[7dc62af]77 *
[9a1b20c]78 * Returns EOK if all went well, or an error code otherwise.
[da1bafb]79 *
[9a1b20c]80 */
[b7fd2a0]81static errno_t _thread_op_begin(thread_t *thread, bool being_go)
[9a1b20c]82{
83 mutex_lock(&TASK->udebug.lock);
[a35b458]84
[9a1b20c]85 /* thread_exists() must be called with threads_lock held */
[da1bafb]86 irq_spinlock_lock(&threads_lock, true);
[a35b458]87
[da1bafb]88 if (!thread_exists(thread)) {
89 irq_spinlock_unlock(&threads_lock, true);
[9a1b20c]90 mutex_unlock(&TASK->udebug.lock);
91 return ENOENT;
92 }
[a35b458]93
[da1bafb]94 /* thread->lock is enough to ensure the thread's existence */
95 irq_spinlock_exchange(&threads_lock, &thread->lock);
[a35b458]96
[da1bafb]97 /* Verify that 'thread' is a userspace thread. */
[6eef3c4]98 if (!thread->uspace) {
[9a1b20c]99 /* It's not, deny its existence */
[da1bafb]100 irq_spinlock_unlock(&thread->lock, true);
[9a1b20c]101 mutex_unlock(&TASK->udebug.lock);
102 return ENOENT;
103 }
[a35b458]104
[1378b2b]105 /* Verify debugging state. */
[da1bafb]106 if (thread->udebug.active != true) {
[9a1b20c]107 /* Not in debugging session or undesired GO state */
[da1bafb]108 irq_spinlock_unlock(&thread->lock, true);
[9a1b20c]109 mutex_unlock(&TASK->udebug.lock);
110 return ENOENT;
111 }
[a35b458]112
[9a1b20c]113 /*
[8af9950]114 * Since the thread has active == true, TASK->udebug.lock
115 * is enough to ensure its existence and that active remains
[9a1b20c]116 * true.
[da1bafb]117 *
[9a1b20c]118 */
[da1bafb]119 irq_spinlock_unlock(&thread->lock, true);
[a35b458]120
[1378b2b]121 /* Only mutex TASK->udebug.lock left. */
[a35b458]122
[1378b2b]123 /* Now verify that the thread belongs to the current task. */
[da1bafb]124 if (thread->task != TASK) {
[9a1b20c]125 /* No such thread belonging this task*/
126 mutex_unlock(&TASK->udebug.lock);
127 return ENOENT;
128 }
[a35b458]129
[9a1b20c]130 /*
131 * Now we need to grab the thread's debug lock for synchronization
132 * of the threads stoppability/stop state.
[da1bafb]133 *
[9a1b20c]134 */
[da1bafb]135 mutex_lock(&thread->udebug.lock);
[a35b458]136
[1378b2b]137 /* The big task mutex is no longer needed. */
[9a1b20c]138 mutex_unlock(&TASK->udebug.lock);
[a35b458]139
[da1bafb]140 if (thread->udebug.go != being_go) {
[1378b2b]141 /* Not in debugging session or undesired GO state. */
[da1bafb]142 mutex_unlock(&thread->udebug.lock);
[9a1b20c]143 return EINVAL;
144 }
[a35b458]145
[da1bafb]146 /* Only thread->udebug.lock left. */
[a35b458]147
[da1bafb]148 return EOK; /* All went well. */
[9a1b20c]149}
150
[7dc62af]151/** End debugging operation on a thread. */
[da1bafb]152static void _thread_op_end(thread_t *thread)
[9a1b20c]153{
[da1bafb]154 mutex_unlock(&thread->udebug.lock);
[9a1b20c]155}
156
[7dc62af]157/** Begin debugging the current task.
158 *
159 * Initiates a debugging session for the current task (and its threads).
[b2a1fd92]160 * When the debugging session has started a reply should be sent to the
[7dc62af]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
[b2a1fd92]163 * case the function sets @a *active to @c true.
[7dc62af]164 *
[b2a1fd92]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).
[7dc62af]168 *
[da1bafb]169 * @param call The BEGIN call we are servicing.
[b2a1fd92]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
[da1bafb]172 *
[b2a1fd92]173 * @return EOK on success, EBUSY if the task is already has an active
174 * debugging session.
[9a1b20c]175 */
[b7fd2a0]176errno_t udebug_begin(call_t *call, bool *active)
[9a1b20c]177{
[da1bafb]178 LOG("Debugging task %" PRIu64, TASK->taskid);
[a35b458]179
[9a1b20c]180 mutex_lock(&TASK->udebug.lock);
[a35b458]181
[9a1b20c]182 if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
183 mutex_unlock(&TASK->udebug.lock);
184 return EBUSY;
185 }
[a35b458]186
[9a1b20c]187 TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
188 TASK->udebug.begin_call = call;
189 TASK->udebug.debugger = call->sender;
[a35b458]190
[bd253241]191 if (TASK->udebug.not_stoppable_count == 0) {
192 TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
193 TASK->udebug.begin_call = NULL;
[b2a1fd92]194 *active = true; /* directly to active state */
[bd253241]195 } else
[b2a1fd92]196 *active = false; /* only in beginning state */
[a35b458]197
[8af9950]198 /* Set udebug.active on all of the task's userspace threads. */
[a35b458]199
[feeac0d]200 list_foreach(TASK->threads, th_link, thread_t, thread) {
[da1bafb]201 mutex_lock(&thread->udebug.lock);
[6eef3c4]202 if (thread->uspace) {
[da1bafb]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);
[9a1b20c]208 }
[a35b458]209
[9a1b20c]210 mutex_unlock(&TASK->udebug.lock);
[b2a1fd92]211 return EOK;
[9a1b20c]212}
213
[7dc62af]214/** Finish debugging the current task.
215 *
216 * Closes the debugging session for the current task.
[da1bafb]217 *
[cde999a]218 * @return Zero on success or an error code.
[da1bafb]219 *
[7dc62af]220 */
[b7fd2a0]221errno_t udebug_end(void)
[9a1b20c]222{
[ae5aa90]223 LOG("Task %" PRIu64, TASK->taskid);
[a35b458]224
[9a1b20c]225 mutex_lock(&TASK->udebug.lock);
[b7fd2a0]226 errno_t rc = udebug_task_cleanup(TASK);
[9a1b20c]227 mutex_unlock(&TASK->udebug.lock);
[a35b458]228
[9a1b20c]229 return rc;
230}
231
[7dc62af]232/** Set the event mask.
233 *
234 * Sets the event mask that determines which events are enabled.
235 *
[da1bafb]236 * @param mask Or combination of events that should be enabled.
237 *
[cde999a]238 * @return Zero on success or an error code.
[da1bafb]239 *
[7dc62af]240 */
[b7fd2a0]241errno_t udebug_set_evmask(udebug_evmask_t mask)
[9a1b20c]242{
[ae5aa90]243 LOG("mask = 0x%x", mask);
[a35b458]244
[9a1b20c]245 mutex_lock(&TASK->udebug.lock);
[a35b458]246
[9a1b20c]247 if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
248 mutex_unlock(&TASK->udebug.lock);
249 return EINVAL;
250 }
[a35b458]251
[9a1b20c]252 TASK->udebug.evmask = mask;
253 mutex_unlock(&TASK->udebug.lock);
[a35b458]254
[7f11dc6]255 return EOK;
[9a1b20c]256}
257
[7dc62af]258/** Give thread GO.
259 *
[1378b2b]260 * Upon recieving a go message, the thread is given GO. Being GO
[7dc62af]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 *
[da1bafb]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 *
[7dc62af]267 */
[b7fd2a0]268errno_t udebug_go(thread_t *thread, call_t *call)
[9a1b20c]269{
[da1bafb]270 /* On success, this will lock thread->udebug.lock. */
[b7fd2a0]271 errno_t rc = _thread_op_begin(thread, false);
[da1bafb]272 if (rc != EOK)
[9a1b20c]273 return rc;
[a35b458]274
[da1bafb]275 thread->udebug.go_call = call;
276 thread->udebug.go = true;
277 thread->udebug.cur_event = 0; /* none */
[a35b458]278
[9a1b20c]279 /*
[da1bafb]280 * Neither thread's lock nor threads_lock may be held during wakeup.
281 *
[9a1b20c]282 */
[da1bafb]283 waitq_wakeup(&thread->udebug.go_wq, WAKEUP_FIRST);
[a35b458]284
[da1bafb]285 _thread_op_end(thread);
[a35b458]286
[7f11dc6]287 return EOK;
[9a1b20c]288}
289
[7dc62af]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 *
[da1bafb]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 *
[7dc62af]298 */
[b7fd2a0]299errno_t udebug_stop(thread_t *thread, call_t *call)
[9a1b20c]300{
[ae5aa90]301 LOG("udebug_stop()");
[a35b458]302
[9a1b20c]303 /*
[da1bafb]304 * On success, this will lock thread->udebug.lock. Note that this
305 * makes sure the thread is not stopped.
306 *
[9a1b20c]307 */
[b7fd2a0]308 errno_t rc = _thread_op_begin(thread, true);
[da1bafb]309 if (rc != EOK)
[9a1b20c]310 return rc;
[a35b458]311
[1378b2b]312 /* Take GO away from the thread. */
[da1bafb]313 thread->udebug.go = false;
[a35b458]314
[da1bafb]315 if (thread->udebug.stoppable != true) {
[1378b2b]316 /* Answer will be sent when the thread becomes stoppable. */
[da1bafb]317 _thread_op_end(thread);
[7f11dc6]318 return EOK;
[9a1b20c]319 }
[a35b458]320
[9a1b20c]321 /*
[1378b2b]322 * Answer GO call.
[da1bafb]323 *
[9a1b20c]324 */
[a35b458]325
[1378b2b]326 /* Make sure nobody takes this call away from us. */
[da1bafb]327 call = thread->udebug.go_call;
328 thread->udebug.go_call = NULL;
[a35b458]329
[9a1b20c]330 IPC_SET_RETVAL(call->data, 0);
331 IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
[a35b458]332
[9a1b20c]333 THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
[a35b458]334
[da1bafb]335 _thread_op_end(thread);
[a35b458]336
[741fd16]337 mutex_lock(&TASK->udebug.lock);
[9a1b20c]338 ipc_answer(&TASK->answerbox, call);
339 mutex_unlock(&TASK->udebug.lock);
[a35b458]340
[7f11dc6]341 return EOK;
[9a1b20c]342}
343
[7dc62af]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
[336db295]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.
[7dc62af]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 *
[da1bafb]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 *
[7dc62af]365 */
[b7fd2a0]366errno_t udebug_thread_read(void **buffer, size_t buf_size, size_t *stored,
[336db295]367 size_t *needed)
[9a1b20c]368{
[ae5aa90]369 LOG("udebug_thread_read()");
[a35b458]370
[9a1b20c]371 /* Allocate a buffer to hold thread IDs */
[96b02eb9]372 sysarg_t *id_buffer = malloc(buf_size + 1, 0);
[a35b458]373
[9a1b20c]374 mutex_lock(&TASK->udebug.lock);
[a35b458]375
[9a1b20c]376 /* Verify task state */
377 if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
378 mutex_unlock(&TASK->udebug.lock);
[87a2f9b]379 free(id_buffer);
[9a1b20c]380 return EINVAL;
381 }
[a35b458]382
[da1bafb]383 irq_spinlock_lock(&TASK->lock, true);
[a35b458]384
[9a1b20c]385 /* Copy down the thread IDs */
[a35b458]386
[96b02eb9]387 size_t max_ids = buf_size / sizeof(sysarg_t);
[da1bafb]388 size_t copied_ids = 0;
389 size_t extra_ids = 0;
[a35b458]390
[9a1b20c]391 /* FIXME: make sure the thread isn't past debug shutdown... */
[feeac0d]392 list_foreach(TASK->threads, th_link, thread_t, thread) {
[da1bafb]393 irq_spinlock_lock(&thread->lock, false);
[6eef3c4]394 bool uspace = thread->uspace;
[da1bafb]395 irq_spinlock_unlock(&thread->lock, false);
[a35b458]396
[1378b2b]397 /* Not interested in kernel threads. */
[6eef3c4]398 if (!uspace)
[336db295]399 continue;
[a35b458]400
[336db295]401 if (copied_ids < max_ids) {
[9a1b20c]402 /* Using thread struct pointer as identification hash */
[96b02eb9]403 id_buffer[copied_ids++] = (sysarg_t) thread;
[da1bafb]404 } else
[336db295]405 extra_ids++;
[9a1b20c]406 }
[a35b458]407
[da1bafb]408 irq_spinlock_unlock(&TASK->lock, true);
[a35b458]409
[9a1b20c]410 mutex_unlock(&TASK->udebug.lock);
[a35b458]411
[9a1b20c]412 *buffer = id_buffer;
[96b02eb9]413 *stored = copied_ids * sizeof(sysarg_t);
414 *needed = (copied_ids + extra_ids) * sizeof(sysarg_t);
[a35b458]415
[7f11dc6]416 return EOK;
[9a1b20c]417}
418
[3698e44]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 *
[da1bafb]424 * @param data Place to store pointer to newly allocated block.
425 * @param data_size Place to store size of the data.
426 *
[1bfd3d3]427 * @return EOK.
[3698e44]428 *
429 */
[b7fd2a0]430errno_t udebug_name_read(char **data, size_t *data_size)
[3698e44]431{
[da1bafb]432 size_t name_size = str_size(TASK->name) + 1;
[a35b458]433
[3698e44]434 *data = malloc(name_size, 0);
435 *data_size = name_size;
[a35b458]436
[3698e44]437 memcpy(*data, TASK->name, name_size);
[a35b458]438
[7f11dc6]439 return EOK;
[3698e44]440}
441
[7dc62af]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 *
[da1bafb]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 *
[7dc62af]458 */
[b7fd2a0]459errno_t udebug_args_read(thread_t *thread, void **buffer)
[9a1b20c]460{
[1378b2b]461 /* On success, this will lock t->udebug.lock. */
[b7fd2a0]462 errno_t rc = _thread_op_begin(thread, false);
[da1bafb]463 if (rc != EOK)
[9a1b20c]464 return rc;
[a35b458]465
[1378b2b]466 /* Additionally we need to verify that we are inside a syscall. */
[da1bafb]467 if ((thread->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B) &&
468 (thread->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E)) {
469 _thread_op_end(thread);
[9a1b20c]470 return EINVAL;
471 }
[a35b458]472
[87a2f9b]473 /* Prepare a buffer to hold the arguments. */
474 sysarg_t *arg_buffer = malloc(6 * sizeof(sysarg_t), 0);
[a35b458]475
[1378b2b]476 /* Copy to a local buffer before releasing the lock. */
[96b02eb9]477 memcpy(arg_buffer, thread->udebug.syscall_args, 6 * sizeof(sysarg_t));
[a35b458]478
[da1bafb]479 _thread_op_end(thread);
[a35b458]480
[9a1b20c]481 *buffer = arg_buffer;
[7f11dc6]482 return EOK;
[9a1b20c]483}
484
[80487bc5]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 *
[da1bafb]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 *
[80487bc5]501 */
[b7fd2a0]502errno_t udebug_regs_read(thread_t *thread, void **buffer)
[80487bc5]503{
504 /* On success, this will lock t->udebug.lock */
[b7fd2a0]505 errno_t rc = _thread_op_begin(thread, false);
[da1bafb]506 if (rc != EOK)
[80487bc5]507 return rc;
[a35b458]508
[da1bafb]509 istate_t *state = thread->udebug.uspace_state;
[80487bc5]510 if (state == NULL) {
[da1bafb]511 _thread_op_end(thread);
[80487bc5]512 return EBUSY;
513 }
[a35b458]514
[87a2f9b]515 /* Prepare a buffer to hold the data. */
516 istate_t *state_buf = malloc(sizeof(istate_t), 0);
[a35b458]517
[80487bc5]518 /* Copy to the allocated buffer */
519 memcpy(state_buf, state, sizeof(istate_t));
[a35b458]520
[da1bafb]521 _thread_op_end(thread);
[a35b458]522
[80487bc5]523 *buffer = (void *) state_buf;
[7f11dc6]524 return EOK;
[80487bc5]525}
526
[7dc62af]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 *
[da1bafb]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 *
[7dc62af]537 */
[b7fd2a0]538errno_t udebug_mem_read(sysarg_t uspace_addr, size_t n, void **buffer)
[9a1b20c]539{
540 /* Verify task state */
541 mutex_lock(&TASK->udebug.lock);
[a35b458]542
[9a1b20c]543 if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
544 mutex_unlock(&TASK->udebug.lock);
545 return EBUSY;
546 }
[a35b458]547
[da1bafb]548 void *data_buffer = malloc(n, 0);
[a35b458]549
[da1bafb]550 /*
551 * NOTE: this is not strictly from a syscall... but that shouldn't
552 * be a problem
553 *
554 */
[b7fd2a0]555 errno_t rc = copy_from_uspace(data_buffer, (void *) uspace_addr, n);
[9a1b20c]556 mutex_unlock(&TASK->udebug.lock);
[a35b458]557
[a53ed3a]558 if (rc != EOK)
[da1bafb]559 return rc;
[a35b458]560
[9a1b20c]561 *buffer = data_buffer;
[7f11dc6]562 return EOK;
[9a1b20c]563}
564
565/** @}
566 */
Note: See TracBrowser for help on using the repository browser.