Subversion Repositories HelenOS

Rev

Rev 3441 | Rev 3600 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3441 Rev 3457
1
/*
1
/*
2
 * Copyright (c) 2008 Jiri Svoboda
2
 * Copyright (c) 2008 Jiri Svoboda
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
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
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.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup generic
29
/** @addtogroup generic
30
 * @{
30
 * @{
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>
41
#include <arch.h>
45
#include <arch.h>
42
#include <errno.h>
46
#include <errno.h>
43
#include <syscall/copy.h>
47
#include <syscall/copy.h>
44
#include <ipc/ipc.h>
48
#include <ipc/ipc.h>
45
#include <udebug/udebug.h>
49
#include <udebug/udebug.h>
46
#include <udebug/udebug_ops.h>
50
#include <udebug/udebug_ops.h>
47
 
51
 
48
/**
52
/**
49
 * Prepare a thread for a debugging operation.
53
 * Prepare a thread for a debugging operation.
50
 *
54
 *
51
 * Simply put, return thread t with t->udebug.lock held,
55
 * Simply put, return thread t with t->udebug.lock held,
52
 * but only if it verifies all conditions.
56
 * but only if it verifies all conditions.
53
 *
57
 *
54
 * Specifically, verifies that thread t exists, is a userspace thread,
58
 * Specifically, verifies that thread t exists, is a userspace thread,
55
 * and belongs to the current task (TASK). Verifies, that the thread
59
 * and belongs to the current task (TASK). Verifies, that the thread
56
 * has (or hasn't) go according to having_go (typically false).
60
 * has (or hasn't) go according to having_go (typically false).
57
 * It also locks t->udebug.lock, making sure that t->udebug.debug_active
61
 * It also locks t->udebug.lock, making sure that t->udebug.debug_active
58
 * is true - that the thread is in a valid debugging session.
62
 * is true - that the thread is in a valid debugging session.
59
 *
63
 *
60
 * With this verified and the t->udebug.lock mutex held, it is ensured
64
 * With this verified and the t->udebug.lock mutex held, it is ensured
61
 * that the thread cannot leave the debugging session, let alone cease
65
 * that the thread cannot leave the debugging session, let alone cease
62
 * to exist.
66
 * to exist.
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;
73
    ipl_t ipl;
80
    ipl_t ipl;
74
 
81
 
75
    taskid = TASK->taskid;
82
    taskid = TASK->taskid;
76
 
83
 
77
    mutex_lock(&TASK->udebug.lock);
84
    mutex_lock(&TASK->udebug.lock);
78
 
85
 
79
    /* thread_exists() must be called with threads_lock held */
86
    /* thread_exists() must be called with threads_lock held */
80
    ipl = interrupts_disable();
87
    ipl = interrupts_disable();
81
    spinlock_lock(&threads_lock);
88
    spinlock_lock(&threads_lock);
82
 
89
 
83
    if (!thread_exists(t)) {
90
    if (!thread_exists(t)) {
84
        spinlock_unlock(&threads_lock);
91
        spinlock_unlock(&threads_lock);
85
        interrupts_restore(ipl);
92
        interrupts_restore(ipl);
86
        mutex_unlock(&TASK->udebug.lock);
93
        mutex_unlock(&TASK->udebug.lock);
87
        return ENOENT;
94
        return ENOENT;
88
    }
95
    }
89
 
96
 
90
    /* t->lock is enough to ensure the thread's existence */
97
    /* t->lock is enough to ensure the thread's existence */
91
    spinlock_lock(&t->lock);
98
    spinlock_lock(&t->lock);
92
    spinlock_unlock(&threads_lock);
99
    spinlock_unlock(&threads_lock);
93
 
100
 
94
    /* Verify that 't' is a userspace thread */
101
    /* Verify that 't' is a userspace thread */
95
    if ((t->flags & THREAD_FLAG_USPACE) == 0) {
102
    if ((t->flags & THREAD_FLAG_USPACE) == 0) {
96
        /* It's not, deny its existence */
103
        /* It's not, deny its existence */
97
        spinlock_unlock(&t->lock);
104
        spinlock_unlock(&t->lock);
98
        interrupts_restore(ipl);
105
        interrupts_restore(ipl);
99
        mutex_unlock(&TASK->udebug.lock);
106
        mutex_unlock(&TASK->udebug.lock);
100
        return ENOENT;
107
        return ENOENT;
101
    }
108
    }
102
 
109
 
103
    /* Verify debugging state */
110
    /* Verify debugging state */
104
    if (t->udebug.debug_active != true) {
111
    if (t->udebug.debug_active != true) {
105
        /* Not in debugging session or undesired GO state */
112
        /* Not in debugging session or undesired GO state */
106
        spinlock_unlock(&t->lock);
113
        spinlock_unlock(&t->lock);
107
        interrupts_restore(ipl);
114
        interrupts_restore(ipl);
108
        mutex_unlock(&TASK->udebug.lock);
115
        mutex_unlock(&TASK->udebug.lock);
109
        return ENOENT;
116
        return ENOENT;
110
    }
117
    }
111
 
118
 
112
    /*
119
    /*
113
     * Since the thread has debug_active == true, TASK->udebug.lock
120
     * Since the thread has debug_active == true, TASK->udebug.lock
114
     * is enough to ensure its existence and that debug_active remains
121
     * is enough to ensure its existence and that debug_active remains
115
     * true.
122
     * true.
116
     */
123
     */
117
    spinlock_unlock(&t->lock);
124
    spinlock_unlock(&t->lock);
118
    interrupts_restore(ipl);
125
    interrupts_restore(ipl);
119
 
126
 
120
    /* Only mutex TASK->udebug.lock left */
127
    /* Only mutex TASK->udebug.lock left */
121
   
128
   
122
    /* Now verify that the thread belongs to the current task */
129
    /* Now verify that the thread belongs to the current task */
123
    if (t->task != TASK) {
130
    if (t->task != TASK) {
124
        /* No such thread belonging this task*/
131
        /* No such thread belonging this task*/
125
        mutex_unlock(&TASK->udebug.lock);
132
        mutex_unlock(&TASK->udebug.lock);
126
        return ENOENT;
133
        return ENOENT;
127
    }
134
    }
128
 
135
 
129
    /*
136
    /*
130
     * Now we need to grab the thread's debug lock for synchronization
137
     * Now we need to grab the thread's debug lock for synchronization
131
     * of the threads stoppability/stop state.
138
     * of the threads stoppability/stop state.
132
     */
139
     */
133
    mutex_lock(&t->udebug.lock);
140
    mutex_lock(&t->udebug.lock);
134
 
141
 
135
    /* The big task mutex is no longer needed */
142
    /* The big task mutex is no longer needed */
136
    mutex_unlock(&TASK->udebug.lock);
143
    mutex_unlock(&TASK->udebug.lock);
137
 
144
 
138
    if (!t->udebug.stop != having_go) {
145
    if (!t->udebug.stop != having_go) {
139
        /* Not in debugging session or undesired GO state */
146
        /* Not in debugging session or undesired GO state */
140
        mutex_unlock(&t->udebug.lock);
147
        mutex_unlock(&t->udebug.lock);
141
        return EINVAL;
148
        return EINVAL;
142
    }
149
    }
143
 
150
 
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
 
162
    thread_t *t;
180
    thread_t *t;
163
    link_t *cur;
181
    link_t *cur;
164
 
182
 
165
    LOG("udebug_begin()\n");
183
    LOG("udebug_begin()\n");
166
 
184
 
167
    mutex_lock(&TASK->udebug.lock);
185
    mutex_lock(&TASK->udebug.lock);
168
    LOG("debugging task %llu\n", TASK->taskid);
186
    LOG("debugging task %llu\n", TASK->taskid);
169
 
187
 
170
    if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
188
    if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
171
        mutex_unlock(&TASK->udebug.lock);
189
        mutex_unlock(&TASK->udebug.lock);
172
        LOG("udebug_begin(): busy error\n");
190
        LOG("udebug_begin(): busy error\n");
173
 
191
 
174
        return EBUSY;
192
        return EBUSY;
175
    }
193
    }
176
 
194
 
177
    TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
195
    TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
178
    TASK->udebug.begin_call = call;
196
    TASK->udebug.begin_call = call;
179
    TASK->udebug.debugger = call->sender;
197
    TASK->udebug.debugger = call->sender;
180
 
198
 
181
    if (TASK->udebug.not_stoppable_count == 0) {
199
    if (TASK->udebug.not_stoppable_count == 0) {
182
        TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
200
        TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
183
        TASK->udebug.begin_call = NULL;
201
        TASK->udebug.begin_call = NULL;
184
        reply = 1; /* immediate reply */
202
        reply = 1; /* immediate reply */
185
    } else {
203
    } else {
186
        reply = 0; /* no reply */
204
        reply = 0; /* no reply */
187
    }
205
    }
188
   
206
   
189
    /* Set udebug.debug_active on all of the task's userspace threads */
207
    /* Set udebug.debug_active on all of the task's userspace threads */
190
 
208
 
191
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
209
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
192
        t = list_get_instance(cur, thread_t, th_link);
210
        t = list_get_instance(cur, thread_t, th_link);
193
 
211
 
194
        mutex_lock(&t->udebug.lock);
212
        mutex_lock(&t->udebug.lock);
195
        if ((t->flags & THREAD_FLAG_USPACE) != 0)
213
        if ((t->flags & THREAD_FLAG_USPACE) != 0)
196
            t->udebug.debug_active = true;
214
            t->udebug.debug_active = true;
197
        mutex_unlock(&t->udebug.lock);
215
        mutex_unlock(&t->udebug.lock);
198
    }
216
    }
199
 
217
 
200
    mutex_unlock(&TASK->udebug.lock);
218
    mutex_unlock(&TASK->udebug.lock);
201
 
219
 
202
    LOG("udebug_begin() done (%s)\n",
220
    LOG("udebug_begin() done (%s)\n",
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");
213
 
236
 
214
    mutex_lock(&TASK->udebug.lock);
237
    mutex_lock(&TASK->udebug.lock);
215
    LOG("task %" PRIu64 "\n", TASK->taskid);
238
    LOG("task %" PRIu64 "\n", TASK->taskid);
216
 
239
 
217
    rc = udebug_task_cleanup(TASK);
240
    rc = udebug_task_cleanup(TASK);
218
 
241
 
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);
229
 
259
 
230
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
260
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
231
        mutex_unlock(&TASK->udebug.lock);
261
        mutex_unlock(&TASK->udebug.lock);
232
        LOG("udebug_set_mask(): not active debuging session\n");
262
        LOG("udebug_set_mask(): not active debuging session\n");
233
 
263
 
234
        return EINVAL;
264
        return EINVAL;
235
    }
265
    }
236
 
266
 
237
    TASK->udebug.evmask = mask;
267
    TASK->udebug.evmask = mask;
238
 
268
 
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 */
250
    rc = _thread_op_begin(t, false);
288
    rc = _thread_op_begin(t, false);
251
    if (rc != EOK) {
289
    if (rc != EOK) {
252
        return rc;
290
        return rc;
253
    }
291
    }
254
 
292
 
255
    t->udebug.go_call = call;
293
    t->udebug.go_call = call;
256
    t->udebug.stop = false;
294
    t->udebug.stop = false;
257
    t->udebug.cur_event = 0;    /* none */
295
    t->udebug.cur_event = 0;    /* none */
258
 
296
 
259
    /*
297
    /*
260
     * Neither t's lock nor threads_lock may be held during wakeup
298
     * Neither t's lock nor threads_lock may be held during wakeup
261
     */
299
     */
262
    waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
300
    waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
263
 
301
 
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");
274
    mutex_lock(&TASK->udebug.lock);
320
    mutex_lock(&TASK->udebug.lock);
275
 
321
 
276
    /*
322
    /*
277
     * On success, this will lock t->udebug.lock. Note that this makes sure
323
     * On success, this will lock t->udebug.lock. Note that this makes sure
278
     * the thread is not stopped.
324
     * the thread is not stopped.
279
     */
325
     */
280
    rc = _thread_op_begin(t, true);
326
    rc = _thread_op_begin(t, true);
281
    if (rc != EOK) {
327
    if (rc != EOK) {
282
        return rc;
328
        return rc;
283
    }
329
    }
284
 
330
 
285
    /* Take GO away from the thread */
331
    /* Take GO away from the thread */
286
    t->udebug.stop = true;
332
    t->udebug.stop = true;
287
 
333
 
288
    if (!t->udebug.stoppable) {
334
    if (!t->udebug.stoppable) {
289
        /* Answer will be sent when the thread becomes stoppable */
335
        /* Answer will be sent when the thread becomes stoppable */
290
        _thread_op_end(t);
336
        _thread_op_end(t);
291
        return 0;
337
        return 0;
292
    }
338
    }
293
 
339
 
294
    /*
340
    /*
295
     * Answer GO call
341
     * Answer GO call
296
     */
342
     */
297
    LOG("udebug_stop - answering go call\n");
343
    LOG("udebug_stop - answering go call\n");
298
 
344
 
299
    /* Make sure nobody takes this call away from us */
345
    /* Make sure nobody takes this call away from us */
300
    call = t->udebug.go_call;
346
    call = t->udebug.go_call;
301
    t->udebug.go_call = NULL;
347
    t->udebug.go_call = NULL;
302
 
348
 
303
    IPC_SET_RETVAL(call->data, 0);
349
    IPC_SET_RETVAL(call->data, 0);
304
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
350
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
305
    LOG("udebug_stop/ipc_answer\n");
351
    LOG("udebug_stop/ipc_answer\n");
306
 
352
 
307
    THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
353
    THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
308
 
354
 
309
    _thread_op_end(t);
355
    _thread_op_end(t);
310
 
356
 
311
    ipc_answer(&TASK->answerbox, call);
357
    ipc_answer(&TASK->answerbox, call);
312
    mutex_unlock(&TASK->udebug.lock);
358
    mutex_unlock(&TASK->udebug.lock);
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;
323
    unsigned copied_ids;
388
    unsigned copied_ids;
324
    ipl_t ipl;
389
    ipl_t ipl;
325
    unative_t *id_buffer;
390
    unative_t *id_buffer;
326
    int flags;
391
    int flags;
327
    size_t max_ids;
392
    size_t max_ids;
328
 
393
 
329
    LOG("udebug_thread_read()\n");
394
    LOG("udebug_thread_read()\n");
330
 
395
 
331
    /* Allocate a buffer to hold thread IDs */
396
    /* Allocate a buffer to hold thread IDs */
332
    id_buffer = malloc(buf_size, 0);
397
    id_buffer = malloc(buf_size, 0);
333
 
398
 
334
    mutex_lock(&TASK->udebug.lock);
399
    mutex_lock(&TASK->udebug.lock);
335
 
400
 
336
    /* Verify task state */
401
    /* Verify task state */
337
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
402
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
338
        mutex_unlock(&TASK->udebug.lock);
403
        mutex_unlock(&TASK->udebug.lock);
339
        return EINVAL;
404
        return EINVAL;
340
    }
405
    }
341
 
406
 
342
    ipl = interrupts_disable();
407
    ipl = interrupts_disable();
343
    spinlock_lock(&TASK->lock);
408
    spinlock_lock(&TASK->lock);
344
    /* Copy down the thread IDs */
409
    /* Copy down the thread IDs */
345
 
410
 
346
    max_ids = buf_size / sizeof(unative_t);
411
    max_ids = buf_size / sizeof(unative_t);
347
    copied_ids = 0;
412
    copied_ids = 0;
348
 
413
 
349
    /* FIXME: make sure the thread isn't past debug shutdown... */
414
    /* FIXME: make sure the thread isn't past debug shutdown... */
350
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
415
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
351
        /* Do not write past end of buffer */
416
        /* Do not write past end of buffer */
352
        if (copied_ids >= max_ids) break;
417
        if (copied_ids >= max_ids) break;
353
 
418
 
354
        t = list_get_instance(cur, thread_t, th_link);
419
        t = list_get_instance(cur, thread_t, th_link);
355
 
420
 
356
        spinlock_lock(&t->lock);
421
        spinlock_lock(&t->lock);
357
        flags = t->flags;
422
        flags = t->flags;
358
        spinlock_unlock(&t->lock);
423
        spinlock_unlock(&t->lock);
359
 
424
 
360
        /* Not interested in kernel threads */
425
        /* Not interested in kernel threads */
361
        if ((flags & THREAD_FLAG_USPACE) != 0) {
426
        if ((flags & THREAD_FLAG_USPACE) != 0) {
362
            /* Using thread struct pointer as identification hash */
427
            /* Using thread struct pointer as identification hash */
363
            tid = (unative_t) t;
428
            tid = (unative_t) t;
364
            id_buffer[copied_ids++] = tid;
429
            id_buffer[copied_ids++] = tid;
365
        }
430
        }
366
    }
431
    }
367
 
432
 
368
    spinlock_unlock(&TASK->lock);
433
    spinlock_unlock(&TASK->lock);
369
    interrupts_restore(ipl);
434
    interrupts_restore(ipl);
370
 
435
 
371
    mutex_unlock(&TASK->udebug.lock);
436
    mutex_unlock(&TASK->udebug.lock);
372
 
437
 
373
    *buffer = id_buffer;
438
    *buffer = id_buffer;
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
 
384
    /* Prepare a buffer to hold the arguments */
461
    /* Prepare a buffer to hold the arguments */
385
    arg_buffer = malloc(6 * sizeof(unative_t), 0);
462
    arg_buffer = malloc(6 * sizeof(unative_t), 0);
386
 
463
 
387
    /* On success, this will lock t->udebug.lock */
464
    /* On success, this will lock t->udebug.lock */
388
    rc = _thread_op_begin(t, false);
465
    rc = _thread_op_begin(t, false);
389
    if (rc != EOK) {
466
    if (rc != EOK) {
390
        return rc;
467
        return rc;
391
    }
468
    }
392
 
469
 
393
    /* Additionally we need to verify that we are inside a syscall */
470
    /* Additionally we need to verify that we are inside a syscall */
394
    if (t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B &&
471
    if (t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B &&
395
        t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E) {
472
        t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E) {
396
        _thread_op_end(t);
473
        _thread_op_end(t);
397
        return EINVAL;
474
        return EINVAL;
398
    }
475
    }
399
 
476
 
400
    /* Copy to a local buffer before releasing the lock */
477
    /* Copy to a local buffer before releasing the lock */
401
    memcpy(arg_buffer, t->udebug.syscall_args, 6 * sizeof(unative_t));
478
    memcpy(arg_buffer, t->udebug.syscall_args, 6 * sizeof(unative_t));
402
 
479
 
403
    _thread_op_end(t);
480
    _thread_op_end(t);
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
 
414
    /* Verify task state */
501
    /* Verify task state */
415
    mutex_lock(&TASK->udebug.lock);
502
    mutex_lock(&TASK->udebug.lock);
416
 
503
 
417
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
504
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
418
        mutex_unlock(&TASK->udebug.lock);
505
        mutex_unlock(&TASK->udebug.lock);
419
        return EBUSY;
506
        return EBUSY;
420
    }
507
    }
421
 
508
 
422
    data_buffer = malloc(n, 0);
509
    data_buffer = malloc(n, 0);
423
 
510
 
424
    /* NOTE: this is not strictly from a syscall... but that shouldn't
511
    /* NOTE: this is not strictly from a syscall... but that shouldn't
425
     * be a problem */
512
     * be a problem */
426
    rc = copy_from_uspace(data_buffer, (void *)uspace_addr, n);
513
    rc = copy_from_uspace(data_buffer, (void *)uspace_addr, n);
427
    mutex_unlock(&TASK->udebug.lock);
514
    mutex_unlock(&TASK->udebug.lock);
428
 
515
 
429
    if (rc != 0) return rc;
516
    if (rc != 0) return rc;
430
 
517
 
431
    *buffer = data_buffer;
518
    *buffer = data_buffer;
432
    return 0;
519
    return 0;
433
}
520
}
434
 
521
 
435
/** @}
522
/** @}
436
 */
523
 */
437
 
524